ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/csvlib.c
Revision: 34
Committed: Sun Oct 2 21:05:51 2005 UTC (18 years, 5 months ago) by lusky
Content type: text/x-csrc
File size: 17737 byte(s)
Log Message:
create 7.2 branch, we can move/rename it as needed.


File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * csvlib.c - set of functions to deal with csv type of conf files
4 *
5 * Copyright (C) 2003 by Diane Bruce, Stuart Walsh
6 * Use it anywhere you like, if you like it buy us a beer.
7 * If it's broken, don't bother us with the lawyers.
8 *
9 * $Id$
10 */
11
12 #include "stdinc.h"
13 #include "tools.h"
14 #include "s_log.h"
15 #include "s_conf.h"
16 #include "hostmask.h"
17 #include "client.h"
18 #include "pcre.h"
19 #include "irc_string.h"
20 #include "sprintf_irc.h"
21 #include "memory.h"
22 #include "send.h"
23 #include "resv.h"
24 #include "s_serv.h"
25
26 /* Fix "statement not reached" warnings on Sun WorkShop C */
27 #ifdef __SUNPRO_C
28 # pragma error_messages(off, E_STATEMENT_NOT_REACHED)
29 #endif
30
31
32 static void parse_csv_line(char *, ...);
33 static int write_csv_line(FBFILE *, const char *, ...);
34 static int flush_write(struct Client *, FBFILE *, FBFILE *,
35 const char *, const char *);
36 static char *getfield(char *);
37
38 /* parse_csv_file()
39 *
40 * inputs - FILE pointer
41 * - type of conf to parse
42 * output - none
43 * side effects -
44 */
45 void
46 parse_csv_file(FBFILE *file, ConfType conf_type)
47 {
48 struct ConfItem *conf;
49 struct AccessItem *aconf;
50 struct MatchItem *match_item;
51 char *name_field=NULL;
52 char *user_field=NULL;
53 char *reason_field=NULL;
54 char *oper_reason=NULL;
55 char *host_field=NULL;
56 char line[IRCD_BUFSIZE];
57 char *p;
58
59 while (fbgets(line, sizeof(line), file) != NULL)
60 {
61 if ((p = strchr(line, '\n')) != NULL)
62 *p = '\0';
63
64 if ((line[0] == '\0') || (line[0] == '#'))
65 continue;
66
67 switch(conf_type)
68 {
69 case KLINE_TYPE:
70 parse_csv_line(line, &user_field, &host_field, &reason_field, NULL);
71 conf = make_conf_item(KLINE_TYPE);
72 aconf = map_to_conf(conf);
73
74 if (host_field != NULL)
75 DupString(aconf->host, host_field);
76 if (reason_field != NULL)
77 DupString(aconf->reason, reason_field);
78 if (user_field != NULL)
79 DupString(aconf->user, user_field);
80 if (aconf->host != NULL)
81 add_conf_by_address(CONF_KILL, aconf);
82 break;
83
84 case RKLINE_TYPE:
85 {
86 const char *errptr = NULL;
87 pcre *exp_user = NULL, *exp_host = NULL;
88
89 parse_csv_line(line, &user_field, &host_field, &reason_field, NULL);
90
91 if (host_field == NULL || user_field == NULL)
92 break;
93
94 if (!(exp_user = ircd_pcre_compile(user_field, &errptr)) ||
95 !(exp_host = ircd_pcre_compile(host_field, &errptr)))
96 {
97 sendto_realops_flags(UMODE_ALL, L_ALL,
98 "Failed to add regular expression based K-Line: %s", errptr);
99 break;
100 }
101
102 aconf = map_to_conf(make_conf_item(RKLINE_TYPE));
103
104 aconf->regexuser = exp_user;
105 aconf->regexhost = exp_host;
106
107 DupString(aconf->user, user_field);
108 DupString(aconf->host, host_field);
109
110 if (reason_field != NULL)
111 DupString(aconf->reason, reason_field);
112 else
113 DupString(aconf->reason, "No reason");
114
115 }
116 break;
117
118 case DLINE_TYPE:
119 parse_csv_line(line, &host_field, &reason_field, NULL);
120 conf = make_conf_item(DLINE_TYPE);
121 aconf = (struct AccessItem *)map_to_conf(conf);
122 if (host_field != NULL)
123 DupString(aconf->host, host_field);
124 if (reason_field != NULL)
125 DupString(aconf->reason, reason_field);
126 conf_add_d_conf(aconf);
127 break;
128
129 case XLINE_TYPE:
130 parse_csv_line(line, &name_field, &reason_field, &oper_reason, NULL);
131 conf = make_conf_item(XLINE_TYPE);
132 match_item = (struct MatchItem *)map_to_conf(conf);
133 if (name_field != NULL)
134 DupString(conf->name, name_field);
135 if (reason_field != NULL)
136 DupString(match_item->reason, reason_field);
137 break;
138
139 case RXLINE_TYPE:
140 {
141 const char *errptr = NULL;
142 pcre *exp_p = NULL;
143
144 parse_csv_line(line, &name_field, &reason_field, &oper_reason, NULL);
145
146 if (name_field == NULL)
147 break;
148
149 if (!(exp_p = ircd_pcre_compile(name_field, &errptr)))
150 {
151 sendto_realops_flags(UMODE_ALL, L_ALL,
152 "Failed to add regular expression based X-Line: %s", errptr);
153 break;
154 }
155
156 conf = make_conf_item(RXLINE_TYPE);
157 conf->regexpname = exp_p;
158 match_item = map_to_conf(conf);
159 DupString(conf->name, name_field);
160
161 if (reason_field != NULL)
162 DupString(match_item->reason, reason_field);
163 else
164 DupString(match_item->reason, "No reason");
165 }
166 break;
167
168 case CRESV_TYPE:
169 parse_csv_line(line, &name_field, &reason_field, NULL);
170 (void)create_channel_resv(name_field, reason_field, 0);
171 break;
172
173 case NRESV_TYPE:
174 parse_csv_line(line, &name_field, &reason_field, NULL);
175 (void)create_nick_resv(name_field, reason_field, 0);
176 break;
177
178 case GLINE_TYPE:
179 case GDENY_TYPE:
180 case CONF_TYPE:
181 case OPER_TYPE:
182 case CLIENT_TYPE:
183 case SERVER_TYPE:
184 case CLUSTER_TYPE:
185 case HUB_TYPE:
186 case LEAF_TYPE:
187 case ULINE_TYPE:
188 case EXEMPTDLINE_TYPE:
189 case CLASS_TYPE:
190 break;
191 }
192 }
193 }
194
195 /*
196 * parse_csv_line()
197 *
198 * inputs - pointer to line to parse
199 * output -
200 * side effects -
201 */
202
203 static void
204 parse_csv_line(char *line, ...)
205 {
206 va_list args;
207 char **dest;
208 char *field = NULL;
209
210 va_start(args, line);
211
212 for (; ;)
213 {
214 dest = va_arg(args, char **);
215 if ((dest == NULL) || ((field = getfield(field ? NULL : line)) == NULL))
216 {
217 va_end(args);
218 return;
219 }
220 *dest = field;
221 }
222 }
223
224 /* write_conf_line()
225 *
226 * inputs - pointer to struct AccessItem
227 * - string current_date (small date)
228 * - time_t cur_time
229 * output - NONE
230 * side effects - This function takes care of
231 * finding right conf file, writing
232 * the right lines to this file,
233 * notifying the oper that their kline/dline etc. is in place
234 * notifying the opers on the server about the k/d etc. line
235 *
236 * - Dianora
237 */
238 void
239 write_conf_line(struct Client *source_p, struct ConfItem *conf,
240 const char *current_date, time_t cur_time)
241 {
242 FBFILE *out;
243 const char *filename, *from, *to;
244 struct AccessItem *aconf;
245 struct MatchItem *xconf;
246 struct ResvChannel *cresv_p=NULL;
247 struct MatchItem *nresv_p=NULL;
248 ConfType type;
249
250 type = conf->type;
251 filename = get_conf_name(type);
252
253 if (!MyConnect(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
254 {
255 from = me.id;
256 to = source_p->id;
257 }
258 else
259 {
260 from = me.name;
261 to = source_p->name;
262 }
263
264 if ((out = fbopen(filename, "a")) == NULL)
265 {
266 sendto_realops_flags(UMODE_ALL, L_ALL,
267 "*** Problem opening %s ", filename);
268 return;
269 }
270
271 switch(type)
272 {
273 case KLINE_TYPE:
274 aconf = (struct AccessItem *)map_to_conf(conf);
275 sendto_realops_flags(UMODE_ALL, L_ALL,
276 "%s added K-Line for [%s@%s] [%s]",
277 get_oper_name(source_p),
278 aconf->user, aconf->host, aconf->reason);
279 sendto_one(source_p, ":%s NOTICE %s :Added K-Line [%s@%s]",
280 from, to, aconf->user, aconf->host);
281 ilog(L_TRACE, "%s added K-Line for [%s@%s] [%s]",
282 source_p->name, aconf->user, aconf->host, aconf->reason);
283 log_oper_action(LOG_KLINE_TYPE, source_p, "[%s@%s] [%s]\n",
284 aconf->user, aconf->host, aconf->reason);
285 write_csv_line(out, "%s%s%s%s%s%s%d",
286 aconf->user, aconf->host,
287 aconf->reason, aconf->oper_reason, current_date,
288 get_oper_name(source_p), cur_time);
289 break;
290
291 case RKLINE_TYPE:
292 aconf = map_to_conf(conf);
293 sendto_realops_flags(UMODE_ALL, L_ALL,
294 "%s added RK-Line for [%s@%s] [%s]",
295 get_oper_name(source_p),
296 aconf->user, aconf->host, aconf->reason);
297 sendto_one(source_p, ":%s NOTICE %s :Added RK-Line [%s@%s]",
298 from, to, aconf->user, aconf->host);
299 ilog(L_TRACE, "%s added K-Line for [%s@%s] [%s]",
300 source_p->name, aconf->user, aconf->host, aconf->reason);
301 log_oper_action(LOG_RKLINE_TYPE, source_p, "[%s@%s] [%s]\n",
302 aconf->user, aconf->host, aconf->reason);
303 write_csv_line(out, "%s%s%s%s%s%s%d",
304 aconf->user, aconf->host,
305 aconf->reason, aconf->oper_reason, current_date,
306 get_oper_name(source_p), cur_time);
307 break;
308
309 case DLINE_TYPE:
310 aconf = (struct AccessItem *)map_to_conf(conf);
311 sendto_realops_flags(UMODE_ALL, L_ALL,
312 "%s added D-Line for [%s] [%s]",
313 get_oper_name(source_p), aconf->host, aconf->reason);
314 sendto_one(source_p, ":%s NOTICE %s :Added D-Line [%s] to %s",
315 from, to, aconf->host, filename);
316 ilog(L_TRACE, "%s added D-Line for [%s] [%s]",
317 get_oper_name(source_p), aconf->host, aconf->reason);
318 log_oper_action(LOG_DLINE_TYPE, source_p, "[%s] [%s]\n",
319 aconf->host, aconf->reason);
320 write_csv_line(out, "%s%s%s%s%s%d",
321 aconf->host, aconf->reason, aconf->oper_reason,
322 current_date,
323 get_oper_name(source_p), cur_time);
324 break;
325
326 case XLINE_TYPE:
327 xconf = (struct MatchItem *)map_to_conf(conf);
328 sendto_realops_flags(UMODE_ALL, L_ALL,
329 "%s added X-Line for [%s] [%s]",
330 get_oper_name(source_p), conf->name,
331 xconf->reason);
332 sendto_one(source_p,
333 ":%s NOTICE %s :Added X-Line [%s] [%d] [%s] to %s",
334 from, to, conf->name,
335 xconf->action, xconf->reason, filename);
336 ilog(L_TRACE, "%s added X-Line for [%s] [%s]",
337 get_oper_name(source_p), conf->name, xconf->reason);
338 write_csv_line(out, "%s%s%s%s%s%d",
339 conf->name, xconf->reason, xconf->oper_reason,
340 current_date, get_oper_name(source_p), cur_time);
341 break;
342
343 case RXLINE_TYPE:
344 xconf = (struct MatchItem *)map_to_conf(conf);
345 sendto_realops_flags(UMODE_ALL, L_ALL,
346 "%s added RX-Line for [%s] [%s]",
347 get_oper_name(source_p), conf->name,
348 xconf->reason);
349 sendto_one(source_p,
350 ":%s NOTICE %s :Added RX-Line [%s] [%s] to %s",
351 from, to, conf->name,
352 xconf->reason, filename);
353 ilog(L_TRACE, "%s added X-Line for [%s] [%s]",
354 get_oper_name(source_p), conf->name, xconf->reason);
355 write_csv_line(out, "%s%s%s%s%s%d",
356 conf->name, xconf->reason, xconf->oper_reason,
357 current_date, get_oper_name(source_p), cur_time);
358 break;
359
360 case CRESV_TYPE:
361 cresv_p = (struct ResvChannel *)map_to_conf(conf);
362
363 write_csv_line(out, "%s%s",
364 cresv_p->name, cresv_p->reason);
365 break;
366
367 case NRESV_TYPE:
368 nresv_p = (struct MatchItem *)map_to_conf(conf);
369
370 write_csv_line(out, "%s%s",
371 conf->name, nresv_p->reason);
372 break;
373
374 default:
375 fbclose(out);
376 return;
377 }
378
379 fbclose(out);
380 }
381
382 /*
383 * write_csv_line()
384 *
385 * inputs - pointer to FBFILE *
386 * - formatted string
387 * output -
388 * side effects - single line is written to csv conf file
389 */
390 static int
391 write_csv_line(FBFILE *out, const char *format, ...)
392 {
393 char c;
394 size_t bytes = 0;
395 va_list args;
396 char tmp[1024];
397 char *str = tmp;
398 const char *null_string = "";
399
400 if (out == NULL)
401 return(0);
402
403 va_start(args, format);
404
405 while ((c = *format++))
406 {
407 if (c == '%')
408 {
409 c = *format++;
410 if (c == 's')
411 {
412 const char *p1 = va_arg(args, const char *);
413 if (p1 == NULL)
414 p1 = null_string;
415 *str++ = '\"';
416 ++bytes;
417 while (*p1 != '\0')
418 {
419 *str++ = *p1++;
420 ++bytes;
421 }
422 *str++ = '\"';
423 *str++ = ',';
424
425 bytes += 2;
426 continue;
427 }
428 if (c == 'c')
429 {
430 *str++ = '\"';
431 ++bytes;
432 *str++ = (char) va_arg(args, int);
433 ++bytes;
434 *str++ = '\"';
435 *str++ = ',';
436
437 bytes += 2;
438 continue;
439 }
440
441 if (c == 'd')
442 {
443 int v = va_arg(args, int);
444 char t[40];
445 char *p=t;
446
447 while (v > 10)
448 {
449 *p++ = (v % 10) + '0';
450 v = v/10;
451 }
452 *p++ = (v % 10) + '0';
453
454 *str++ = '\"';
455 ++bytes;
456 while (p != t)
457 {
458 *str++ = *--p;
459 ++bytes;
460 }
461
462 *str++ = '\"';
463 *str++ = ',';
464 bytes += 2;
465 continue;
466 }
467 if (c != '%')
468 {
469 int ret;
470
471 format -= 2;
472 ret = vsprintf(str, format, args);
473 str += ret;
474 bytes += ret;
475 *str++ = ',';
476
477 ++bytes;
478 break;
479 }
480 }
481 *str++ = c;
482 ++bytes;
483 }
484
485 if (*(str-1) == ',')
486 {
487 *(str-1) = '\n';
488 *str = '\0';
489 }
490 else
491 {
492 *str++ = '\n';
493 ++bytes;
494 *str = '\0';
495 }
496
497 va_end(args);
498 str = tmp;
499 fbputs(str, out, bytes);
500
501 return(bytes);
502 }
503
504 /*
505 * getfield
506 *
507 * inputs - input buffer
508 * output - next field
509 * side effects - field breakup for ircd.conf file.
510 */
511 static char *
512 getfield(char *newline)
513 {
514 static char *line = NULL;
515 char *end, *field;
516
517 if (newline != NULL)
518 line = newline;
519
520 if (line == NULL)
521 return(NULL);
522
523 field = line;
524
525 while (*field != '"') /* skip everything that's not a starting quote */
526 ++field;
527
528 /* skip over the beginning " */
529 end = ++field;
530
531 for (;;)
532 {
533 /* At end of string, mark it as end and return */
534 if ((*end == '\0') || (*end == '\n'))
535 {
536 line = NULL;
537 return(NULL);
538 }
539 else if (*end == '\\') /* found escape character ? */
540 {
541 end++;
542 }
543 else if (*end == '"') /* found terminating " */
544 {
545 *end++ = '\0';
546 line = end;
547 return(field);
548 }
549
550 end++;
551 }
552
553 return (NULL);
554 }
555
556 /* remove_conf_line()
557 *
558 * inputs - type of kline to remove
559 * - pointer to oper removing
560 * - pat1 pat2 patterns to match
561 * output - -1 if unsuccessful 0 if no change 1 if change
562 * side effects -
563 */
564 int
565 remove_conf_line(ConfType type, struct Client *source_p, const char *pat1, const char *pat2)
566 {
567 const char *filename;
568 FBFILE *in, *out;
569 int pairme=0;
570 char buf[IRCD_BUFSIZE], buff[IRCD_BUFSIZE], temppath[IRCD_BUFSIZE];
571 char *found1;
572 char *found2;
573 int oldumask;
574 int (*cmpfunc)(const char *, const char *) = irccmp;
575
576 if (type == RXLINE_TYPE || type == RKLINE_TYPE)
577 cmpfunc = strcmp;
578
579 filename = get_conf_name(type);
580
581 if ((in = fbopen(filename, "r")) == NULL)
582 {
583 sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name,
584 source_p->name, filename);
585 return -1;
586 }
587
588 ircsprintf(temppath, "%s.tmp", filename);
589 oldumask = umask(0);
590
591 if ((out = fbopen(temppath, "w")) == NULL)
592 {
593 sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name,
594 source_p->name, temppath);
595 fbclose(in);
596 umask(oldumask);
597 return -1;
598 }
599
600 umask(oldumask);
601 oldumask = umask(0);
602
603 while (fbgets(buf, sizeof(buf), in) != NULL)
604 {
605 if ((*buf == '\0') || (*buf == '#'))
606 {
607 if (flush_write(source_p, in, out, buf, temppath) < 0)
608 return -1;
609 }
610
611 /* Keep copy of original line, getfield trashes line as it goes */
612 strlcpy(buff, buf, sizeof(buff));
613
614 if ((found1 = getfield(buff)) == NULL)
615 {
616 if (flush_write(source_p, in, out, buf, temppath) < 0)
617 return -1;
618 continue;
619 }
620
621 if (pat2 != NULL)
622 {
623 if ((found2 = getfield(NULL)) == NULL)
624 {
625 if (flush_write(source_p, in, out, buf, temppath) < 0)
626 return -1;
627 continue;
628 }
629
630 if (!cmpfunc(pat1, found1) && !cmpfunc(pat2, found2))
631 {
632 pairme = 1;
633 continue;
634 }
635 else
636 {
637 if(flush_write(source_p, in, out, buf, temppath) < 0)
638 return -1;
639 continue;
640 }
641 }
642 else
643 {
644 if (!cmpfunc(pat1, found1))
645 {
646 pairme = 1;
647 continue;
648 }
649 else
650 {
651 if(flush_write(source_p, in, out, buf, temppath) < 0)
652 return -1;
653 continue;
654 }
655 }
656 }
657
658 fbclose(in);
659 fbclose(out);
660
661 /* The result of the rename should be checked too... oh well */
662 /* If there was an error on a write above, then its been reported
663 * and I am not going to trash the original kline /conf file
664 */
665
666 if (pairme == 0)
667 {
668 if(temppath != NULL)
669 (void)unlink(temppath);
670 return 0;
671 }
672 else
673 {
674 (void)rename(temppath, filename);
675
676 /* XXX
677 * This is a very inefficient way of removing a kline/xline etc.
678 * This next function call forces a complete re-read of all conf
679 * files, instead of a re-read of the kline/dline etc. files modified
680 * But, consider how often an /quote unkline etc. is done compared
681 * to how often a /quote kline is done. Its not a biggie in
682 * the grand scheme of things. If it does become a biggie,
683 * we will rewrite it - Dianora
684 */
685
686 rehash(0);
687 return 1;
688 }
689 }
690
691 /*
692 * flush_write()
693 *
694 * inputs - pointer to client structure of oper requesting unkline
695 * - in is the input file descriptor
696 * - out is the output file descriptor
697 * - buf is the buffer to write
698 * - ntowrite is the expected number of character to be written
699 * - temppath is the temporary file name to be written
700 * output - -1 for error on write
701 * - 0 for ok
702 * side effects - if successful, the buf is written to output file
703 * if a write failure happesn, and the file pointed to
704 * by temppath, if its non NULL, is removed.
705 *
706 * The idea here is, to be as robust as possible when writing to the
707 * kline file.
708 *
709 * -Dianora
710 */
711 static int
712 flush_write(struct Client *source_p, FBFILE *in, FBFILE* out,
713 const char *buf, const char *temppath)
714 {
715 int error_on_write = (fbputs(buf, out, strlen(buf)) < 0) ? (-1) : (0);
716
717 if (error_on_write)
718 {
719 sendto_one(source_p,":%s NOTICE %s :Unable to write to %s aborting",
720 me.name, source_p->name, temppath);
721 if(temppath != NULL)
722 (void)unlink(temppath);
723 fbclose(in);
724 fbclose(out);
725 }
726
727 return (error_on_write);
728 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision