00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "stdinc.h"
00013 #include "tools.h"
00014 #include "s_log.h"
00015 #include "s_conf.h"
00016 #include "hostmask.h"
00017 #include "client.h"
00018 #include "pcre.h"
00019 #include "irc_string.h"
00020 #include "sprintf_irc.h"
00021 #include "memory.h"
00022 #include "send.h"
00023 #include "resv.h"
00024 #include "s_serv.h"
00025
00026
00027 #ifdef __SUNPRO_C
00028 # pragma error_messages(off, E_STATEMENT_NOT_REACHED)
00029 #endif
00030
00031
00032 static void parse_csv_line(char *, ...);
00033 static int write_csv_line(FBFILE *, const char *, ...);
00034 static int flush_write(struct Client *, FBFILE *, FBFILE *,
00035 const char *, const char *);
00036 static char *getfield(char *);
00037
00038
00039
00040
00041
00042
00043
00044
00045 void
00046 parse_csv_file(FBFILE *file, ConfType conf_type)
00047 {
00048 struct ConfItem *conf;
00049 struct AccessItem *aconf;
00050 struct MatchItem *match_item;
00051 char *name_field=NULL;
00052 char *user_field=NULL;
00053 char *reason_field=NULL;
00054 char *oper_reason=NULL;
00055 char *host_field=NULL;
00056 char line[IRCD_BUFSIZE];
00057 char *p;
00058
00059 while (fbgets(line, sizeof(line), file) != NULL)
00060 {
00061 if ((p = strchr(line, '\n')) != NULL)
00062 *p = '\0';
00063
00064 if ((line[0] == '\0') || (line[0] == '#'))
00065 continue;
00066
00067 switch(conf_type)
00068 {
00069 case KLINE_TYPE:
00070 parse_csv_line(line, &user_field, &host_field, &reason_field, NULL);
00071 conf = make_conf_item(KLINE_TYPE);
00072 aconf = map_to_conf(conf);
00073
00074 if (host_field != NULL)
00075 DupString(aconf->host, host_field);
00076 if (reason_field != NULL)
00077 DupString(aconf->reason, reason_field);
00078 if (user_field != NULL)
00079 DupString(aconf->user, user_field);
00080 if (aconf->host != NULL)
00081 add_conf_by_address(CONF_KILL, aconf);
00082 break;
00083
00084 case RKLINE_TYPE:
00085 {
00086 const char *errptr = NULL;
00087 pcre *exp_user = NULL, *exp_host = NULL;
00088
00089 parse_csv_line(line, &user_field, &host_field, &reason_field, NULL);
00090
00091 if (host_field == NULL || user_field == NULL)
00092 break;
00093
00094 if (!(exp_user = ircd_pcre_compile(user_field, &errptr)) ||
00095 !(exp_host = ircd_pcre_compile(host_field, &errptr)))
00096 {
00097 sendto_realops_flags(UMODE_ALL, L_ALL,
00098 "Failed to add regular expression based K-Line: %s", errptr);
00099 break;
00100 }
00101
00102 aconf = map_to_conf(make_conf_item(RKLINE_TYPE));
00103
00104 aconf->regexuser = exp_user;
00105 aconf->regexhost = exp_host;
00106
00107 DupString(aconf->user, user_field);
00108 DupString(aconf->host, host_field);
00109
00110 if (reason_field != NULL)
00111 DupString(aconf->reason, reason_field);
00112 else
00113 DupString(aconf->reason, "No reason");
00114
00115 }
00116 break;
00117
00118 case DLINE_TYPE:
00119 parse_csv_line(line, &host_field, &reason_field, NULL);
00120 conf = make_conf_item(DLINE_TYPE);
00121 aconf = (struct AccessItem *)map_to_conf(conf);
00122 if (host_field != NULL)
00123 DupString(aconf->host, host_field);
00124 if (reason_field != NULL)
00125 DupString(aconf->reason, reason_field);
00126 conf_add_d_conf(aconf);
00127 break;
00128
00129 case XLINE_TYPE:
00130 parse_csv_line(line, &name_field, &reason_field, &oper_reason, NULL);
00131 conf = make_conf_item(XLINE_TYPE);
00132 match_item = (struct MatchItem *)map_to_conf(conf);
00133 if (name_field != NULL)
00134 DupString(conf->name, name_field);
00135 if (reason_field != NULL)
00136 DupString(match_item->reason, reason_field);
00137 break;
00138
00139 case RXLINE_TYPE:
00140 {
00141 const char *errptr = NULL;
00142 pcre *exp_p = NULL;
00143
00144 parse_csv_line(line, &name_field, &reason_field, &oper_reason, NULL);
00145
00146 if (name_field == NULL)
00147 break;
00148
00149 if (!(exp_p = ircd_pcre_compile(name_field, &errptr)))
00150 {
00151 sendto_realops_flags(UMODE_ALL, L_ALL,
00152 "Failed to add regular expression based X-Line: %s", errptr);
00153 break;
00154 }
00155
00156 conf = make_conf_item(RXLINE_TYPE);
00157 conf->regexpname = exp_p;
00158 match_item = map_to_conf(conf);
00159 DupString(conf->name, name_field);
00160
00161 if (reason_field != NULL)
00162 DupString(match_item->reason, reason_field);
00163 else
00164 DupString(match_item->reason, "No reason");
00165 }
00166 break;
00167
00168 case CRESV_TYPE:
00169 parse_csv_line(line, &name_field, &reason_field, NULL);
00170 (void)create_channel_resv(name_field, reason_field, 0);
00171 break;
00172
00173 case NRESV_TYPE:
00174 parse_csv_line(line, &name_field, &reason_field, NULL);
00175 (void)create_nick_resv(name_field, reason_field, 0);
00176 break;
00177
00178 case GLINE_TYPE:
00179 case GDENY_TYPE:
00180 case CONF_TYPE:
00181 case OPER_TYPE:
00182 case CLIENT_TYPE:
00183 case SERVER_TYPE:
00184 case CLUSTER_TYPE:
00185 case HUB_TYPE:
00186 case LEAF_TYPE:
00187 case ULINE_TYPE:
00188 case EXEMPTDLINE_TYPE:
00189 case CLASS_TYPE:
00190 break;
00191 }
00192 }
00193 }
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203 static void
00204 parse_csv_line(char *line, ...)
00205 {
00206 va_list args;
00207 char **dest;
00208 char *field = NULL;
00209
00210 va_start(args, line);
00211
00212 for (; ;)
00213 {
00214 dest = va_arg(args, char **);
00215 if ((dest == NULL) || ((field = getfield(field ? NULL : line)) == NULL))
00216 {
00217 va_end(args);
00218 return;
00219 }
00220 *dest = field;
00221 }
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 void
00239 write_conf_line(struct Client *source_p, struct ConfItem *conf,
00240 const char *current_date, time_t cur_time)
00241 {
00242 FBFILE *out;
00243 const char *filename, *from, *to;
00244 struct AccessItem *aconf;
00245 struct MatchItem *xconf;
00246 struct ResvChannel *cresv_p=NULL;
00247 struct MatchItem *nresv_p=NULL;
00248 ConfType type;
00249
00250 type = conf->type;
00251 filename = get_conf_name(type);
00252
00253 if (!MyConnect(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
00254 {
00255 from = me.id;
00256 to = source_p->id;
00257 }
00258 else
00259 {
00260 from = me.name;
00261 to = source_p->name;
00262 }
00263
00264 if ((out = fbopen(filename, "a")) == NULL)
00265 {
00266 sendto_realops_flags(UMODE_ALL, L_ALL,
00267 "*** Problem opening %s ", filename);
00268 return;
00269 }
00270
00271 switch(type)
00272 {
00273 case KLINE_TYPE:
00274 aconf = (struct AccessItem *)map_to_conf(conf);
00275 sendto_realops_flags(UMODE_ALL, L_ALL,
00276 "%s added K-Line for [%s@%s] [%s]",
00277 get_oper_name(source_p),
00278 aconf->user, aconf->host, aconf->reason);
00279 sendto_one(source_p, ":%s NOTICE %s :Added K-Line [%s@%s]",
00280 from, to, aconf->user, aconf->host);
00281 ilog(L_TRACE, "%s added K-Line for [%s@%s] [%s]",
00282 source_p->name, aconf->user, aconf->host, aconf->reason);
00283 log_oper_action(LOG_KLINE_TYPE, source_p, "[%s@%s] [%s]\n",
00284 aconf->user, aconf->host, aconf->reason);
00285 write_csv_line(out, "%s%s%s%s%s%s%d",
00286 aconf->user, aconf->host,
00287 aconf->reason, aconf->oper_reason, current_date,
00288 get_oper_name(source_p), cur_time);
00289 break;
00290
00291 case RKLINE_TYPE:
00292 aconf = map_to_conf(conf);
00293 sendto_realops_flags(UMODE_ALL, L_ALL,
00294 "%s added RK-Line for [%s@%s] [%s]",
00295 get_oper_name(source_p),
00296 aconf->user, aconf->host, aconf->reason);
00297 sendto_one(source_p, ":%s NOTICE %s :Added RK-Line [%s@%s]",
00298 from, to, aconf->user, aconf->host);
00299 ilog(L_TRACE, "%s added K-Line for [%s@%s] [%s]",
00300 source_p->name, aconf->user, aconf->host, aconf->reason);
00301 log_oper_action(LOG_RKLINE_TYPE, source_p, "[%s@%s] [%s]\n",
00302 aconf->user, aconf->host, aconf->reason);
00303 write_csv_line(out, "%s%s%s%s%s%s%d",
00304 aconf->user, aconf->host,
00305 aconf->reason, aconf->oper_reason, current_date,
00306 get_oper_name(source_p), cur_time);
00307 break;
00308
00309 case DLINE_TYPE:
00310 aconf = (struct AccessItem *)map_to_conf(conf);
00311 sendto_realops_flags(UMODE_ALL, L_ALL,
00312 "%s added D-Line for [%s] [%s]",
00313 get_oper_name(source_p), aconf->host, aconf->reason);
00314 sendto_one(source_p, ":%s NOTICE %s :Added D-Line [%s] to %s",
00315 from, to, aconf->host, filename);
00316 ilog(L_TRACE, "%s added D-Line for [%s] [%s]",
00317 get_oper_name(source_p), aconf->host, aconf->reason);
00318 log_oper_action(LOG_DLINE_TYPE, source_p, "[%s] [%s]\n",
00319 aconf->host, aconf->reason);
00320 write_csv_line(out, "%s%s%s%s%s%d",
00321 aconf->host, aconf->reason, aconf->oper_reason,
00322 current_date,
00323 get_oper_name(source_p), cur_time);
00324 break;
00325
00326 case XLINE_TYPE:
00327 xconf = (struct MatchItem *)map_to_conf(conf);
00328 sendto_realops_flags(UMODE_ALL, L_ALL,
00329 "%s added X-Line for [%s] [%s]",
00330 get_oper_name(source_p), conf->name,
00331 xconf->reason);
00332 sendto_one(source_p,
00333 ":%s NOTICE %s :Added X-Line [%s] [%d] [%s] to %s",
00334 from, to, conf->name,
00335 xconf->action, xconf->reason, filename);
00336 ilog(L_TRACE, "%s added X-Line for [%s] [%s]",
00337 get_oper_name(source_p), conf->name, xconf->reason);
00338 write_csv_line(out, "%s%s%s%s%s%d",
00339 conf->name, xconf->reason, xconf->oper_reason,
00340 current_date, get_oper_name(source_p), cur_time);
00341 break;
00342
00343 case RXLINE_TYPE:
00344 xconf = (struct MatchItem *)map_to_conf(conf);
00345 sendto_realops_flags(UMODE_ALL, L_ALL,
00346 "%s added RX-Line for [%s] [%s]",
00347 get_oper_name(source_p), conf->name,
00348 xconf->reason);
00349 sendto_one(source_p,
00350 ":%s NOTICE %s :Added RX-Line [%s] [%s] to %s",
00351 from, to, conf->name,
00352 xconf->reason, filename);
00353 ilog(L_TRACE, "%s added X-Line for [%s] [%s]",
00354 get_oper_name(source_p), conf->name, xconf->reason);
00355 write_csv_line(out, "%s%s%s%s%s%d",
00356 conf->name, xconf->reason, xconf->oper_reason,
00357 current_date, get_oper_name(source_p), cur_time);
00358 break;
00359
00360 case CRESV_TYPE:
00361 cresv_p = (struct ResvChannel *)map_to_conf(conf);
00362
00363 write_csv_line(out, "%s%s",
00364 cresv_p->name, cresv_p->reason);
00365 break;
00366
00367 case NRESV_TYPE:
00368 nresv_p = (struct MatchItem *)map_to_conf(conf);
00369
00370 write_csv_line(out, "%s%s",
00371 conf->name, nresv_p->reason);
00372 break;
00373
00374 default:
00375 fbclose(out);
00376 return;
00377 }
00378
00379 fbclose(out);
00380 }
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390 static int
00391 write_csv_line(FBFILE *out, const char *format, ...)
00392 {
00393 char c;
00394 size_t bytes = 0;
00395 va_list args;
00396 char tmp[1024];
00397 char *str = tmp;
00398 const char *null_string = "";
00399
00400 if (out == NULL)
00401 return(0);
00402
00403 va_start(args, format);
00404
00405 while ((c = *format++))
00406 {
00407 if (c == '%')
00408 {
00409 c = *format++;
00410 if (c == 's')
00411 {
00412 const char *p1 = va_arg(args, const char *);
00413 if (p1 == NULL)
00414 p1 = null_string;
00415 *str++ = '\"';
00416 ++bytes;
00417 while (*p1 != '\0')
00418 {
00419 *str++ = *p1++;
00420 ++bytes;
00421 }
00422 *str++ = '\"';
00423 *str++ = ',';
00424
00425 bytes += 2;
00426 continue;
00427 }
00428 if (c == 'c')
00429 {
00430 *str++ = '\"';
00431 ++bytes;
00432 *str++ = (char) va_arg(args, int);
00433 ++bytes;
00434 *str++ = '\"';
00435 *str++ = ',';
00436
00437 bytes += 2;
00438 continue;
00439 }
00440
00441 if (c == 'd')
00442 {
00443 int v = va_arg(args, int);
00444 char t[40];
00445 char *p=t;
00446
00447 while (v > 10)
00448 {
00449 *p++ = (v % 10) + '0';
00450 v = v/10;
00451 }
00452 *p++ = (v % 10) + '0';
00453
00454 *str++ = '\"';
00455 ++bytes;
00456 while (p != t)
00457 {
00458 *str++ = *--p;
00459 ++bytes;
00460 }
00461
00462 *str++ = '\"';
00463 *str++ = ',';
00464 bytes += 2;
00465 continue;
00466 }
00467 if (c != '%')
00468 {
00469 int ret;
00470
00471 format -= 2;
00472 ret = vsprintf(str, format, args);
00473 str += ret;
00474 bytes += ret;
00475 *str++ = ',';
00476
00477 ++bytes;
00478 break;
00479 }
00480 }
00481 *str++ = c;
00482 ++bytes;
00483 }
00484
00485 if (*(str-1) == ',')
00486 {
00487 *(str-1) = '\n';
00488 *str = '\0';
00489 }
00490 else
00491 {
00492 *str++ = '\n';
00493 ++bytes;
00494 *str = '\0';
00495 }
00496
00497 va_end(args);
00498 str = tmp;
00499 fbputs(str, out, bytes);
00500
00501 return(bytes);
00502 }
00503
00504
00505
00506
00507
00508
00509
00510
00511 static char *
00512 getfield(char *newline)
00513 {
00514 static char *line = NULL;
00515 char *end, *field;
00516
00517 if (newline != NULL)
00518 line = newline;
00519
00520 if (line == NULL)
00521 return(NULL);
00522
00523 field = line;
00524
00525
00526 for(;;)
00527 {
00528 if (*field == '\0')
00529 return(NULL);
00530 else if (*field == '"')
00531 break;
00532 ++field;
00533 }
00534
00535
00536 end = ++field;
00537
00538 for (;;)
00539 {
00540
00541 if ((*end == '\0') || (*end == '\n'))
00542 {
00543 line = NULL;
00544 return(NULL);
00545 }
00546 else if (*end == '\\')
00547 {
00548 end++;
00549 }
00550 else if (*end == '"')
00551 {
00552 *end++ = '\0';
00553 line = end;
00554 return(field);
00555 }
00556
00557 end++;
00558 }
00559
00560 return (NULL);
00561 }
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571 int
00572 remove_conf_line(ConfType type, struct Client *source_p, const char *pat1, const char *pat2)
00573 {
00574 const char *filename;
00575 FBFILE *in, *out;
00576 int pairme=0;
00577 char buf[IRCD_BUFSIZE], buff[IRCD_BUFSIZE], temppath[IRCD_BUFSIZE];
00578 char *found1;
00579 char *found2;
00580 int oldumask;
00581 int (*cmpfunc)(const char *, const char *) = irccmp;
00582
00583 if (type == RXLINE_TYPE || type == RKLINE_TYPE)
00584 cmpfunc = strcmp;
00585
00586 filename = get_conf_name(type);
00587
00588 if ((in = fbopen(filename, "r")) == NULL)
00589 {
00590 sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name,
00591 source_p->name, filename);
00592 return -1;
00593 }
00594
00595 ircsprintf(temppath, "%s.tmp", filename);
00596 oldumask = umask(0);
00597
00598 if ((out = fbopen(temppath, "w")) == NULL)
00599 {
00600 sendto_one(source_p, ":%s NOTICE %s :Cannot open %s", me.name,
00601 source_p->name, temppath);
00602 fbclose(in);
00603 umask(oldumask);
00604 return -1;
00605 }
00606
00607 umask(oldumask);
00608 oldumask = umask(0);
00609
00610 while (fbgets(buf, sizeof(buf), in) != NULL)
00611 {
00612 if ((*buf == '\0') || (*buf == '#'))
00613 {
00614 if (flush_write(source_p, in, out, buf, temppath) < 0)
00615 return -1;
00616 }
00617
00618
00619 strlcpy(buff, buf, sizeof(buff));
00620
00621 if ((found1 = getfield(buff)) == NULL)
00622 {
00623 if (flush_write(source_p, in, out, buf, temppath) < 0)
00624 return -1;
00625 continue;
00626 }
00627
00628 if (pat2 != NULL)
00629 {
00630 if ((found2 = getfield(NULL)) == NULL)
00631 {
00632 if (flush_write(source_p, in, out, buf, temppath) < 0)
00633 return -1;
00634 continue;
00635 }
00636
00637 if (!cmpfunc(pat1, found1) && !cmpfunc(pat2, found2))
00638 {
00639 pairme = 1;
00640 continue;
00641 }
00642 else
00643 {
00644 if(flush_write(source_p, in, out, buf, temppath) < 0)
00645 return -1;
00646 continue;
00647 }
00648 }
00649 else
00650 {
00651 if (!cmpfunc(pat1, found1))
00652 {
00653 pairme = 1;
00654 continue;
00655 }
00656 else
00657 {
00658 if(flush_write(source_p, in, out, buf, temppath) < 0)
00659 return -1;
00660 continue;
00661 }
00662 }
00663 }
00664
00665 fbclose(in);
00666 fbclose(out);
00667
00668
00669
00670
00671
00672
00673 if (pairme == 0)
00674 {
00675 if(temppath != NULL)
00676 (void)unlink(temppath);
00677 return 0;
00678 }
00679 else
00680 {
00681 (void)rename(temppath, filename);
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693 rehash(0);
00694 return 1;
00695 }
00696 }
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718 static int
00719 flush_write(struct Client *source_p, FBFILE *in, FBFILE* out,
00720 const char *buf, const char *temppath)
00721 {
00722 int error_on_write = (fbputs(buf, out, strlen(buf)) < 0) ? (-1) : (0);
00723
00724 if (error_on_write)
00725 {
00726 sendto_one(source_p,":%s NOTICE %s :Unable to write to %s aborting",
00727 me.name, source_p->name, temppath);
00728 if(temppath != NULL)
00729 (void)unlink(temppath);
00730 fbclose(in);
00731 fbclose(out);
00732 }
00733
00734 return (error_on_write);
00735 }