ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/csvlib.c
Revision: 139
Committed: Sun Oct 16 06:01:13 2005 UTC (20 years, 9 months ago) by db
Content type: text/x-csrc
File size: 17522 byte(s)
Log Message:
- get rid of map_conf_item and unmap_conf_item
- Use an union in struct ConfItem, but only allocate memory needed


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

Properties

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