ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/csvlib.c
Revision: 1247
Committed: Sat Oct 1 07:54:24 2011 UTC (15 years ago) by michael
Content type: text/x-csrc
File size: 17812 byte(s)
Log Message:
- Rewrite and cleanup half-broken logging subsystem.
  Logfile rotating is not working yet

File Contents

# User Rev Content
1 adx 30 /*
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 knight 31 * $Id$
10 adx 30 */
11    
12 michael 1009 #include "config.h"
13     #ifdef HAVE_LIBPCRE
14     #include <pcre.h>
15     #endif
16 adx 30 #include "stdinc.h"
17 michael 1011 #include "list.h"
18 adx 30 #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 michael 1009 #ifdef HAVE_LIBPCRE
87 adx 30 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 michael 1009 #endif
121 adx 30 case DLINE_TYPE:
122     parse_csv_line(line, &host_field, &reason_field, NULL);
123 michael 1005
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 adx 30 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 michael 1009 #ifdef HAVE_LIBPCRE
148 adx 30 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 michael 1009 #endif
177 adx 30 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 michael 1009 default:
200 adx 30 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 michael 1247 ilog(LOG_TYPE_KLINE, "%s added K-Line for [%s@%s] [%s]",
292 adx 30 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 michael 1009 #ifdef HAVE_LIBPCRE
299 adx 30 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 michael 1247 ilog(LOG_TYPE_IRCD, "%s added K-Line for [%s@%s] [%s]",
308 adx 30 source_p->name, aconf->user, aconf->host, aconf->reason);
309 michael 1247
310 adx 30 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 michael 1009 #endif
316 adx 30 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 michael 1247 ilog(LOG_TYPE_DLINE, "%s added D-Line for [%s] [%s]",
324 adx 30 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 michael 1247 ilog(LOG_TYPE_IRCD, "%s added X-Line for [%s] [%s]",
342 adx 30 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 michael 1009 #ifdef HAVE_LIBPCRE
348 adx 30 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 michael 1247 ilog(LOG_TYPE_IRCD, "%s added X-Line for [%s] [%s]",
359 adx 30 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 michael 1009 #endif
365 adx 30 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 db 521 /* 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 adx 30 ++field;
538 db 521 }
539 adx 30
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