ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-7.2/src/csvlib.c
Revision: 1011
Committed: Fri Sep 18 10:14:09 2009 UTC (14 years, 7 months ago) by michael
Content type: text/x-csrc
File size: 18100 byte(s)
Log Message:
- move list manipulation routines from tools.c to list.c
- mem_frob() goes to memory.c
- sort out redundant/unneeded header includes

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

Properties

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