ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/csvlib.c
Revision: 1371
Committed: Wed Apr 25 19:32:21 2012 UTC (11 years, 11 months ago) by michael
Content type: text/x-csrc
File size: 18475 byte(s)
Log Message:
- "UNKLINE bla@bla.net" may accidentaly remove existing klines such as *@bla.* - Fixed

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

Properties

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