ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/csvlib.c
Revision: 1309
Committed: Sun Mar 25 11:24:18 2012 UTC (13 years, 5 months ago) by michael
Content type: text/x-csrc
File size: 17808 byte(s)
Log Message:
- renaming files:

  ircd_parser.y -> conf_parser.y
  ircd_lexer.l  -> conf_lexer.l
  s_conf.c      -> conf.c
  s_conf.h      -> conf.h
  s_log.c       -> log.c
  s_log.h       -> log.h

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 "log.h"
19 #include "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(LOG_TYPE_KLINE, "%s added K-Line for [%s@%s] [%s]",
292 source_p->name, aconf->user, aconf->host, aconf->reason);
293 write_csv_line(out, "%s%s%s%s%s%s%d",
294 aconf->user, aconf->host,
295 aconf->reason, aconf->oper_reason, current_date,
296 get_oper_name(source_p), cur_time);
297 break;
298 #ifdef HAVE_LIBPCRE
299 case RKLINE_TYPE:
300 aconf = map_to_conf(conf);
301 sendto_realops_flags(UMODE_ALL, L_ALL,
302 "%s added RK-Line for [%s@%s] [%s]",
303 get_oper_name(source_p),
304 aconf->user, aconf->host, aconf->reason);
305 sendto_one(source_p, ":%s NOTICE %s :Added RK-Line [%s@%s]",
306 from, to, aconf->user, aconf->host);
307 ilog(LOG_TYPE_IRCD, "%s added K-Line for [%s@%s] [%s]",
308 source_p->name, aconf->user, aconf->host, aconf->reason);
309
310 write_csv_line(out, "%s%s%s%s%s%s%d",
311 aconf->user, aconf->host,
312 aconf->reason, aconf->oper_reason, current_date,
313 get_oper_name(source_p), cur_time);
314 break;
315 #endif
316 case DLINE_TYPE:
317 aconf = (struct AccessItem *)map_to_conf(conf);
318 sendto_realops_flags(UMODE_ALL, L_ALL,
319 "%s added D-Line for [%s] [%s]",
320 get_oper_name(source_p), aconf->host, aconf->reason);
321 sendto_one(source_p, ":%s NOTICE %s :Added D-Line [%s] to %s",
322 from, to, aconf->host, filename);
323 ilog(LOG_TYPE_DLINE, "%s added D-Line for [%s] [%s]",
324 get_oper_name(source_p), aconf->host, aconf->reason);
325 write_csv_line(out, "%s%s%s%s%s%d",
326 aconf->host, aconf->reason, aconf->oper_reason,
327 current_date,
328 get_oper_name(source_p), cur_time);
329 break;
330
331 case XLINE_TYPE:
332 xconf = (struct MatchItem *)map_to_conf(conf);
333 sendto_realops_flags(UMODE_ALL, L_ALL,
334 "%s added X-Line for [%s] [%s]",
335 get_oper_name(source_p), conf->name,
336 xconf->reason);
337 sendto_one(source_p,
338 ":%s NOTICE %s :Added X-Line [%s] [%d] [%s] to %s",
339 from, to, conf->name,
340 xconf->action, xconf->reason, filename);
341 ilog(LOG_TYPE_IRCD, "%s added X-Line for [%s] [%s]",
342 get_oper_name(source_p), conf->name, xconf->reason);
343 write_csv_line(out, "%s%s%s%s%s%d",
344 conf->name, xconf->reason, xconf->oper_reason,
345 current_date, get_oper_name(source_p), cur_time);
346 break;
347 #ifdef HAVE_LIBPCRE
348 case RXLINE_TYPE:
349 xconf = (struct MatchItem *)map_to_conf(conf);
350 sendto_realops_flags(UMODE_ALL, L_ALL,
351 "%s added RX-Line for [%s] [%s]",
352 get_oper_name(source_p), conf->name,
353 xconf->reason);
354 sendto_one(source_p,
355 ":%s NOTICE %s :Added RX-Line [%s] [%s] to %s",
356 from, to, conf->name,
357 xconf->reason, filename);
358 ilog(LOG_TYPE_IRCD, "%s added X-Line for [%s] [%s]",
359 get_oper_name(source_p), conf->name, xconf->reason);
360 write_csv_line(out, "%s%s%s%s%s%d",
361 conf->name, xconf->reason, xconf->oper_reason,
362 current_date, get_oper_name(source_p), cur_time);
363 break;
364 #endif
365 case CRESV_TYPE:
366 cresv_p = (struct ResvChannel *)map_to_conf(conf);
367
368 write_csv_line(out, "%s%s",
369 cresv_p->name, cresv_p->reason);
370 break;
371
372 case NRESV_TYPE:
373 nresv_p = (struct MatchItem *)map_to_conf(conf);
374
375 write_csv_line(out, "%s%s",
376 conf->name, nresv_p->reason);
377 break;
378
379 default:
380 fbclose(out);
381 return;
382 }
383
384 fbclose(out);
385 }
386
387 /*
388 * write_csv_line()
389 *
390 * inputs - pointer to FBFILE *
391 * - formatted string
392 * output -
393 * side effects - single line is written to csv conf file
394 */
395 static int
396 write_csv_line(FBFILE *out, const char *format, ...)
397 {
398 char c;
399 size_t bytes = 0;
400 va_list args;
401 char tmp[1024];
402 char *str = tmp;
403 const char *null_string = "";
404
405 if (out == NULL)
406 return(0);
407
408 va_start(args, format);
409
410 while ((c = *format++))
411 {
412 if (c == '%')
413 {
414 c = *format++;
415 if (c == 's')
416 {
417 const char *p1 = va_arg(args, const char *);
418 if (p1 == NULL)
419 p1 = null_string;
420 *str++ = '\"';
421 ++bytes;
422 while (*p1 != '\0')
423 {
424 *str++ = *p1++;
425 ++bytes;
426 }
427 *str++ = '\"';
428 *str++ = ',';
429
430 bytes += 2;
431 continue;
432 }
433 if (c == 'c')
434 {
435 *str++ = '\"';
436 ++bytes;
437 *str++ = (char) va_arg(args, int);
438 ++bytes;
439 *str++ = '\"';
440 *str++ = ',';
441
442 bytes += 2;
443 continue;
444 }
445
446 if (c == 'd')
447 {
448 int v = va_arg(args, int);
449 char t[40];
450 char *p=t;
451
452 while (v > 10)
453 {
454 *p++ = (v % 10) + '0';
455 v = v/10;
456 }
457 *p++ = (v % 10) + '0';
458
459 *str++ = '\"';
460 ++bytes;
461 while (p != t)
462 {
463 *str++ = *--p;
464 ++bytes;
465 }
466
467 *str++ = '\"';
468 *str++ = ',';
469 bytes += 2;
470 continue;
471 }
472 if (c != '%')
473 {
474 int ret;
475
476 format -= 2;
477 ret = vsprintf(str, format, args);
478 str += ret;
479 bytes += ret;
480 *str++ = ',';
481
482 ++bytes;
483 break;
484 }
485 }
486 *str++ = c;
487 ++bytes;
488 }
489
490 if (*(str-1) == ',')
491 {
492 *(str-1) = '\n';
493 *str = '\0';
494 }
495 else
496 {
497 *str++ = '\n';
498 ++bytes;
499 *str = '\0';
500 }
501
502 va_end(args);
503 str = tmp;
504 fbputs(str, out, bytes);
505
506 return(bytes);
507 }
508
509 /*
510 * getfield
511 *
512 * inputs - input buffer
513 * output - next field
514 * side effects - field breakup for ircd.conf file.
515 */
516 static char *
517 getfield(char *newline)
518 {
519 static char *line = NULL;
520 char *end, *field;
521
522 if (newline != NULL)
523 line = newline;
524
525 if (line == NULL)
526 return(NULL);
527
528 field = line;
529
530 /* skip everything that's not a starting quote */
531 for(;;)
532 {
533 if (*field == '\0')
534 return(NULL);
535 else if (*field == '"')
536 break;
537 ++field;
538 }
539
540 /* skip over the beginning " */
541 end = ++field;
542
543 for (;;)
544 {
545 /* At end of string, mark it as end and return */
546 if ((*end == '\0') || (*end == '\n'))
547 {
548 line = NULL;
549 return(NULL);
550 }
551 else if (*end == '\\') /* found escape character ? */
552 {
553 end++;
554 }
555 else if (*end == '"') /* found terminating " */
556 {
557 *end++ = '\0';
558 line = end;
559 return(field);
560 }
561
562 end++;
563 }
564
565 return (NULL);
566 }
567
568 /* remove_conf_line()
569 *
570 * inputs - type of kline to remove
571 * - pointer to oper removing
572 * - pat1 pat2 patterns to match
573 * output - -1 if unsuccessful 0 if no change 1 if change
574 * side effects -
575 */
576 int
577 remove_conf_line(ConfType type, struct Client *source_p, const char *pat1, const char *pat2)
578 {
579 const char *filename;
580 FBFILE *in, *out;
581 int pairme=0;
582 char buf[IRCD_BUFSIZE], buff[IRCD_BUFSIZE], temppath[IRCD_BUFSIZE];
583 char *found1;
584 char *found2;
585 int oldumask;
586 int (*cmpfunc)(const char *, const char *) = irccmp;
587
588 if (type == RXLINE_TYPE || type == RKLINE_TYPE)
589 cmpfunc = strcmp;
590
591 filename = get_conf_name(type);
592
593 if ((in = fbopen(filename, "r")) == NULL)
594 {
595 sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name,
596 source_p->name, filename);
597 return -1;
598 }
599
600 ircsprintf(temppath, "%s.tmp", filename);
601 oldumask = umask(0);
602
603 if ((out = fbopen(temppath, "w")) == NULL)
604 {
605 sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name,
606 source_p->name, temppath);
607 fbclose(in);
608 umask(oldumask);
609 return -1;
610 }
611
612 umask(oldumask);
613 oldumask = umask(0);
614
615 while (fbgets(buf, sizeof(buf), in) != NULL)
616 {
617 if ((*buf == '\0') || (*buf == '#'))
618 {
619 if (flush_write(source_p, in, out, buf, temppath) < 0)
620 return -1;
621 }
622
623 /* Keep copy of original line, getfield trashes line as it goes */
624 strlcpy(buff, buf, sizeof(buff));
625
626 if ((found1 = getfield(buff)) == NULL)
627 {
628 if (flush_write(source_p, in, out, buf, temppath) < 0)
629 return -1;
630 continue;
631 }
632
633 if (pat2 != NULL)
634 {
635 if ((found2 = getfield(NULL)) == NULL)
636 {
637 if (flush_write(source_p, in, out, buf, temppath) < 0)
638 return -1;
639 continue;
640 }
641
642 if (!cmpfunc(pat1, found1) && !cmpfunc(pat2, found2))
643 {
644 pairme = 1;
645 continue;
646 }
647 else
648 {
649 if(flush_write(source_p, in, out, buf, temppath) < 0)
650 return -1;
651 continue;
652 }
653 }
654 else
655 {
656 if (!cmpfunc(pat1, found1))
657 {
658 pairme = 1;
659 continue;
660 }
661 else
662 {
663 if(flush_write(source_p, in, out, buf, temppath) < 0)
664 return -1;
665 continue;
666 }
667 }
668 }
669
670 fbclose(in);
671 fbclose(out);
672
673 /* The result of the rename should be checked too... oh well */
674 /* If there was an error on a write above, then its been reported
675 * and I am not going to trash the original kline /conf file
676 */
677
678 if (pairme == 0)
679 {
680 if(temppath != NULL)
681 (void)unlink(temppath);
682 return 0;
683 }
684 else
685 {
686 (void)rename(temppath, filename);
687
688 /* XXX
689 * This is a very inefficient way of removing a kline/xline etc.
690 * This next function call forces a complete re-read of all conf
691 * files, instead of a re-read of the kline/dline etc. files modified
692 * But, consider how often an /quote unkline etc. is done compared
693 * to how often a /quote kline is done. Its not a biggie in
694 * the grand scheme of things. If it does become a biggie,
695 * we will rewrite it - Dianora
696 */
697
698 rehash(0);
699 return 1;
700 }
701 }
702
703 /*
704 * flush_write()
705 *
706 * inputs - pointer to client structure of oper requesting unkline
707 * - in is the input file descriptor
708 * - out is the output file descriptor
709 * - buf is the buffer to write
710 * - ntowrite is the expected number of character to be written
711 * - temppath is the temporary file name to be written
712 * output - -1 for error on write
713 * - 0 for ok
714 * side effects - if successful, the buf is written to output file
715 * if a write failure happesn, and the file pointed to
716 * by temppath, if its non NULL, is removed.
717 *
718 * The idea here is, to be as robust as possible when writing to the
719 * kline file.
720 *
721 * -Dianora
722 */
723 static int
724 flush_write(struct Client *source_p, FBFILE *in, FBFILE* out,
725 const char *buf, const char *temppath)
726 {
727 int error_on_write = (fbputs(buf, out, strlen(buf)) < 0) ? (-1) : (0);
728
729 if (error_on_write)
730 {
731 sendto_one(source_p,":%s NOTICE %s :Unable to write to %s aborting",
732 me.name, source_p->name, temppath);
733 if(temppath != NULL)
734 (void)unlink(temppath);
735 fbclose(in);
736 fbclose(out);
737 }
738
739 return (error_on_write);
740 }

Properties

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