ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/csvlib.c
Revision: 1028
Committed: Sun Nov 8 13:03:38 2009 UTC (16 years, 11 months ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid/src/csvlib.c
File size: 18100 byte(s)
Log Message:
- move ircd-hybrid-7.2 to trunk

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     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 michael 1009 #ifdef HAVE_LIBPCRE
301 adx 30 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 michael 1009 #endif
319 adx 30 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 michael 1009 #ifdef HAVE_LIBPCRE
353 adx 30 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 michael 1009 #endif
370 adx 30 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 db 521 /* 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 adx 30 ++field;
543 db 521 }
544 adx 30
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