ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid-8/src/csvlib.c
Revision: 1518
Committed: Sun Sep 2 16:50:40 2012 UTC (11 years, 6 months ago) by michael
Content type: text/x-csrc
File size: 15008 byte(s)
Log Message:
- Removed rkline.conf and rxline.conf leftovers. Regular expression based
  k- and x-lines can be set via ircd.conf only.

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

Properties

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