ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/csvlib.c
Revision: 1459
Committed: Fri Jul 6 14:23:09 2012 UTC (13 years, 1 month ago) by michael
Content type: text/x-csrc
File size: 18454 byte(s)
Log Message:
- remove g-line acls
- added general::gline_request_duration configuration option which
  simply replaces the harcoded PENDING_GLINE_TIME definition

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

Properties

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