ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/csvlib.c
Revision: 1005
Committed: Mon Aug 31 23:07:43 2009 UTC (16 years ago) by michael
Content type: text/x-csrc
Original Path: ircd-hybrid-7.2/src/csvlib.c
File size: 17941 byte(s)
Log Message:
- remove conf_add_d_conf wrapper

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

Properties

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