1 /*
2 * Unreal Internet Relay Chat Daemon, src/s_conf.c
3 * (C) 1998-2000 Chris Behrens & Fred Jacobs (comstud, moogle)
4 * (C) 2000-2002 Carsten V. Munk and the UnrealIRCd Team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 1, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 #include "struct.h"
21 #include "url.h"
22 #include "common.h"
23 #include "sys.h"
24 #include "numeric.h"
25 #include "channel.h"
26 #include "macros.h"
27 #include <fcntl.h>
28 #ifndef _WIN32
29 #include <sys/socket.h>
30 #include <sys/wait.h>
31 #else
32 #include <io.h>
33 #endif
34 #include <sys/stat.h>
35 #ifdef __hpux
36 #include "inet.h"
37 #endif
38 #if defined(PCS) || defined(AIX) || defined(SVR3)
39 #include <time.h>
40 #endif
41 #include <string.h>
42 #ifdef GLOBH
43 #include <glob.h>
44 #endif
45 #ifdef STRIPBADWORDS
46 #include "badwords.h"
47 #endif
48 #include "h.h"
49 #include "inet.h"
50 #include "proto.h"
51 #ifdef _WIN32
52 #undef GLOBH
53 #endif
54 #include "badwords.h"
55
56 #define ircstrdup(x,y) do { if (x) MyFree(x); if (!y) x = NULL; else x = strdup(y); } while(0)
57 #define ircfree(x) do { if (x) MyFree(x); x = NULL; } while(0)
58
59 /*
60 * Some typedefs..
61 */
62 typedef struct _confcommand ConfigCommand;
63 struct _confcommand
64 {
65 char *name;
66 int (*conffunc)(ConfigFile *conf, ConfigEntry *ce);
67 int (*testfunc)(ConfigFile *conf, ConfigEntry *ce);
68 };
69
70 typedef struct _conf_operflag OperFlag;
71 struct _conf_operflag
72 {
73 long flag;
74 char *name;
75 };
76
77
78 /* Config commands */
79
80 static int _conf_admin (ConfigFile *conf, ConfigEntry *ce);
81 static int _conf_me (ConfigFile *conf, ConfigEntry *ce);
82 static int _conf_files (ConfigFile *conf, ConfigEntry *ce);
83 static int _conf_oper (ConfigFile *conf, ConfigEntry *ce);
84 static int _conf_class (ConfigFile *conf, ConfigEntry *ce);
85 static int _conf_drpass (ConfigFile *conf, ConfigEntry *ce);
86 static int _conf_ulines (ConfigFile *conf, ConfigEntry *ce);
87 static int _conf_include (ConfigFile *conf, ConfigEntry *ce);
88 static int _conf_tld (ConfigFile *conf, ConfigEntry *ce);
89 static int _conf_listen (ConfigFile *conf, ConfigEntry *ce);
90 static int _conf_allow (ConfigFile *conf, ConfigEntry *ce);
91 static int _conf_except (ConfigFile *conf, ConfigEntry *ce);
92 static int _conf_vhost (ConfigFile *conf, ConfigEntry *ce);
93 static int _conf_link (ConfigFile *conf, ConfigEntry *ce);
94 static int _conf_ban (ConfigFile *conf, ConfigEntry *ce);
95 static int _conf_set (ConfigFile *conf, ConfigEntry *ce);
96 #ifdef STRIPBADWORDS
97 static int _conf_badword (ConfigFile *conf, ConfigEntry *ce);
98 #endif
99 static int _conf_deny (ConfigFile *conf, ConfigEntry *ce);
100 static int _conf_deny_dcc (ConfigFile *conf, ConfigEntry *ce);
101 static int _conf_deny_link (ConfigFile *conf, ConfigEntry *ce);
102 static int _conf_deny_channel (ConfigFile *conf, ConfigEntry *ce);
103 static int _conf_deny_version (ConfigFile *conf, ConfigEntry *ce);
104 static int _conf_allow_channel (ConfigFile *conf, ConfigEntry *ce);
105 static int _conf_allow_dcc (ConfigFile *conf, ConfigEntry *ce);
106 static int _conf_loadmodule (ConfigFile *conf, ConfigEntry *ce);
107 static int _conf_log (ConfigFile *conf, ConfigEntry *ce);
108 static int _conf_alias (ConfigFile *conf, ConfigEntry *ce);
109 static int _conf_help (ConfigFile *conf, ConfigEntry *ce);
110 static int _conf_offchans (ConfigFile *conf, ConfigEntry *ce);
111 static int _conf_spamfilter (ConfigFile *conf, ConfigEntry *ce);
112 static int _conf_cgiirc (ConfigFile *conf, ConfigEntry *ce);
113
114 /*
115 * Validation commands
116 */
117
118 static int _test_admin (ConfigFile *conf, ConfigEntry *ce);
119 static int _test_me (ConfigFile *conf, ConfigEntry *ce);
120 static int _test_files (ConfigFile *conf, ConfigEntry *ce);
121 static int _test_oper (ConfigFile *conf, ConfigEntry *ce);
122 static int _test_class (ConfigFile *conf, ConfigEntry *ce);
123 static int _test_drpass (ConfigFile *conf, ConfigEntry *ce);
124 static int _test_ulines (ConfigFile *conf, ConfigEntry *ce);
125 static int _test_include (ConfigFile *conf, ConfigEntry *ce);
126 static int _test_tld (ConfigFile *conf, ConfigEntry *ce);
127 static int _test_listen (ConfigFile *conf, ConfigEntry *ce);
128 static int _test_allow (ConfigFile *conf, ConfigEntry *ce);
129 static int _test_except (ConfigFile *conf, ConfigEntry *ce);
130 static int _test_vhost (ConfigFile *conf, ConfigEntry *ce);
131 static int _test_link (ConfigFile *conf, ConfigEntry *ce);
132 static int _test_ban (ConfigFile *conf, ConfigEntry *ce);
133 static int _test_set (ConfigFile *conf, ConfigEntry *ce);
134 #ifdef STRIPBADWORDS
135 static int _test_badword (ConfigFile *conf, ConfigEntry *ce);
136 #endif
137 static int _test_deny (ConfigFile *conf, ConfigEntry *ce);
138 static int _test_allow_channel (ConfigFile *conf, ConfigEntry *ce);
139 static int _test_allow_dcc (ConfigFile *conf, ConfigEntry *ce);
140 static int _test_loadmodule (ConfigFile *conf, ConfigEntry *ce);
141 static int _test_log (ConfigFile *conf, ConfigEntry *ce);
142 static int _test_alias (ConfigFile *conf, ConfigEntry *ce);
143 static int _test_help (ConfigFile *conf, ConfigEntry *ce);
144 static int _test_offchans (ConfigFile *conf, ConfigEntry *ce);
145 static int _test_spamfilter (ConfigFile *conf, ConfigEntry *ce);
146 static int _test_cgiirc (ConfigFile *conf, ConfigEntry *ce);
147
148 /* This MUST be alphabetized */
149 static ConfigCommand _ConfigCommands[] = {
150 { "admin", _conf_admin, _test_admin },
151 { "alias", _conf_alias, _test_alias },
152 { "allow", _conf_allow, _test_allow },
153 #ifdef STRIPBADWORDS
154 { "badword", _conf_badword, _test_badword },
155 #endif
156 { "ban", _conf_ban, _test_ban },
157 { "cgiirc", _conf_cgiirc, _test_cgiirc },
158 { "class", _conf_class, _test_class },
159 { "deny", _conf_deny, _test_deny },
160 { "drpass", _conf_drpass, _test_drpass },
161 { "except", _conf_except, _test_except },
162 { "files", _conf_files, _test_files },
163 { "help", _conf_help, _test_help },
164 { "include", NULL, _test_include },
165 { "link", _conf_link, _test_link },
166 { "listen", _conf_listen, _test_listen },
167 { "loadmodule", NULL, _test_loadmodule},
168 { "log", _conf_log, _test_log },
169 { "me", _conf_me, _test_me },
170 { "official-channels", _conf_offchans, _test_offchans },
171 { "oper", _conf_oper, _test_oper },
172 { "set", _conf_set, _test_set },
173 { "spamfilter", _conf_spamfilter, _test_spamfilter },
174 { "tld", _conf_tld, _test_tld },
175 { "ulines", _conf_ulines, _test_ulines },
176 { "vhost", _conf_vhost, _test_vhost },
177 };
178
179 static int _OldOperFlags[] = {
180 OFLAG_LOCAL, 'o',
181 OFLAG_GLOBAL, 'O',
182 OFLAG_REHASH, 'r',
183 OFLAG_DIE, 'D',
184 OFLAG_RESTART, 'R',
185 OFLAG_HELPOP, 'h',
186 OFLAG_GLOBOP, 'g',
187 OFLAG_WALLOP, 'w',
188 OFLAG_LOCOP, 'l',
189 OFLAG_LROUTE, 'c',
190 OFLAG_GROUTE, 'L',
191 OFLAG_LKILL, 'k',
192 OFLAG_GKILL, 'K',
193 OFLAG_KLINE, 'b',
194 OFLAG_UNKLINE, 'B',
195 OFLAG_LNOTICE, 'n',
196 OFLAG_GNOTICE, 'G',
197 OFLAG_ADMIN_, 'A',
198 OFLAG_SADMIN_, 'a',
199 OFLAG_NADMIN, 'N',
200 OFLAG_COADMIN, 'C',
201 OFLAG_ZLINE, 'z',
202 OFLAG_WHOIS, 'W',
203 OFLAG_HIDE, 'H',
204 OFLAG_TKL, 't',
205 OFLAG_GZL, 'Z',
206 OFLAG_OVERRIDE, 'v',
207 OFLAG_UMODEQ, 'q',
208 OFLAG_DCCDENY, 'd',
209 OFLAG_ADDLINE, 'X',
210 0, 0
211 };
212
213 /* This MUST be alphabetized */
214 static OperFlag _OperFlags[] = {
215 { OFLAG_ADMIN_, "admin"},
216 { OFLAG_ADDLINE, "can_addline"},
217 { OFLAG_DCCDENY, "can_dccdeny"},
218 { OFLAG_DIE, "can_die" },
219 { OFLAG_TKL, "can_gkline"},
220 { OFLAG_GKILL, "can_globalkill" },
221 { OFLAG_GNOTICE, "can_globalnotice" },
222 { OFLAG_GROUTE, "can_globalroute" },
223 { OFLAG_GLOBOP, "can_globops" },
224 { OFLAG_GZL, "can_gzline"},
225 { OFLAG_KLINE, "can_kline" },
226 { OFLAG_LKILL, "can_localkill" },
227 { OFLAG_LNOTICE, "can_localnotice" },
228 { OFLAG_LROUTE, "can_localroute" },
229 { OFLAG_OVERRIDE, "can_override" },
230 { OFLAG_REHASH, "can_rehash" },
231 { OFLAG_RESTART, "can_restart" },
232 { OFLAG_UMODEQ, "can_setq" },
233 { OFLAG_UNKLINE, "can_unkline" },
234 { OFLAG_WALLOP, "can_wallops" },
235 { OFLAG_ZLINE, "can_zline"},
236 { OFLAG_COADMIN_, "coadmin"},
237 { OFLAG_HIDE, "get_host"},
238 { OFLAG_WHOIS, "get_umodew"},
239 { OFLAG_GLOBAL, "global" },
240 { OFLAG_HELPOP, "helpop" },
241 { OFLAG_LOCAL, "local" },
242 { OFLAG_LOCOP, "locop"},
243 { OFLAG_NADMIN, "netadmin"},
244 { OFLAG_SADMIN_, "services-admin"},
245 };
246
247 /* This MUST be alphabetized */
248 static OperFlag _ListenerFlags[] = {
249 { LISTENER_CLIENTSONLY, "clientsonly"},
250 { LISTENER_JAVACLIENT, "java"},
251 { LISTENER_MASK, "mask"},
252 { LISTENER_REMOTEADMIN, "remoteadmin"},
253 { LISTENER_SERVERSONLY, "serversonly"},
254 { LISTENER_SSL, "ssl"},
255 { LISTENER_NORMAL, "standard"},
256 };
257
258 /* This MUST be alphabetized */
259 static OperFlag _LinkFlags[] = {
260 { CONNECT_AUTO, "autoconnect" },
261 { CONNECT_NODNSCACHE, "nodnscache" },
262 { CONNECT_NOHOSTCHECK, "nohostcheck" },
263 { CONNECT_QUARANTINE, "quarantine"},
264 { CONNECT_SSL, "ssl" },
265 { CONNECT_ZIP, "zip" },
266 };
267
268 /* This MUST be alphabetized */
269 static OperFlag _LogFlags[] = {
270 { LOG_CHGCMDS, "chg-commands" },
271 { LOG_CLIENT, "connects" },
272 { LOG_ERROR, "errors" },
273 { LOG_KILL, "kills" },
274 { LOG_KLINE, "kline" },
275 { LOG_OPER, "oper" },
276 { LOG_OVERRIDE, "oper-override" },
277 { LOG_SACMDS, "sadmin-commands" },
278 { LOG_SERVER, "server-connects" },
279 { LOG_SPAMFILTER, "spamfilter" },
280 { LOG_TKL, "tkl" },
281 };
282
283 /* This MUST be alphabetized */
284 static OperFlag ExceptTklFlags[] = {
285 { 0, "all" },
286 { TKL_GLOBAL|TKL_KILL, "gline" },
287 { TKL_GLOBAL|TKL_NICK, "gqline" },
288 { TKL_GLOBAL|TKL_ZAP, "gzline" },
289 { TKL_NICK, "qline" },
290 { TKL_GLOBAL|TKL_SHUN, "shun" }
291 };
292
293 #ifdef USE_SSL
294 /* This MUST be alphabetized */
295 static OperFlag _SSLFlags[] = {
296 { SSLFLAG_FAILIFNOCERT, "fail-if-no-clientcert" },
297 { SSLFLAG_DONOTACCEPTSELFSIGNED, "no-self-signed" },
298 { SSLFLAG_NOSTARTTLS, "no-starttls" },
299 { SSLFLAG_VERIFYCERT, "verify-certificate" },
300 };
301 #endif
302
303 struct {
304 unsigned conf_me : 1;
305 unsigned conf_admin : 1;
306 unsigned conf_listen : 1;
307 } requiredstuff;
308 struct SetCheck settings;
309 /*
310 * Utilities
311 */
312
313 void ipport_seperate(char *string, char **ip, char **port);
314 void port_range(char *string, int *start, int *end);
315 long config_checkval(char *value, unsigned short flags);
316
317 /*
318 * Parser
319 */
320
321 ConfigFile *config_load(char *filename);
322 void config_free(ConfigFile *cfptr);
323 static ConfigFile *config_parse(char *filename, char *confdata);
324 static void config_entry_free(ConfigEntry *ceptr);
325 ConfigEntry *config_find_entry(ConfigEntry *ce, char *name);
326 /*
327 * Error handling
328 */
329
330 void config_warn(char *format, ...);
331 void config_error(char *format, ...);
332 void config_status(char *format, ...);
333 void config_progress(char *format, ...);
334
335 #ifdef _WIN32
336 extern void win_log(char *format, ...);
337 extern void win_error();
338 #endif
339 extern void add_entropy_configfile(struct stat st, char *buf);
340 extern void unload_all_unused_snomasks();
341 extern void unload_all_unused_umodes();
342 extern void unload_all_unused_extcmodes(void);
343
344 extern int charsys_test_language(char *name);
345 extern void charsys_add_language(char *name);
346 extern void charsys_reset_pretest(void);
347 int charsys_postconftest(void);
348 void charsys_finish(void);
349 void delete_cgiircblock(ConfigItem_cgiirc *e);
350
351 /*
352 * Config parser (IRCd)
353 */
354 int init_conf(char *rootconf, int rehash);
355 int load_conf(char *filename, const char *original_path);
356 void config_rehash();
357 int config_run();
358 /*
359 * Configuration linked lists
360 */
361 ConfigItem_me *conf_me = NULL;
362 ConfigItem_files *conf_files = NULL;
363 ConfigItem_class *conf_class = NULL;
364 ConfigItem_class *default_class = NULL;
365 ConfigItem_admin *conf_admin = NULL;
366 ConfigItem_admin *conf_admin_tail = NULL;
367 ConfigItem_drpass *conf_drpass = NULL;
368 ConfigItem_ulines *conf_ulines = NULL;
369 ConfigItem_tld *conf_tld = NULL;
370 ConfigItem_oper *conf_oper = NULL;
371 ConfigItem_listen *conf_listen = NULL;
372 ConfigItem_allow *conf_allow = NULL;
373 ConfigItem_except *conf_except = NULL;
374 ConfigItem_vhost *conf_vhost = NULL;
375 ConfigItem_link *conf_link = NULL;
376 ConfigItem_cgiirc *conf_cgiirc = NULL;
377 ConfigItem_ban *conf_ban = NULL;
378 ConfigItem_deny_dcc *conf_deny_dcc = NULL;
379 ConfigItem_deny_channel *conf_deny_channel = NULL;
380 ConfigItem_allow_channel *conf_allow_channel = NULL;
381 ConfigItem_allow_dcc *conf_allow_dcc = NULL;
382 ConfigItem_deny_link *conf_deny_link = NULL;
383 ConfigItem_deny_version *conf_deny_version = NULL;
384 ConfigItem_log *conf_log = NULL;
385 ConfigItem_alias *conf_alias = NULL;
386 ConfigItem_include *conf_include = NULL;
387 ConfigItem_help *conf_help = NULL;
388 #ifdef STRIPBADWORDS
389 ConfigItem_badword *conf_badword_channel = NULL;
390 ConfigItem_badword *conf_badword_message = NULL;
391 ConfigItem_badword *conf_badword_quit = NULL;
392 #endif
393 ConfigItem_offchans *conf_offchans = NULL;
394
395 aConfiguration iConf;
396 MODVAR aConfiguration tempiConf;
397 MODVAR ConfigFile *conf = NULL;
398
399 MODVAR int config_error_flag = 0;
400 int config_verbose = 0;
401
402 void add_include(const char *filename, const char *included_from, int included_from_line);
403 #ifdef USE_LIBCURL
404 void add_remote_include(const char *, const char *, int, const char *, const char *included_from, int included_from_line);
405 void update_remote_include(ConfigItem_include *inc, const char *file, int, const char *errorbuf);
406 int remote_include(ConfigEntry *ce);
407 #endif
408 void unload_notloaded_includes(void);
409 void load_includes(void);
410 void unload_loaded_includes(void);
411 int rehash_internal(aClient *cptr, aClient *sptr, int sig);
412
413
414 /* Pick out the ip address and the port number from a string.
415 * The string syntax is: ip:port. ip must be enclosed in brackets ([]) if its an ipv6
416 * address because they contain colon (:) separators. The ip part is optional. If the string
417 * contains a single number its assumed to be a port number.
418 *
419 * Returns with ip pointing to the ip address (if one was specified), a "*" (if only a port
420 * was specified), or an empty string if there was an error. port is returned pointing to the
421 * port number if one was specified, otherwise it points to a empty string.
422 */
ipport_seperate(char * string,char ** ip,char ** port)423 void ipport_seperate(char *string, char **ip, char **port)
424 {
425 char *f;
426
427 /* assume failure */
428 *ip = *port = "";
429
430 /* sanity check */
431 if (string && strlen(string) > 0)
432 {
433 /* handle ipv6 type of ip address */
434 if (*string == '[')
435 {
436 if ((f = strrchr(string, ']')))
437 {
438 *ip = string + 1; /* skip [ */
439 *f = '\0'; /* terminate the ip string */
440 /* next char must be a : if a port was specified */
441 if (*++f == ':')
442 {
443 *port = ++f;
444 }
445 }
446 }
447 /* handle ipv4 and port */
448 else if ((f = strchr(string, ':')))
449 {
450 /* we found a colon... we may have ip:port or just :port */
451 if (f == string)
452 {
453 /* we have just :port */
454 *ip = "*";
455 }
456 else
457 {
458 /* we have ip:port */
459 *ip = string;
460 *f = '\0';
461 }
462 *port = ++f;
463 }
464 /* no ip was specified, just a port number */
465 else if (!strcmp(string, my_itoa(atoi(string))))
466 {
467 *ip = "*";
468 *port = string;
469 }
470 }
471 }
472
port_range(char * string,int * start,int * end)473 void port_range(char *string, int *start, int *end)
474 {
475 char *c = strchr(string, '-');
476 if (!c)
477 {
478 int tmp = atoi(string);
479 *start = tmp;
480 *end = tmp;
481 return;
482 }
483 *c = '\0';
484 *start = atoi(string);
485 *end = atoi((c+1));
486 }
487
488 /** Parses '5:60s' config values.
489 * orig: original string
490 * times: pointer to int, first value (before the :)
491 * period: pointer to int, second value (after the :) in seconds
492 * RETURNS: 0 for parse error, 1 if ok.
493 * REMARK: times&period should be ints!
494 */
config_parse_flood(char * orig,int * times,int * period)495 int config_parse_flood(char *orig, int *times, int *period)
496 {
497 char *x;
498
499 *times = *period = 0;
500 x = strchr(orig, ':');
501 /* 'blah', ':blah', '1:' */
502 if (!x || (x == orig) || (*(x+1) == '\0'))
503 return 0;
504
505 *x = '\0';
506 *times = atoi(orig);
507 *period = config_checkval(x+1, CFG_TIME);
508 *x = ':'; /* restore */
509 return 1;
510 }
511
config_checkval(char * orig,unsigned short flags)512 long config_checkval(char *orig, unsigned short flags) {
513 char *value;
514 char *text;
515 long ret = 0;
516
517 value = strdup(orig);
518
519 if (flags == CFG_YESNO) {
520 for (text = value; *text; text++) {
521 if (!isalnum(*text))
522 continue;
523 if (tolower(*text) == 'y' || (tolower(*text) == 'o' &&
524 tolower(*(text+1)) == 'n') || *text == '1' || tolower(*text) == 't') {
525 ret = 1;
526 break;
527 }
528 }
529 }
530 else if (flags == CFG_SIZE) {
531 int mfactor = 1;
532 char *sz;
533 for (text = value; *text; text++) {
534 if (isalpha(*text)) {
535 if (tolower(*text) == 'k')
536 mfactor = 1024;
537 else if (tolower(*text) == 'm')
538 mfactor = 1048576;
539 else if (tolower(*text) == 'g')
540 mfactor = 1073741824;
541 else
542 mfactor = 1;
543 sz = text;
544 while (isalpha(*text))
545 text++;
546
547 *sz-- = 0;
548 while (sz-- > value && *sz) {
549 if (isspace(*sz))
550 *sz = 0;
551 if (!isdigit(*sz))
552 break;
553 }
554 ret += atoi(sz+1)*mfactor;
555 if (*text == '\0') {
556 text++;
557 break;
558 }
559 }
560 }
561 mfactor = 1;
562 sz = text;
563 sz--;
564 while (sz-- > value) {
565 if (isspace(*sz))
566 *sz = 0;
567 if (!isdigit(*sz))
568 break;
569 }
570 ret += atoi(sz+1)*mfactor;
571 }
572 else if (flags == CFG_TIME) {
573 int mfactor = 1;
574 char *sz;
575 for (text = value; *text; text++) {
576 if (isalpha(*text)) {
577 if (tolower(*text) == 'w')
578 mfactor = 604800;
579 else if (tolower(*text) == 'd')
580 mfactor = 86400;
581 else if (tolower(*text) == 'h')
582 mfactor = 3600;
583 else if (tolower(*text) == 'm')
584 mfactor = 60;
585 else
586 mfactor = 1;
587 sz = text;
588 while (isalpha(*text))
589 text++;
590
591 *sz-- = 0;
592 while (sz-- > value && *sz) {
593 if (isspace(*sz))
594 *sz = 0;
595 if (!isdigit(*sz))
596 break;
597 }
598 ret += atoi(sz+1)*mfactor;
599 if (*text == '\0') {
600 text++;
601 break;
602 }
603 }
604 }
605 mfactor = 1;
606 sz = text;
607 sz--;
608 while (sz-- > value) {
609 if (isspace(*sz))
610 *sz = 0;
611 if (!isdigit(*sz))
612 break;
613 }
614 ret += atoi(sz+1)*mfactor;
615 }
616 free(value);
617 return ret;
618 }
619
iplist_onlist(IPList * iplist,char * ip)620 int iplist_onlist(IPList *iplist, char *ip)
621 {
622 IPList *e;
623
624 for (e = iplist; e; e = e->next)
625 if (!match(e->mask, ip))
626 return 1;
627 return 0;
628 }
629
set_channelmodes(char * modes,struct ChMode * store,int warn)630 void set_channelmodes(char *modes, struct ChMode *store, int warn)
631 {
632 aCtab *tab;
633 char *params = strchr(modes, ' ');
634 char *parambuf = NULL;
635 char *param = NULL;
636 char *save = NULL;
637
638 warn = 0; // warn is broken
639
640 if (params)
641 {
642 params++;
643 parambuf = MyMalloc(strlen(params)+1);
644 strcpy(parambuf, params);
645 param = strtoken(&save, parambuf, " ");
646 }
647
648 for (; *modes && *modes != ' '; modes++)
649 {
650 if (*modes == '+')
651 continue;
652 if (*modes == '-')
653 /* When a channel is created it has no modes, so just ignore if the
654 * user asks us to unset anything -- codemastr
655 */
656 {
657 while (*modes && *modes != '+')
658 modes++;
659 continue;
660 }
661 switch (*modes)
662 {
663 case 'f':
664 {
665 #ifdef NEWCHFLOODPROT
666 char *myparam = param;
667
668 ChanFloodProt newf;
669
670 memset(&newf, 0, sizeof(newf));
671 if (!myparam)
672 break;
673 /* Go to next parameter */
674 param = strtoken(&save, NULL, " ");
675
676 if (myparam[0] != '[')
677 {
678 if (warn)
679 config_status("set::modes-on-join: please use the new +f format: '10:5' becomes '[10t]:5' "
680 "and '*10:5' becomes '[10t#b]:5'.");
681 } else
682 {
683 char xbuf[256], c, a, *p, *p2, *x = xbuf+1;
684 int v;
685 unsigned short breakit;
686 unsigned char r;
687
688 /* '['<number><1 letter>[optional: '#'+1 letter],[next..]']'':'<number> */
689 strlcpy(xbuf, myparam, sizeof(xbuf));
690 p2 = strchr(xbuf+1, ']');
691 if (!p2)
692 break;
693 *p2 = '\0';
694 if (*(p2+1) != ':')
695 break;
696 breakit = 0;
697 for (x = strtok(xbuf+1, ","); x; x = strtok(NULL, ","))
698 {
699 /* <number><1 letter>[optional: '#'+1 letter] */
700 p = x;
701 while(isdigit(*p)) { p++; }
702 if ((*p == '\0') ||
703 !((*p == 'c') || (*p == 'j') || (*p == 'k') ||
704 (*p == 'm') || (*p == 'n') || (*p == 't')))
705 break;
706 c = *p;
707 *p = '\0';
708 v = atoi(x);
709 if ((v < 1) || (v > 999)) /* out of range... */
710 break;
711 p++;
712 a = '\0';
713 r = 0;
714 if (*p != '\0')
715 {
716 if (*p == '#')
717 {
718 p++;
719 a = *p;
720 p++;
721 if (*p != '\0')
722 {
723 int tv;
724 tv = atoi(p);
725 if (tv <= 0)
726 tv = 0; /* (ignored) */
727 if (tv > 255)
728 tv = 255; /* set to max */
729 r = tv;
730 }
731 }
732 }
733
734 switch(c)
735 {
736 case 'c':
737 newf.l[FLD_CTCP] = v;
738 if ((a == 'm') || (a == 'M'))
739 newf.a[FLD_CTCP] = a;
740 else
741 newf.a[FLD_CTCP] = 'C';
742 newf.r[FLD_CTCP] = r;
743 break;
744 case 'j':
745 newf.l[FLD_JOIN] = v;
746 if (a == 'R')
747 newf.a[FLD_JOIN] = a;
748 else
749 newf.a[FLD_JOIN] = 'i';
750 newf.r[FLD_JOIN] = r;
751 break;
752 case 'k':
753 newf.l[FLD_KNOCK] = v;
754 newf.a[FLD_KNOCK] = 'K';
755 newf.r[FLD_KNOCK] = r;
756 break;
757 case 'm':
758 newf.l[FLD_MSG] = v;
759 if (a == 'M')
760 newf.a[FLD_MSG] = a;
761 else
762 newf.a[FLD_MSG] = 'm';
763 newf.r[FLD_MSG] = r;
764 break;
765 case 'n':
766 newf.l[FLD_NICK] = v;
767 newf.a[FLD_NICK] = 'N';
768 newf.r[FLD_NICK] = r;
769 break;
770 case 't':
771 newf.l[FLD_TEXT] = v;
772 if (a == 'b')
773 newf.a[FLD_TEXT] = 'b';
774 /** newf.r[FLD_TEXT] ** not supported */
775 break;
776 default:
777 breakit=1;
778 break;
779 }
780 if (breakit)
781 break;
782 } /* for strtok.. */
783 if (breakit)
784 break;
785 /* parse 'per' */
786 p2++;
787 if (*p2 != ':')
788 break;
789 p2++;
790 if (!*p2)
791 break;
792 v = atoi(p2);
793 if ((v < 1) || (v > 999)) /* 'per' out of range */
794 break;
795 newf.per = v;
796 /* Is anything turned on? (to stop things like '+f []:15' */
797 breakit = 1;
798 for (v=0; v < NUMFLD; v++)
799 if (newf.l[v])
800 breakit=0;
801 if (breakit)
802 break;
803
804 /* w00t, we passed... */
805 memcpy(&store->floodprot, &newf, sizeof(newf));
806 store->mode |= MODE_FLOODLIMIT;
807 break;
808 }
809 #else
810 char *myparam = param;
811 char kmode = 0;
812 char *xp;
813 int msgs=0, per=0;
814 int hascolon = 0;
815 if (!myparam)
816 break;
817 /* Go to next parameter */
818 param = strtoken(&save, NULL, " ");
819
820 if (*myparam == '*')
821 kmode = 1;
822 for (xp = myparam; *xp; xp++)
823 {
824 if (*xp == ':')
825 {
826 hascolon++;
827 continue;
828 }
829 if (((*xp < '0') || (*xp > '9')) && *xp != '*')
830 break;
831 if (*xp == '*' && *myparam != '*')
832 break;
833 }
834 if (hascolon != 1)
835 break;
836 xp = strchr(myparam, ':');
837 *xp = 0;
838 msgs = atoi((*myparam == '*') ? (myparam+1) : myparam);
839 xp++;
840 per = atoi(xp);
841 xp--;
842 *xp = ':';
843 if (msgs == 0 || msgs > 500 || per == 0 || per > 500)
844 break;
845 store->msgs = msgs;
846 store->per = per;
847 store->kmode = kmode;
848 store->mode |= MODE_FLOODLIMIT;
849 #endif
850 break;
851 }
852 default:
853 for (tab = &cFlagTab[0]; tab->mode; tab++)
854 {
855 if (tab->flag == *modes)
856 {
857 if (tab->parameters)
858 {
859 /* INCOMPATIBLE */
860 break;
861 }
862 store->mode |= tab->mode;
863 break;
864 }
865 }
866 #ifdef EXTCMODE
867 /* Try extcmodes */
868 if (!tab->mode)
869 {
870 int i;
871 for (i=0; i <= Channelmode_highest; i++)
872 {
873 if (!(Channelmode_Table[i].flag))
874 continue;
875 if (*modes == Channelmode_Table[i].flag)
876 {
877 if (Channelmode_Table[i].paracount)
878 {
879 if (!param)
880 break;
881 param = Channelmode_Table[i].conv_param(param);
882 if (!param)
883 break; /* invalid parameter fmt, do not set mode. */
884 store->extparams[i] = strdup(param);
885 /* Get next parameter */
886 param = strtoken(&save, NULL, " ");
887 }
888 store->extmodes |= Channelmode_Table[i].mode;
889 break;
890 }
891 }
892 }
893 #endif
894 }
895 }
896 if (parambuf)
897 free(parambuf);
898 }
899
chmode_str(struct ChMode modes,char * mbuf,char * pbuf)900 void chmode_str(struct ChMode modes, char *mbuf, char *pbuf)
901 {
902 aCtab *tab;
903 int i;
904 *pbuf = 0;
905 *mbuf++ = '+';
906 for (tab = &cFlagTab[0]; tab->mode; tab++)
907 {
908 if (modes.mode & tab->mode)
909 {
910 if (!tab->parameters)
911 *mbuf++ = tab->flag;
912 }
913 }
914 #ifdef EXTCMODE
915 for (i=0; i <= Channelmode_highest; i++)
916 {
917 if (!(Channelmode_Table[i].flag))
918 continue;
919
920 if (modes.extmodes & Channelmode_Table[i].mode)
921 {
922 *mbuf++ = Channelmode_Table[i].flag;
923 if (Channelmode_Table[i].paracount)
924 {
925 strcat(pbuf, modes.extparams[i]);
926 strcat(pbuf, " ");
927 }
928 }
929 }
930 #endif
931 #ifdef NEWCHFLOODPROT
932 if (modes.floodprot.per)
933 {
934 *mbuf++ = 'f';
935 strcat(pbuf, channel_modef_string(&modes.floodprot));
936 }
937 #else
938 if (modes.per)
939 {
940 *mbuf++ = 'f';
941 if (modes.kmode)
942 strcat(pbuf, "*");
943 strcat(pbuf, my_itoa(modes.msgs));
944 strcat(pbuf, ":");
945 strcat(pbuf, my_itoa(modes.per));
946 }
947 #endif
948 *mbuf++=0;
949 }
950
channellevel_to_int(char * s)951 int channellevel_to_int(char *s)
952 {
953 /* Requested at http://bugs.unrealircd.org/view.php?id=3852 */
954 if (!strcmp(s, "none"))
955 return CHFL_DEOPPED;
956 if (!strcmp(s, "voice"))
957 return CHFL_VOICE;
958 if (!strcmp(s, "halfop"))
959 return CHFL_HALFOP;
960 if (!strcmp(s, "op") || !strcmp(s, "chanop"))
961 return CHFL_CHANOP;
962 if (!strcmp(s, "protect") || !strcmp(s, "chanprot"))
963 #ifdef PREFIX_AQ
964 return CHFL_CHANPROT;
965 #else
966 return CHFL_CHANOP|CHFL_CHANPROT;
967 #endif
968 if (!strcmp(s, "owner") || !strcmp(s, "chanowner"))
969 #ifdef PREFIX_AQ
970 return CHFL_CHANOWNER;
971 #else
972 return CHFL_CHANOP|CHFL_CHANOWNER;
973 #endif
974
975 return 0; /* unknown or unsupported */
976 }
977
978 /* Channel flag (eg: CHFL_CHANOWNER) to SJOIN symbol (eg: *).
979 * WARNING: Do not confuse SJOIN symbols with prefixes in /NAMES!
980 */
chfl_to_sjoin_symbol(int s)981 char *chfl_to_sjoin_symbol(int s)
982 {
983 switch(s)
984 {
985 case CHFL_VOICE:
986 return "+";
987 case CHFL_HALFOP:
988 return "%";
989 case CHFL_CHANOP:
990 return "@";
991 case CHFL_CHANPROT:
992 #ifdef PREFIX_AQ
993 return "~";
994 #else
995 return "~@";
996 #endif
997 case CHFL_CHANOWNER:
998 #ifdef PREFIX_AQ
999 return "*";
1000 #else
1001 return "*@";
1002 #endif
1003 case CHFL_DEOPPED:
1004 default:
1005 return "";
1006 }
1007 /* NOT REACHED */
1008 }
1009
chfl_to_chanmode(int s)1010 char chfl_to_chanmode(int s)
1011 {
1012 switch(s)
1013 {
1014 case CHFL_VOICE:
1015 return 'v';
1016 case CHFL_HALFOP:
1017 return 'h';
1018 case CHFL_CHANOP:
1019 return 'o';
1020 case CHFL_CHANPROT:
1021 return 'a';
1022 case CHFL_CHANOWNER:
1023 return 'q';
1024 case CHFL_DEOPPED:
1025 default:
1026 return '\0';
1027 }
1028 /* NOT REACHED */
1029 }
1030
config_load(char * filename)1031 ConfigFile *config_load(char *filename)
1032 {
1033 struct stat sb;
1034 int fd;
1035 int ret;
1036 char *buf = NULL;
1037 ConfigFile *cfptr;
1038
1039 #ifndef _WIN32
1040 fd = open(filename, O_RDONLY);
1041 #else
1042 fd = open(filename, O_RDONLY|O_BINARY);
1043 #endif
1044 if (fd == -1)
1045 {
1046 config_error("Couldn't open \"%s\": %s\n", filename, strerror(errno));
1047 return NULL;
1048 }
1049 if (fstat(fd, &sb) == -1)
1050 {
1051 config_error("Couldn't fstat \"%s\": %s\n", filename, strerror(errno));
1052 close(fd);
1053 return NULL;
1054 }
1055 if (!sb.st_size)
1056 {
1057 /* Workaround for empty files */
1058 cfptr = config_parse(filename, " ");
1059 return cfptr;
1060 }
1061 buf = MyMalloc(sb.st_size+1);
1062 if (buf == NULL)
1063 {
1064 config_error("Out of memory trying to load \"%s\"\n", filename);
1065 close(fd);
1066 return NULL;
1067 }
1068 ret = read(fd, buf, sb.st_size);
1069 if (ret != sb.st_size)
1070 {
1071 config_error("Error reading \"%s\": %s\n", filename,
1072 ret == -1 ? strerror(errno) : strerror(EFAULT));
1073 free(buf);
1074 close(fd);
1075 return NULL;
1076 }
1077 /* Just me or could this cause memory corrupted when ret <0 ? */
1078 buf[ret] = '\0';
1079 close(fd);
1080 add_entropy_configfile(sb, buf);
1081 cfptr = config_parse(filename, buf);
1082 free(buf);
1083 return cfptr;
1084 }
1085
config_free(ConfigFile * cfptr)1086 void config_free(ConfigFile *cfptr)
1087 {
1088 ConfigFile *nptr;
1089
1090 for(;cfptr;cfptr=nptr)
1091 {
1092 nptr = cfptr->cf_next;
1093 if (cfptr->cf_entries)
1094 config_entry_free(cfptr->cf_entries);
1095 if (cfptr->cf_filename)
1096 free(cfptr->cf_filename);
1097 free(cfptr);
1098 }
1099 }
1100
1101 /* This is the internal parser, made by Chris Behrens & Fred Jacobs */
config_parse(char * filename,char * confdata)1102 static ConfigFile *config_parse(char *filename, char *confdata)
1103 {
1104 char *ptr;
1105 char *start;
1106 int linenumber = 1;
1107 ConfigEntry *curce;
1108 ConfigEntry **lastce;
1109 ConfigEntry *cursection;
1110
1111 ConfigFile *curcf;
1112 ConfigFile *lastcf;
1113
1114 lastcf = curcf = MyMalloc(sizeof(ConfigFile));
1115 memset(curcf, 0, sizeof(ConfigFile));
1116 curcf->cf_filename = strdup(filename);
1117 lastce = &(curcf->cf_entries);
1118 curce = NULL;
1119 cursection = NULL;
1120 /* Replace \r's with spaces .. ugly ugly -Stskeeps */
1121 for (ptr=confdata; *ptr; ptr++)
1122 if (*ptr == '\r')
1123 *ptr = ' ';
1124
1125 for(ptr=confdata;*ptr;ptr++)
1126 {
1127 switch(*ptr)
1128 {
1129 case ';':
1130 if (!curce)
1131 {
1132 config_status("%s:%i Ignoring extra semicolon\n",
1133 filename, linenumber);
1134 break;
1135 }
1136 *lastce = curce;
1137 lastce = &(curce->ce_next);
1138 curce->ce_fileposend = (ptr - confdata);
1139 curce = NULL;
1140 break;
1141 case '{':
1142 if (!curce)
1143 {
1144 config_status("%s:%i: No name for section start\n",
1145 filename, linenumber);
1146 continue;
1147 }
1148 else if (curce->ce_entries)
1149 {
1150 config_status("%s:%i: Ignoring extra section start\n",
1151 filename, linenumber);
1152 continue;
1153 }
1154 curce->ce_sectlinenum = linenumber;
1155 lastce = &(curce->ce_entries);
1156 cursection = curce;
1157 curce = NULL;
1158 break;
1159 case '}':
1160 if (curce)
1161 {
1162 config_error("%s:%i: Missing semicolon before close brace\n",
1163 filename, linenumber);
1164 config_entry_free(curce);
1165 config_free(curcf);
1166
1167 return NULL;
1168 }
1169 else if (!cursection)
1170 {
1171 config_status("%s:%i: Ignoring extra close brace\n",
1172 filename, linenumber);
1173 continue;
1174 }
1175 curce = cursection;
1176 cursection->ce_fileposend = (ptr - confdata);
1177 cursection = cursection->ce_prevlevel;
1178 if (!cursection)
1179 lastce = &(curcf->cf_entries);
1180 else
1181 lastce = &(cursection->ce_entries);
1182 for(;*lastce;lastce = &((*lastce)->ce_next))
1183 continue;
1184 break;
1185 case '#':
1186 ptr++;
1187 while(*ptr && (*ptr != '\n'))
1188 ptr++;
1189 if (!*ptr)
1190 break;
1191 ptr--;
1192 continue;
1193 case '/':
1194 if (*(ptr+1) == '/')
1195 {
1196 ptr += 2;
1197 while(*ptr && (*ptr != '\n'))
1198 ptr++;
1199 if (!*ptr)
1200 break;
1201 ptr--; /* grab the \n on next loop thru */
1202 continue;
1203 }
1204 else if (*(ptr+1) == '*')
1205 {
1206 int commentstart = linenumber;
1207 int commentlevel = 1;
1208
1209 for(ptr+=2;*ptr;ptr++)
1210 {
1211 if ((*ptr == '/') && (*(ptr+1) == '*'))
1212 {
1213 commentlevel++;
1214 ptr++;
1215 }
1216
1217 else if ((*ptr == '*') && (*(ptr+1) == '/'))
1218 {
1219 commentlevel--;
1220 ptr++;
1221 }
1222
1223 else if (*ptr == '\n')
1224 linenumber++;
1225
1226 if (!commentlevel)
1227 break;
1228 }
1229 if (!*ptr)
1230 {
1231 config_error("%s:%i Comment on this line does not end\n",
1232 filename, commentstart);
1233 config_entry_free(curce);
1234 config_free(curcf);
1235 return NULL;
1236 }
1237 }
1238 break;
1239 case '\"':
1240 if (curce && curce->ce_varlinenum != linenumber && cursection)
1241 {
1242 config_warn("%s:%i: Missing semicolon at end of line\n",
1243 filename, curce->ce_varlinenum);
1244
1245 *lastce = curce;
1246 lastce = &(curce->ce_next);
1247 curce->ce_fileposend = (ptr - confdata);
1248 curce = NULL;
1249 }
1250
1251 start = ++ptr;
1252 for(;*ptr;ptr++)
1253 {
1254 if ((*ptr == '\\'))
1255 {
1256
1257 if (*(ptr+1) == '\\' || *(ptr+1) == '\"')
1258 {
1259 char *tptr = ptr;
1260 while((*tptr = *(tptr+1)))
1261 tptr++;
1262 }
1263 }
1264 else if ((*ptr == '\"') || (*ptr == '\n'))
1265 break;
1266 }
1267 if (!*ptr || (*ptr == '\n'))
1268 {
1269 config_error("%s:%i: Unterminated quote found\n",
1270 filename, linenumber);
1271 config_entry_free(curce);
1272 config_free(curcf);
1273 return NULL;
1274 }
1275 if (curce)
1276 {
1277 if (curce->ce_vardata)
1278 {
1279 config_status("%s:%i: Ignoring extra data\n",
1280 filename, linenumber);
1281 }
1282 else
1283 {
1284 curce->ce_vardata = MyMalloc(ptr-start+1);
1285 strncpy(curce->ce_vardata, start, ptr-start);
1286 curce->ce_vardata[ptr-start] = '\0';
1287 }
1288 }
1289 else
1290 {
1291 curce = MyMalloc(sizeof(ConfigEntry));
1292 memset(curce, 0, sizeof(ConfigEntry));
1293 curce->ce_varname = MyMalloc((ptr-start)+1);
1294 strncpy(curce->ce_varname, start, ptr-start);
1295 curce->ce_varname[ptr-start] = '\0';
1296 curce->ce_varlinenum = linenumber;
1297 curce->ce_fileptr = curcf;
1298 curce->ce_prevlevel = cursection;
1299 curce->ce_fileposstart = (start - confdata);
1300 }
1301 break;
1302 case '\n':
1303 linenumber++;
1304 /* fall through */
1305 case '\t':
1306 case ' ':
1307 case '=':
1308 case '\r':
1309 break;
1310 default:
1311 if ((*ptr == '*') && (*(ptr+1) == '/'))
1312 {
1313 config_status("%s:%i Ignoring extra end comment\n",
1314 filename, linenumber);
1315 ptr++;
1316 break;
1317 }
1318 start = ptr;
1319 for(;*ptr;ptr++)
1320 {
1321 if ((*ptr == ' ') || (*ptr == '=') || (*ptr == '\t') || (*ptr == '\n') || (*ptr == ';'))
1322 break;
1323 }
1324 if (!*ptr)
1325 {
1326 if (curce)
1327 config_error("%s: Unexpected EOF for variable starting at %i\n",
1328 filename, curce->ce_varlinenum);
1329 else if (cursection)
1330 config_error("%s: Unexpected EOF for section starting at %i\n",
1331 filename, cursection->ce_sectlinenum);
1332 else
1333 config_error("%s: Unexpected EOF.\n", filename);
1334 config_entry_free(curce);
1335 config_free(curcf);
1336 return NULL;
1337 }
1338 if (curce)
1339 {
1340 if (curce->ce_vardata)
1341 {
1342 config_status("%s:%i: Ignoring extra data\n",
1343 filename, linenumber);
1344 }
1345 else
1346 {
1347 curce->ce_vardata = MyMalloc(ptr-start+1);
1348 strncpy(curce->ce_vardata, start, ptr-start);
1349 curce->ce_vardata[ptr-start] = '\0';
1350 }
1351 }
1352 else
1353 {
1354 curce = MyMalloc(sizeof(ConfigEntry));
1355 memset(curce, 0, sizeof(ConfigEntry));
1356 curce->ce_varname = MyMalloc((ptr-start)+1);
1357 strncpy(curce->ce_varname, start, ptr-start);
1358 curce->ce_varname[ptr-start] = '\0';
1359 curce->ce_varlinenum = linenumber;
1360 curce->ce_fileptr = curcf;
1361 curce->ce_prevlevel = cursection;
1362 curce->ce_fileposstart = (start - confdata);
1363 }
1364 if ((*ptr == ';') || (*ptr == '\n'))
1365 ptr--;
1366 break;
1367 } /* switch */
1368 if (!*ptr) /* This IS possible. -- Syzop */
1369 break;
1370 } /* for */
1371 if (curce)
1372 {
1373 config_error("%s: Unexpected EOF for variable starting on line %i\n",
1374 filename, curce->ce_varlinenum);
1375 config_entry_free(curce);
1376 config_free(curcf);
1377 return NULL;
1378 }
1379 else if (cursection)
1380 {
1381 config_error("%s: Unexpected EOF for section starting on line %i\n",
1382 filename, cursection->ce_sectlinenum);
1383 config_free(curcf);
1384 return NULL;
1385 }
1386 return curcf;
1387 }
1388
config_entry_free(ConfigEntry * ceptr)1389 static void config_entry_free(ConfigEntry *ceptr)
1390 {
1391 ConfigEntry *nptr;
1392
1393 for(;ceptr;ceptr=nptr)
1394 {
1395 nptr = ceptr->ce_next;
1396 if (ceptr->ce_entries)
1397 config_entry_free(ceptr->ce_entries);
1398 if (ceptr->ce_varname)
1399 free(ceptr->ce_varname);
1400 if (ceptr->ce_vardata)
1401 free(ceptr->ce_vardata);
1402 free(ceptr);
1403 }
1404 }
1405
config_find_entry(ConfigEntry * ce,char * name)1406 ConfigEntry *config_find_entry(ConfigEntry *ce, char *name)
1407 {
1408 ConfigEntry *cep;
1409
1410 for (cep = ce; cep; cep = cep->ce_next)
1411 if (cep->ce_varname && !strcmp(cep->ce_varname, name))
1412 break;
1413 return cep;
1414 }
1415
config_error(char * format,...)1416 void config_error(char *format, ...)
1417 {
1418 va_list ap;
1419 char buffer[1024];
1420 char *ptr;
1421
1422 va_start(ap, format);
1423 vsprintf(buffer, format, ap);
1424 va_end(ap);
1425 if ((ptr = strchr(buffer, '\n')) != NULL)
1426 *ptr = '\0';
1427 if (!loop.ircd_booted)
1428 #ifndef _WIN32
1429 fprintf(stderr, "[error] %s\n", buffer);
1430 #else
1431 win_log("[error] %s", buffer);
1432 #endif
1433 else
1434 ircd_log(LOG_ERROR, "config error: %s", buffer);
1435 sendto_realops("error: %s", buffer);
1436 /* We cannot live with this */
1437 config_error_flag = 1;
1438 }
1439
config_error_missing(const char * filename,int line,const char * entry)1440 static void inline config_error_missing(const char *filename, int line, const char *entry)
1441 {
1442 config_error("%s:%d: %s is missing", filename, line, entry);
1443 }
1444
config_error_unknown(const char * filename,int line,const char * block,const char * entry)1445 static void inline config_error_unknown(const char *filename, int line, const char *block,
1446 const char *entry)
1447 {
1448 config_error("%s:%d: Unknown directive '%s::%s'", filename, line, block, entry);
1449 }
1450
config_error_unknownflag(const char * filename,int line,const char * block,const char * entry)1451 static void inline config_error_unknownflag(const char *filename, int line, const char *block,
1452 const char *entry)
1453 {
1454 config_error("%s:%d: Unknown %s flag '%s'", filename, line, block, entry);
1455 }
1456
config_error_unknownopt(const char * filename,int line,const char * block,const char * entry)1457 static void inline config_error_unknownopt(const char *filename, int line, const char *block,
1458 const char *entry)
1459 {
1460 config_error("%s:%d: Unknown %s option '%s'", filename, line, block, entry);
1461 }
1462
config_error_noname(const char * filename,int line,const char * block)1463 static void inline config_error_noname(const char *filename, int line, const char *block)
1464 {
1465 config_error("%s:%d: %s block has no name", filename, line, block);
1466 }
1467
config_error_blank(const char * filename,int line,const char * block)1468 static void inline config_error_blank(const char *filename, int line, const char *block)
1469 {
1470 config_error("%s:%d: Blank %s entry", filename, line, block);
1471 }
1472
config_error_empty(const char * filename,int line,const char * block,const char * entry)1473 static void inline config_error_empty(const char *filename, int line, const char *block,
1474 const char *entry)
1475 {
1476 config_error("%s:%d: %s::%s specified without a value",
1477 filename, line, block, entry);
1478 }
1479
1480 /* Like above */
config_status(char * format,...)1481 void config_status(char *format, ...)
1482 {
1483 va_list ap;
1484 char buffer[1024];
1485 char *ptr;
1486
1487 va_start(ap, format);
1488 vsnprintf(buffer, 1023, format, ap);
1489 va_end(ap);
1490 if ((ptr = strchr(buffer, '\n')) != NULL)
1491 *ptr = '\0';
1492 if (!loop.ircd_booted)
1493 #ifndef _WIN32
1494 fprintf(stderr, "* %s\n", buffer);
1495 #else
1496 win_log("* %s", buffer);
1497 #endif
1498 sendto_realops("%s", buffer);
1499 }
1500
config_warn(char * format,...)1501 void config_warn(char *format, ...)
1502 {
1503 va_list ap;
1504 char buffer[1024];
1505 char *ptr;
1506
1507 va_start(ap, format);
1508 vsnprintf(buffer, 1023, format, ap);
1509 va_end(ap);
1510 if ((ptr = strchr(buffer, '\n')) != NULL)
1511 *ptr = '\0';
1512 if (!loop.ircd_booted)
1513 #ifndef _WIN32
1514 fprintf(stderr, "[warning] %s\n", buffer);
1515 #else
1516 win_log("[warning] %s", buffer);
1517 #endif
1518 sendto_realops("[warning] %s", buffer);
1519 }
1520
config_warn_duplicate(const char * filename,int line,const char * entry)1521 static void inline config_warn_duplicate(const char *filename, int line, const char *entry)
1522 {
1523 config_warn("%s:%d: Duplicate %s directive", filename, line, entry);
1524 }
1525
1526 /* returns 1 if the test fails */
config_test_openfile(ConfigEntry * cep,int flags,mode_t mode,const char * entry,int fatal,int allow_url)1527 int config_test_openfile(ConfigEntry *cep, int flags, mode_t mode, const char *entry, int fatal, int allow_url)
1528 {
1529 int fd;
1530
1531 if(!cep->ce_vardata)
1532 {
1533 if(fatal)
1534 config_error("%s:%i: %s: <no file specified>: no file specified",
1535 cep->ce_fileptr->cf_filename,
1536 cep->ce_varlinenum,
1537 entry);
1538 else
1539
1540 config_warn("%s:%i: %s: <no file specified>: no file specified",
1541 cep->ce_fileptr->cf_filename,
1542 cep->ce_varlinenum,
1543 entry);
1544 return 1;
1545 }
1546
1547 /* There's not much checking that can be done for asynchronously downloaded files */
1548 #ifdef USE_LIBCURL
1549 if(url_is_valid(cep->ce_vardata))
1550 {
1551 if(allow_url)
1552 return 0;
1553
1554 /* but we can check if a URL is used wrongly :-) */
1555 config_warn("%s:%i: %s: %s: URL used where not allowed",
1556 cep->ce_fileptr->cf_filename,
1557 cep->ce_varlinenum,
1558 entry, cep->ce_vardata);
1559 if(fatal)
1560 return 1;
1561 else
1562 return 0;
1563 }
1564 #endif /* USE_LIBCURL */
1565
1566 /*
1567 * Make sure that files are created with the correct mode. This is
1568 * because we don't feel like unlink()ing them...which would require
1569 * stat()ing them to make sure that we don't delete existing ones
1570 * and that we deal with all of the bugs that come with complexity.
1571 * The only files we may be creating are the tunefile and pidfile so far.
1572 */
1573 if(flags & O_CREAT)
1574 fd = open(cep->ce_vardata, flags, mode);
1575 else
1576 fd = open(cep->ce_vardata, flags);
1577 if(fd == -1)
1578 {
1579 if(fatal)
1580 config_error("%s:%i: %s: %s: %s",
1581 cep->ce_fileptr->cf_filename,
1582 cep->ce_varlinenum,
1583 entry,
1584 cep->ce_vardata,
1585 strerror(errno));
1586 else
1587 config_warn("%s:%i: %s: %s: %s",
1588 cep->ce_fileptr->cf_filename,
1589 cep->ce_varlinenum,
1590 entry,
1591 cep->ce_vardata,
1592 strerror(errno));
1593 return 1;
1594 }
1595 close(fd);
1596 return 0;
1597 }
1598
config_progress(char * format,...)1599 void config_progress(char *format, ...)
1600 {
1601 va_list ap;
1602 char buffer[1024];
1603 char *ptr;
1604
1605 va_start(ap, format);
1606 vsnprintf(buffer, 1023, format, ap);
1607 va_end(ap);
1608 if ((ptr = strchr(buffer, '\n')) != NULL)
1609 *ptr = '\0';
1610 if (!loop.ircd_booted)
1611 #ifndef _WIN32
1612 fprintf(stderr, "* %s\n", buffer);
1613 #else
1614 win_log("* %s", buffer);
1615 #endif
1616 sendto_realops("%s", buffer);
1617 }
1618
config_is_blankorempty(ConfigEntry * cep,const char * block)1619 static int inline config_is_blankorempty(ConfigEntry *cep, const char *block)
1620 {
1621 if (!cep->ce_varname)
1622 {
1623 config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum, block);
1624 return 1;
1625 }
1626 if (!cep->ce_vardata)
1627 {
1628 config_error_empty(cep->ce_fileptr->cf_filename, cep->ce_varlinenum, block,
1629 cep->ce_varname);
1630 return 1;
1631 }
1632 return 0;
1633 }
1634
config_binary_search(char * cmd)1635 ConfigCommand *config_binary_search(char *cmd) {
1636 int start = 0;
1637 int stop = ARRAY_SIZEOF(_ConfigCommands)-1;
1638 int mid;
1639 while (start <= stop) {
1640 mid = (start+stop)/2;
1641 if (smycmp(cmd,_ConfigCommands[mid].name) < 0) {
1642 stop = mid-1;
1643 }
1644 else if (strcmp(cmd,_ConfigCommands[mid].name) == 0) {
1645 return &_ConfigCommands[mid];
1646 }
1647 else
1648 start = mid+1;
1649 }
1650 return NULL;
1651 }
1652
free_iConf(aConfiguration * i)1653 void free_iConf(aConfiguration *i)
1654 {
1655 ircfree(i->name_server);
1656 ircfree(i->kline_address);
1657 ircfree(i->gline_address);
1658 ircfree(i->auto_join_chans);
1659 ircfree(i->oper_auto_join_chans);
1660 ircfree(i->oper_only_stats);
1661 ircfree(i->channel_command_prefix);
1662 ircfree(i->oper_snomask);
1663 ircfree(i->user_snomask);
1664 ircfree(i->egd_path);
1665 ircfree(i->static_quit);
1666 #ifdef USE_SSL
1667 ircfree(i->x_server_cert_pem);
1668 ircfree(i->x_server_key_pem);
1669 ircfree(i->x_server_cipher_list);
1670 ircfree(i->trusted_ca_file);
1671 #endif
1672 ircfree(i->restrict_usermodes);
1673 ircfree(i->restrict_channelmodes);
1674 ircfree(i->restrict_extendedbans);
1675 ircfree(i->network.x_ircnetwork);
1676 ircfree(i->network.x_ircnet005);
1677 ircfree(i->network.x_defserv);
1678 ircfree(i->network.x_services_name);
1679 ircfree(i->network.x_oper_host);
1680 ircfree(i->network.x_admin_host);
1681 ircfree(i->network.x_locop_host);
1682 ircfree(i->network.x_sadmin_host);
1683 ircfree(i->network.x_netadmin_host);
1684 ircfree(i->network.x_coadmin_host);
1685 ircfree(i->network.x_hidden_host);
1686 ircfree(i->network.x_prefix_quit);
1687 ircfree(i->network.x_helpchan);
1688 ircfree(i->network.x_stats_server);
1689 ircfree(i->spamfilter_ban_reason);
1690 ircfree(i->spamfilter_virus_help_channel);
1691 ircfree(i->spamexcept_line);
1692 }
1693
1694 int config_test();
1695
config_setdefaultsettings(aConfiguration * i)1696 void config_setdefaultsettings(aConfiguration *i)
1697 {
1698 i->unknown_flood_amount = 4;
1699 i->unknown_flood_bantime = 600;
1700 i->oper_snomask = strdup(SNO_DEFOPER);
1701 i->ident_read_timeout = 30;
1702 i->ident_connect_timeout = 10;
1703 i->nick_count = 3; i->nick_period = 60; /* nickflood protection: max 3 per 60s */
1704 #ifdef NO_FLOOD_AWAY
1705 i->away_count = 4; i->away_period = 120; /* awayflood protection: max 4 per 120s */
1706 #endif
1707 #ifdef NEWCHFLOODPROT
1708 i->modef_default_unsettime = 0;
1709 i->modef_max_unsettime = 60; /* 1 hour seems enough :p */
1710 #endif
1711 i->ban_version_tkl_time = 86400; /* 1d */
1712 i->spamfilter_ban_time = 86400; /* 1d */
1713 i->spamfilter_ban_reason = strdup("Spam/advertising");
1714 i->spamfilter_virus_help_channel = strdup("#help");
1715 i->spamfilter_detectslow_warn = 250;
1716 i->spamfilter_detectslow_fatal = 500;
1717 i->spamfilter_stop_on_first_match = 1;
1718 i->maxdccallow = 10;
1719 i->channel_command_prefix = strdup("`!.");
1720 i->check_target_nick_bans = 1;
1721 i->maxbans = 60;
1722 i->maxbanlength = 2048;
1723 i->timesynch_enabled = 1;
1724 i->timesynch_timeout = 3;
1725 i->timesynch_server = strdup("193.67.79.202,192.43.244.18,128.250.36.3"); /* nlnet (EU), NIST (US), uni melbourne (AU). All open acces, nonotify, nodns. */
1726 i->name_server = strdup("127.0.0.1"); /* default, especially needed for w2003+ in some rare cases */
1727 i->level_on_join = CHFL_CHANOP;
1728 i->watch_away_notification = 1;
1729 i->new_linking_protocol = 1;
1730 i->uhnames = 1;
1731 i->ping_cookie = 1;
1732 #ifdef INET6
1733 i->default_ipv6_clone_mask = 64;
1734 #endif /* INET6 */
1735 }
1736
1737 /* 1: needed for set::options::allow-part-if-shunned,
1738 * we can't just make it M_SHUN and do a ALLOW_PART_IF_SHUNNED in
1739 * m_part itself because that will also block internal calls (like sapart). -- Syzop
1740 * 2: now also used by spamfilter entries added by config...
1741 * we got a chicken-and-egg problem here.. antries added without reason or ban-time
1742 * field should use the config default (set::spamfilter::ban-reason/ban-time) but
1743 * this isn't (or might not) be known yet when parsing spamfilter entries..
1744 * so we do a VERY UGLY mass replace here.. unless someone else has a better idea.
1745 */
do_weird_shun_stuff()1746 static void do_weird_shun_stuff()
1747 {
1748 aCommand *cmptr;
1749 aTKline *tk;
1750 char *encoded;
1751
1752 if ((cmptr = find_Command_simple("PART")))
1753 {
1754 if (ALLOW_PART_IF_SHUNNED)
1755 cmptr->flags |= M_SHUN;
1756 else
1757 cmptr->flags &= ~M_SHUN;
1758 }
1759
1760 encoded = unreal_encodespace(SPAMFILTER_BAN_REASON);
1761 if (!encoded)
1762 abort(); /* hack to trace 'impossible' bug... */
1763 for (tk = tklines[tkl_hash('q')]; tk; tk = tk->next)
1764 {
1765 if (tk->type != TKL_NICK)
1766 continue;
1767 if (!tk->setby)
1768 {
1769 if (me.name[0] != '\0')
1770 tk->setby = strdup(me.name);
1771 else
1772 tk->setby = strdup(conf_me->name ? conf_me->name : "~server~");
1773 }
1774 }
1775
1776 for (tk = tklines[tkl_hash('f')]; tk; tk = tk->next)
1777 {
1778 if (tk->type != TKL_SPAMF)
1779 continue; /* global entry or something else.. */
1780 if (!strcmp(tk->ptr.spamf->tkl_reason, "<internally added by ircd>"))
1781 {
1782 MyFree(tk->ptr.spamf->tkl_reason);
1783 tk->ptr.spamf->tkl_reason = strdup(encoded);
1784 tk->ptr.spamf->tkl_duration = SPAMFILTER_BAN_TIME;
1785 }
1786 /* This one is even more ugly, but our config crap is VERY confusing :[ */
1787 if (!tk->setby)
1788 {
1789 if (me.name[0] != '\0')
1790 tk->setby = strdup(me.name);
1791 else
1792 tk->setby = strdup(conf_me->name ? conf_me->name : "~server~");
1793 }
1794 }
1795 if (loop.ircd_booted) /* only has to be done for rehashes, api-isupport takes care of boot */
1796 {
1797 if (WATCH_AWAY_NOTIFICATION)
1798 {
1799 IsupportAdd(NULL, "WATCHOPTS", "A");
1800 } else {
1801 Isupport *hunted = IsupportFind("WATCHOPTS");
1802 if (hunted)
1803 IsupportDel(hunted);
1804 }
1805 if (UHNAMES_ENABLED)
1806 {
1807 IsupportAdd(NULL, "UHNAMES", NULL);
1808 } else {
1809 Isupport *hunted = IsupportFind("UHNAMES");
1810 if (hunted)
1811 IsupportDel(hunted);
1812 }
1813 }
1814 }
1815
make_default_logblock(void)1816 static void make_default_logblock(void)
1817 {
1818 ConfigItem_log *ca = MyMallocEx(sizeof(ConfigItem_log));
1819
1820 config_status("No log { } block found -- using default: errors will be logged to 'ircd.log'");
1821
1822 ca->file = strdup("ircd.log");
1823 ca->flags |= LOG_ERROR;
1824 AddListItem(ca, conf_log);
1825 }
1826
isanyserverlinked(void)1827 int isanyserverlinked(void)
1828 {
1829 int i;
1830 aClient *acptr;
1831
1832 for (i = LastSlot; i >= 0; i--)
1833 if ((acptr = local[i]) && (acptr != &me) && IsServer(acptr))
1834 return 1;
1835
1836 return 0;
1837 }
1838
applymeblock(void)1839 void applymeblock(void)
1840 {
1841 if (!conf_me || !me.serv)
1842 return; /* uh-huh? */
1843
1844 /* Numeric change? */
1845 if (conf_me->numeric != me.serv->numeric)
1846 {
1847 /* Can we apply ? */
1848 if (!isanyserverlinked())
1849 {
1850 me.serv->numeric = conf_me->numeric;
1851 } else {
1852 config_warn("me::numeric: Numeric change detected, but change cannot be applied "
1853 "due to being linked to other servers. Unlink all servers and /REHASH to "
1854 "try again.");
1855 }
1856 }
1857 }
1858
init_conf(char * rootconf,int rehash)1859 int init_conf(char *rootconf, int rehash)
1860 {
1861 char *old_pid_file = NULL;
1862
1863 config_status("Loading IRCd configuration ..");
1864 if (conf)
1865 {
1866 config_error("%s:%i - Someone forgot to clean up", __FILE__, __LINE__);
1867 return -1;
1868 }
1869 bzero(&tempiConf, sizeof(iConf));
1870 bzero(&settings, sizeof(settings));
1871 bzero(&requiredstuff, sizeof(requiredstuff));
1872 config_setdefaultsettings(&tempiConf);
1873 /*
1874 * the rootconf must be listed in the conf_include for include
1875 * recursion prevention code and sanity checking code to be
1876 * made happy :-). Think of it as us implicitly making an
1877 * in-memory config file that looks like:
1878 *
1879 * include "unrealircd.conf";
1880 */
1881 add_include(rootconf, "[thin air]", -1);
1882 if (load_conf(rootconf, rootconf) > 0)
1883 {
1884 charsys_reset_pretest();
1885 if ((config_test() < 0) || (callbacks_check() < 0) || (efunctions_check() < 0) ||
1886 (charsys_postconftest() < 0))
1887 {
1888 config_error("IRCd configuration failed to pass testing");
1889 #ifdef _WIN32
1890 if (!rehash)
1891 win_error();
1892 #endif
1893 #ifndef STATIC_LINKING
1894 Unload_all_testing_modules();
1895 #endif
1896 unload_notloaded_includes();
1897 config_free(conf);
1898 conf = NULL;
1899 free_iConf(&tempiConf);
1900 return -1;
1901 }
1902 callbacks_switchover();
1903 efunctions_switchover();
1904 if (rehash)
1905 {
1906 Hook *h;
1907 old_pid_file = conf_files->pid_file;
1908 unrealdns_delasyncconnects();
1909 config_rehash();
1910 #ifndef STATIC_LINKING
1911 Unload_all_loaded_modules();
1912
1913 /* Notify permanent modules of the rehash */
1914 for (h = Hooks[HOOKTYPE_REHASH]; h; h = h->next)
1915 {
1916 if (!h->owner)
1917 continue;
1918 if (!(h->owner->options & MOD_OPT_PERM))
1919 continue;
1920 (*(h->func.intfunc))();
1921 }
1922 #else
1923 RunHook0(HOOKTYPE_REHASH);
1924 #endif
1925 unload_loaded_includes();
1926 }
1927 load_includes();
1928 #ifndef STATIC_LINKING
1929 Init_all_testing_modules();
1930 #else
1931 if (!rehash) {
1932 ModuleInfo ModCoreInfo;
1933 ModCoreInfo.size = sizeof(ModuleInfo);
1934 ModCoreInfo.module_load = 0;
1935 ModCoreInfo.handle = NULL;
1936 l_commands_Init(&ModCoreInfo);
1937 }
1938 #endif
1939 charsys_reset();
1940 if (config_run() < 0)
1941 {
1942 config_error("Bad case of config errors. Server will now die. This really shouldn't happen");
1943 #ifdef _WIN32
1944 if (!rehash)
1945 win_error();
1946 #endif
1947 abort();
1948 }
1949 charsys_finish();
1950 applymeblock();
1951 if(old_pid_file &&
1952 strcmp(old_pid_file, conf_files->pid_file))
1953 {
1954 sendto_ops("pidfile is being rewritten to %s, please delete %s",
1955 conf_files->pid_file,
1956 old_pid_file);
1957 ircfree(old_pid_file);
1958
1959 write_pidfile();
1960 }
1961 }
1962 else
1963 {
1964 config_error("IRCd configuration failed to load");
1965 #ifndef STATIC_LINKING
1966 Unload_all_testing_modules();
1967 #endif
1968 unload_notloaded_includes();
1969 config_free(conf);
1970 conf = NULL;
1971 free_iConf(&tempiConf);
1972 #ifdef _WIN32
1973 if (!rehash)
1974 win_error();
1975 #endif
1976 return -1;
1977 }
1978 config_free(conf);
1979 conf = NULL;
1980 if (rehash)
1981 {
1982 #ifndef STATIC_LINKING
1983 module_loadall(0);
1984 #endif
1985 RunHook0(HOOKTYPE_REHASH_COMPLETE);
1986 }
1987 do_weird_shun_stuff();
1988 if (!conf_log)
1989 make_default_logblock();
1990 nextconnect = TStime() + 1; /* check for autoconnects */
1991 config_status("Configuration loaded without any problems ..");
1992 return 0;
1993 }
1994
1995 /**
1996 * Processes filename as part of the IRCd's configuration.
1997 *
1998 * One _must_ call add_include() or add_remote_include() before
1999 * calling load_conf(). This way, include recursion may be detected
2000 * and reported to the user as an error instead of causing the IRCd to
2001 * hang in an infinite recursion, eat up memory, and eventually
2002 * overflow its stack ;-). (reported by warg).
2003 *
2004 * This function will set INCLUDE_USED on the config_include list
2005 * entry if the config file loaded without error.
2006 *
2007 * @param filename the file where the conf may be read from
2008 * @param original_path the path or URL used to refer to this file.
2009 * (mostly to support remote includes' URIs for recursive include detection).
2010 * @return 1 on success, a negative number on error
2011 */
load_conf(char * filename,const char * original_path)2012 int load_conf(char *filename, const char *original_path)
2013 {
2014 ConfigFile *cfptr, *cfptr2, **cfptr3;
2015 ConfigEntry *ce;
2016 ConfigItem_include *inc, *my_inc;
2017 int ret;
2018 int counter;
2019
2020 if (config_verbose > 0)
2021 config_status("Loading config file %s ..", filename);
2022
2023 /*
2024 * Check if we're accidentally including a file a second
2025 * time. We should expect to find one entry in this list: the
2026 * entry for our current file.
2027 */
2028 counter = 0;
2029 my_inc = NULL;
2030 for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
2031 {
2032 /*
2033 * ignore files which were part of a _previous_
2034 * successful rehash.
2035 */
2036 if (!(inc->flag.type & INCLUDE_NOTLOADED))
2037 continue;
2038
2039 if (!counter)
2040 my_inc = inc;
2041
2042 if (!strcmp(filename, inc->file))
2043 {
2044 counter ++;
2045 continue;
2046 }
2047 #ifdef _WIN32
2048 if (!stricmp(filename, inc->file))
2049 {
2050 counter ++;
2051 continue;
2052 }
2053 #endif
2054 #ifdef USE_LIBCURL
2055 if (inc->url && !strcmp(original_path, inc->url))
2056 {
2057 counter ++;
2058 continue;
2059 }
2060 #endif
2061 }
2062 if (counter > 1 || my_inc->flag.type & INCLUDE_USED)
2063 {
2064 config_error("%s:%d:include: Config file %s has been loaded before %d time."
2065 " You may include each file only once.",
2066 my_inc->included_from, my_inc->included_from_line,
2067 filename, counter - 1);
2068 return -1;
2069 }
2070 if (counter < 1 || !my_inc)
2071 {
2072 /*
2073 * The following is simply for debugging/[sanity
2074 * checking]. To make sure that functions call
2075 * add_include() or add_remote_include() before
2076 * calling us.
2077 */
2078 config_error("I don't have a record for %s being included."
2079 " Perhaps someone forgot to call add_include()?",
2080 filename);
2081 }
2082 /* end include recursion checking code */
2083
2084 if ((cfptr = config_load(filename)))
2085 {
2086 for (cfptr3 = &conf, cfptr2 = conf; cfptr2; cfptr2 = cfptr2->cf_next)
2087 cfptr3 = &cfptr2->cf_next;
2088 *cfptr3 = cfptr;
2089 if (config_verbose > 1)
2090 config_status("Loading modules in %s", filename);
2091 for (ce = cfptr->cf_entries; ce; ce = ce->ce_next)
2092 if (!strcmp(ce->ce_varname, "loadmodule"))
2093 {
2094 ret = _conf_loadmodule(cfptr, ce);
2095 if (ret < 0)
2096 return ret;
2097 }
2098 if (config_verbose > 1)
2099 config_status("Searching through %s for include files..", filename);
2100 for (ce = cfptr->cf_entries; ce; ce = ce->ce_next)
2101 if (!strcmp(ce->ce_varname, "include"))
2102 {
2103 ret = _conf_include(cfptr, ce);
2104 if (ret < 0)
2105 return ret;
2106 }
2107 my_inc->flag.type |= INCLUDE_USED;
2108 return 1;
2109 }
2110 else
2111 {
2112 config_error("Could not load config file %s", filename);
2113 return -1;
2114 }
2115 }
2116
config_rehash()2117 void config_rehash()
2118 {
2119 ConfigItem_oper *oper_ptr;
2120 ConfigItem_class *class_ptr;
2121 ConfigItem_ulines *uline_ptr;
2122 ConfigItem_allow *allow_ptr;
2123 ConfigItem_except *except_ptr;
2124 ConfigItem_ban *ban_ptr;
2125 ConfigItem_link *link_ptr;
2126 ConfigItem_cgiirc *cgiirc_ptr;
2127 ConfigItem_listen *listen_ptr;
2128 ConfigItem_tld *tld_ptr;
2129 ConfigItem_vhost *vhost_ptr;
2130 ConfigItem_badword *badword_ptr;
2131 ConfigItem_deny_dcc *deny_dcc_ptr;
2132 ConfigItem_allow_dcc *allow_dcc_ptr;
2133 ConfigItem_deny_link *deny_link_ptr;
2134 ConfigItem_deny_channel *deny_channel_ptr;
2135 ConfigItem_allow_channel *allow_channel_ptr;
2136 ConfigItem_admin *admin_ptr;
2137 ConfigItem_deny_version *deny_version_ptr;
2138 ConfigItem_log *log_ptr;
2139 ConfigItem_alias *alias_ptr;
2140 ConfigItem_help *help_ptr;
2141 ConfigItem_offchans *of_ptr;
2142 OperStat *os_ptr;
2143 ListStruct *next, *next2;
2144 aTKline *tk, *tk_next;
2145 SpamExcept *spamex_ptr;
2146 int i;
2147
2148 USE_BAN_VERSION = 0;
2149 /* clean out stuff that we don't use */
2150 for (admin_ptr = conf_admin; admin_ptr; admin_ptr = (ConfigItem_admin *)next)
2151 {
2152 next = (ListStruct *)admin_ptr->next;
2153 ircfree(admin_ptr->line);
2154 DelListItem(admin_ptr, conf_admin);
2155 MyFree(admin_ptr);
2156 }
2157 /* wipe the fckers out ..*/
2158 for (oper_ptr = conf_oper; oper_ptr; oper_ptr = (ConfigItem_oper *)next)
2159 {
2160 ConfigItem_oper_from *oper_from;
2161 next = (ListStruct *)oper_ptr->next;
2162 ircfree(oper_ptr->name);
2163 ircfree(oper_ptr->swhois);
2164 ircfree(oper_ptr->snomask);
2165 Auth_DeleteAuthStruct(oper_ptr->auth);
2166 for (oper_from = (ConfigItem_oper_from *) oper_ptr->from; oper_from; oper_from = (ConfigItem_oper_from *) next2)
2167 {
2168 next2 = (ListStruct *)oper_from->next;
2169 ircfree(oper_from->name);
2170 if (oper_from->netmask)
2171 {
2172 MyFree(oper_from->netmask);
2173 }
2174 DelListItem(oper_from, oper_ptr->from);
2175 MyFree(oper_from);
2176 }
2177 DelListItem(oper_ptr, conf_oper);
2178 MyFree(oper_ptr);
2179 }
2180 for (link_ptr = conf_link; link_ptr; link_ptr = (ConfigItem_link *) next)
2181 {
2182 next = (ListStruct *)link_ptr->next;
2183 if (link_ptr->refcount == 0)
2184 {
2185 Debug((DEBUG_ERROR, "s_conf: deleting block %s (refcount 0)", link_ptr->servername));
2186 delete_linkblock(link_ptr);
2187 }
2188 else
2189 {
2190 Debug((DEBUG_ERROR, "s_conf: marking block %s (refcount %d) as temporary",
2191 link_ptr->servername, link_ptr->refcount));
2192 link_ptr->flag.temporary = 1;
2193 }
2194 }
2195 for (class_ptr = conf_class; class_ptr; class_ptr = (ConfigItem_class *) next)
2196 {
2197 next = (ListStruct *)class_ptr->next;
2198 if (class_ptr->flag.permanent == 1)
2199 continue;
2200 class_ptr->flag.temporary = 1;
2201 /* We'll wipe it out when it has no clients */
2202 if (!class_ptr->clients && !class_ptr->xrefcount)
2203 {
2204 delete_classblock(class_ptr);
2205 }
2206 }
2207 for (uline_ptr = conf_ulines; uline_ptr; uline_ptr = (ConfigItem_ulines *) next)
2208 {
2209 next = (ListStruct *)uline_ptr->next;
2210 /* We'll wipe it out when it has no clients */
2211 ircfree(uline_ptr->servername);
2212 DelListItem(uline_ptr, conf_ulines);
2213 MyFree(uline_ptr);
2214 }
2215 for (allow_ptr = conf_allow; allow_ptr; allow_ptr = (ConfigItem_allow *) next)
2216 {
2217 next = (ListStruct *)allow_ptr->next;
2218 ircfree(allow_ptr->ip);
2219 ircfree(allow_ptr->hostname);
2220 if (allow_ptr->netmask)
2221 MyFree(allow_ptr->netmask);
2222 Auth_DeleteAuthStruct(allow_ptr->auth);
2223 DelListItem(allow_ptr, conf_allow);
2224 MyFree(allow_ptr);
2225 }
2226 for (except_ptr = conf_except; except_ptr; except_ptr = (ConfigItem_except *) next)
2227 {
2228 next = (ListStruct *)except_ptr->next;
2229 ircfree(except_ptr->mask);
2230 if (except_ptr->netmask)
2231 MyFree(except_ptr->netmask);
2232 DelListItem(except_ptr, conf_except);
2233 MyFree(except_ptr);
2234 }
2235 for (ban_ptr = conf_ban; ban_ptr; ban_ptr = (ConfigItem_ban *) next)
2236 {
2237 next = (ListStruct *)ban_ptr->next;
2238 if (ban_ptr->flag.type2 == CONF_BAN_TYPE_CONF || ban_ptr->flag.type2 == CONF_BAN_TYPE_TEMPORARY)
2239 {
2240 ircfree(ban_ptr->mask);
2241 ircfree(ban_ptr->reason);
2242 if (ban_ptr->netmask)
2243 MyFree(ban_ptr->netmask);
2244 DelListItem(ban_ptr, conf_ban);
2245 MyFree(ban_ptr);
2246 }
2247 }
2248 for (listen_ptr = conf_listen; listen_ptr; listen_ptr = (ConfigItem_listen *)listen_ptr->next)
2249 {
2250 listen_ptr->flag.temporary = 1;
2251 }
2252 for (tld_ptr = conf_tld; tld_ptr; tld_ptr = (ConfigItem_tld *) next)
2253 {
2254 next = (ListStruct *)tld_ptr->next;
2255 ircfree(tld_ptr->motd_file);
2256 ircfree(tld_ptr->rules_file);
2257 ircfree(tld_ptr->smotd_file);
2258 ircfree(tld_ptr->opermotd_file);
2259 ircfree(tld_ptr->botmotd_file);
2260
2261 free_motd(&tld_ptr->motd);
2262 free_motd(&tld_ptr->rules);
2263 free_motd(&tld_ptr->smotd);
2264 free_motd(&tld_ptr->opermotd);
2265 free_motd(&tld_ptr->botmotd);
2266
2267 DelListItem(tld_ptr, conf_tld);
2268 MyFree(tld_ptr);
2269 }
2270 for (vhost_ptr = conf_vhost; vhost_ptr; vhost_ptr = (ConfigItem_vhost *) next)
2271 {
2272 ConfigItem_oper_from *vhost_from;
2273
2274 next = (ListStruct *)vhost_ptr->next;
2275
2276 ircfree(vhost_ptr->login);
2277 Auth_DeleteAuthStruct(vhost_ptr->auth);
2278 ircfree(vhost_ptr->virthost);
2279 ircfree(vhost_ptr->virtuser);
2280 for (vhost_from = (ConfigItem_oper_from *) vhost_ptr->from; vhost_from;
2281 vhost_from = (ConfigItem_oper_from *) next2)
2282 {
2283 next2 = (ListStruct *)vhost_from->next;
2284 ircfree(vhost_from->name);
2285 DelListItem(vhost_from, vhost_ptr->from);
2286 MyFree(vhost_from);
2287 }
2288 DelListItem(vhost_ptr, conf_vhost);
2289 MyFree(vhost_ptr);
2290 }
2291
2292 #ifdef STRIPBADWORDS
2293 for (badword_ptr = conf_badword_channel; badword_ptr;
2294 badword_ptr = (ConfigItem_badword *) next) {
2295 next = (ListStruct *)badword_ptr->next;
2296 ircfree(badword_ptr->word);
2297 if (badword_ptr->replace)
2298 ircfree(badword_ptr->replace);
2299 regfree(&badword_ptr->expr);
2300 DelListItem(badword_ptr, conf_badword_channel);
2301 MyFree(badword_ptr);
2302 }
2303 for (badword_ptr = conf_badword_message; badword_ptr;
2304 badword_ptr = (ConfigItem_badword *) next) {
2305 next = (ListStruct *)badword_ptr->next;
2306 ircfree(badword_ptr->word);
2307 if (badword_ptr->replace)
2308 ircfree(badword_ptr->replace);
2309 regfree(&badword_ptr->expr);
2310 DelListItem(badword_ptr, conf_badword_message);
2311 MyFree(badword_ptr);
2312 }
2313 for (badword_ptr = conf_badword_quit; badword_ptr;
2314 badword_ptr = (ConfigItem_badword *) next) {
2315 next = (ListStruct *)badword_ptr->next;
2316 ircfree(badword_ptr->word);
2317 if (badword_ptr->replace)
2318 ircfree(badword_ptr->replace);
2319 regfree(&badword_ptr->expr);
2320 DelListItem(badword_ptr, conf_badword_quit);
2321 MyFree(badword_ptr);
2322 }
2323 #endif
2324 /* Clean up local spamfilter entries... */
2325 for (tk = tklines[tkl_hash('f')]; tk; tk = tk_next)
2326 {
2327 if (tk->type == TKL_SPAMF)
2328 tk_next = tkl_del_line(tk);
2329 else /* global spamfilter.. don't touch! */
2330 tk_next = tk->next;
2331 }
2332
2333 for (tk = tklines[tkl_hash('q')]; tk; tk = tk_next)
2334 {
2335 if (tk->type == TKL_NICK)
2336 tk_next = tkl_del_line(tk);
2337 else
2338 tk_next = tk->next;
2339 }
2340
2341 for (deny_dcc_ptr = conf_deny_dcc; deny_dcc_ptr; deny_dcc_ptr = (ConfigItem_deny_dcc *)next)
2342 {
2343 next = (ListStruct *)deny_dcc_ptr->next;
2344 if (deny_dcc_ptr->flag.type2 == CONF_BAN_TYPE_CONF)
2345 {
2346 ircfree(deny_dcc_ptr->filename);
2347 ircfree(deny_dcc_ptr->reason);
2348 DelListItem(deny_dcc_ptr, conf_deny_dcc);
2349 MyFree(deny_dcc_ptr);
2350 }
2351 }
2352 for (deny_link_ptr = conf_deny_link; deny_link_ptr; deny_link_ptr = (ConfigItem_deny_link *) next) {
2353 next = (ListStruct *)deny_link_ptr->next;
2354 ircfree(deny_link_ptr->prettyrule);
2355 ircfree(deny_link_ptr->mask);
2356 crule_free(&deny_link_ptr->rule);
2357 DelListItem(deny_link_ptr, conf_deny_link);
2358 MyFree(deny_link_ptr);
2359 }
2360 for (deny_version_ptr = conf_deny_version; deny_version_ptr; deny_version_ptr = (ConfigItem_deny_version *) next) {
2361 next = (ListStruct *)deny_version_ptr->next;
2362 ircfree(deny_version_ptr->mask);
2363 ircfree(deny_version_ptr->version);
2364 ircfree(deny_version_ptr->flags);
2365 DelListItem(deny_version_ptr, conf_deny_version);
2366 MyFree(deny_version_ptr);
2367 }
2368 for (deny_channel_ptr = conf_deny_channel; deny_channel_ptr; deny_channel_ptr = (ConfigItem_deny_channel *) next)
2369 {
2370 next = (ListStruct *)deny_channel_ptr->next;
2371 ircfree(deny_channel_ptr->redirect);
2372 ircfree(deny_channel_ptr->channel);
2373 ircfree(deny_channel_ptr->reason);
2374 ircfree(deny_channel_ptr->class);
2375 DelListItem(deny_channel_ptr, conf_deny_channel);
2376 MyFree(deny_channel_ptr);
2377 }
2378
2379 for (allow_channel_ptr = conf_allow_channel; allow_channel_ptr; allow_channel_ptr = (ConfigItem_allow_channel *) next)
2380 {
2381 next = (ListStruct *)allow_channel_ptr->next;
2382 ircfree(allow_channel_ptr->channel);
2383 ircfree(allow_channel_ptr->class);
2384 DelListItem(allow_channel_ptr, conf_allow_channel);
2385 MyFree(allow_channel_ptr);
2386 }
2387 for (allow_dcc_ptr = conf_allow_dcc; allow_dcc_ptr; allow_dcc_ptr = (ConfigItem_allow_dcc *)next)
2388 {
2389 next = (ListStruct *)allow_dcc_ptr->next;
2390 if (allow_dcc_ptr->flag.type2 == CONF_BAN_TYPE_CONF)
2391 {
2392 ircfree(allow_dcc_ptr->filename);
2393 DelListItem(allow_dcc_ptr, conf_allow_dcc);
2394 MyFree(allow_dcc_ptr);
2395 }
2396 }
2397
2398 if (conf_drpass)
2399 {
2400 Auth_DeleteAuthStruct(conf_drpass->restartauth);
2401 conf_drpass->restartauth = NULL;
2402 Auth_DeleteAuthStruct(conf_drpass->dieauth);
2403 conf_drpass->dieauth = NULL;
2404 ircfree(conf_drpass);
2405 }
2406 for (log_ptr = conf_log; log_ptr; log_ptr = (ConfigItem_log *)next) {
2407 next = (ListStruct *)log_ptr->next;
2408 ircfree(log_ptr->file);
2409 DelListItem(log_ptr, conf_log);
2410 MyFree(log_ptr);
2411 }
2412 for (alias_ptr = conf_alias; alias_ptr; alias_ptr = (ConfigItem_alias *)next) {
2413 aCommand *cmptr = find_Command(alias_ptr->alias, 0, 0);
2414 ConfigItem_alias_format *fmt;
2415 next = (ListStruct *)alias_ptr->next;
2416 ircfree(alias_ptr->nick);
2417 del_Command(alias_ptr->alias, NULL, cmptr->func);
2418 ircfree(alias_ptr->alias);
2419 if (alias_ptr->format && (alias_ptr->type == ALIAS_COMMAND)) {
2420 for (fmt = (ConfigItem_alias_format *) alias_ptr->format; fmt; fmt = (ConfigItem_alias_format *) next2)
2421 {
2422 next2 = (ListStruct *)fmt->next;
2423 ircfree(fmt->format);
2424 ircfree(fmt->nick);
2425 ircfree(fmt->parameters);
2426 regfree(&fmt->expr);
2427 DelListItem(fmt, alias_ptr->format);
2428 MyFree(fmt);
2429 }
2430 }
2431 DelListItem(alias_ptr, conf_alias);
2432 MyFree(alias_ptr);
2433 }
2434 for (help_ptr = conf_help; help_ptr; help_ptr = (ConfigItem_help *)next) {
2435 aMotdLine *text;
2436 next = (ListStruct *)help_ptr->next;
2437 ircfree(help_ptr->command);
2438 while (help_ptr->text) {
2439 text = help_ptr->text->next;
2440 ircfree(help_ptr->text->line);
2441 ircfree(help_ptr->text);
2442 help_ptr->text = text;
2443 }
2444 DelListItem(help_ptr, conf_help);
2445 MyFree(help_ptr);
2446 }
2447 for (os_ptr = iConf.oper_only_stats_ext; os_ptr; os_ptr = (OperStat *)next)
2448 {
2449 next = (ListStruct *)os_ptr->next;
2450 ircfree(os_ptr->flag);
2451 MyFree(os_ptr);
2452 }
2453 iConf.oper_only_stats_ext = NULL;
2454 for (spamex_ptr = iConf.spamexcept; spamex_ptr; spamex_ptr = (SpamExcept *)next)
2455 {
2456 next = (ListStruct *)spamex_ptr->next;
2457 MyFree(spamex_ptr);
2458 }
2459 iConf.spamexcept = NULL;
2460 for (of_ptr = conf_offchans; of_ptr; of_ptr = (ConfigItem_offchans *)next)
2461 {
2462 next = (ListStruct *)of_ptr->next;
2463 ircfree(of_ptr->topic);
2464 MyFree(of_ptr);
2465 }
2466 conf_offchans = NULL;
2467
2468 #ifdef EXTCMODE
2469 for (i = 0; i < EXTCMODETABLESZ; i++)
2470 {
2471 if (iConf.modes_on_join.extparams[i])
2472 free(iConf.modes_on_join.extparams[i]);
2473 }
2474 #endif
2475
2476 for (cgiirc_ptr = conf_cgiirc; cgiirc_ptr; cgiirc_ptr = (ConfigItem_cgiirc *) next)
2477 {
2478 next = (ListStruct *)cgiirc_ptr->next;
2479 delete_cgiircblock(cgiirc_ptr);
2480 }
2481
2482 /*
2483 reset conf_files -- should this be in its own function? no, because
2484 it's only used here
2485 */
2486 ircfree(conf_files->motd_file);
2487 ircfree(conf_files->smotd_file);
2488 ircfree(conf_files->opermotd_file);
2489 ircfree(conf_files->svsmotd_file);
2490 ircfree(conf_files->botmotd_file);
2491 ircfree(conf_files->rules_file);
2492 ircfree(conf_files->tune_file);
2493 /*
2494 Don't free conf_files->pid_file here; the old value is used to determine if
2495 the pidfile location has changed and write_pidfile() needs to be called
2496 again.
2497 */
2498 ircfree(conf_files);
2499 conf_files = NULL;
2500 }
2501
config_post_test()2502 int config_post_test()
2503 {
2504 #define Error(x) { config_error((x)); errors++; }
2505 int errors = 0;
2506 Hook *h;
2507
2508 if (!requiredstuff.conf_me)
2509 Error("me {} block is missing");
2510 if (!requiredstuff.conf_admin)
2511 Error("admin {} block is missing");
2512 if (!requiredstuff.conf_listen)
2513 Error("listen {} block is missing");
2514 if (!settings.has_kline_address)
2515 Error("set::kline-address is missing");
2516 if (!settings.has_maxchannelsperuser)
2517 Error("set::maxchannelsperuser is missing");
2518 #if 0
2519 if (!settings.has_dns_nameserver)
2520 Error("set::dns::nameserver is missing");
2521 if (!settings.has_dns_timeout)
2522 Error("set::dns::timeout is missing");
2523 if (!settings.has_dns_retries)
2524 Error("set::dns::retries is missing");
2525 #endif
2526 if (!settings.has_services_server)
2527 Error("set::services-server is missing");
2528 if (!settings.has_default_server)
2529 Error("set::default-server is missing");
2530 if (!settings.has_network_name)
2531 Error("set::network-name is missing");
2532 if (!settings.has_hosts_global)
2533 Error("set::hosts::global is missing");
2534 if (!settings.has_hosts_admin)
2535 Error("set::hosts::admin is missing");
2536 if (!settings.has_hosts_servicesadmin)
2537 Error("set::hosts::servicesadmin is missing");
2538 if (!settings.has_hosts_netadmin)
2539 Error("set::hosts::netadmin is missing");
2540 if (!settings.has_hosts_coadmin)
2541 Error("set::hosts::coadmin is missing");
2542 if (!settings.has_help_channel)
2543 Error("set::help-channel is missing");
2544 if (!settings.has_hiddenhost_prefix)
2545 Error("set::hiddenhost-prefix is missing");
2546
2547 for (h = Hooks[HOOKTYPE_CONFIGPOSTTEST]; h; h = h->next)
2548 {
2549 int value, errs = 0;
2550 if (h->owner && !(h->owner->flags & MODFLAG_TESTING) &&
2551 !(h->owner->options & MOD_OPT_PERM))
2552 continue;
2553 value = (*(h->func.intfunc))(&errs);
2554 if (value == -1)
2555 {
2556 errors += errs;
2557 break;
2558 }
2559 if (value == -2)
2560 errors += errs;
2561 }
2562 return errors;
2563 }
2564
config_run()2565 int config_run()
2566 {
2567 ConfigEntry *ce;
2568 ConfigFile *cfptr;
2569 ConfigCommand *cc;
2570 int errors = 0;
2571 Hook *h;
2572 #ifdef INET6
2573 ConfigItem_allow *allow;
2574 #endif /* INET6 */
2575 for (cfptr = conf; cfptr; cfptr = cfptr->cf_next)
2576 {
2577 if (config_verbose > 1)
2578 config_status("Running %s", cfptr->cf_filename);
2579 for (ce = cfptr->cf_entries; ce; ce = ce->ce_next)
2580 {
2581 if ((cc = config_binary_search(ce->ce_varname))) {
2582 if ((cc->conffunc) && (cc->conffunc(cfptr, ce) < 0))
2583 errors++;
2584 }
2585 else
2586 {
2587 int value;
2588 for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
2589 {
2590 value = (*(h->func.intfunc))(cfptr,ce,CONFIG_MAIN);
2591 if (value == 1)
2592 break;
2593 }
2594 }
2595 }
2596 }
2597 #ifdef INET6
2598 /*
2599 * transfer default values from set::ipv6_clones_mask into
2600 * each individual allow block. If other similar things like
2601 * this stack up here, perhaps this shoul be moved to another
2602 * function.
2603 */
2604 for(allow = conf_allow; allow; allow = (ConfigItem_allow *)allow->next)
2605 if(!allow->ipv6_clone_mask)
2606 allow->ipv6_clone_mask = tempiConf.default_ipv6_clone_mask;
2607 #endif /* INET6 */
2608
2609 close_listeners();
2610 listen_cleanup();
2611 close_listeners();
2612 loop.do_bancheck = 1;
2613 free_iConf(&iConf);
2614 bcopy(&tempiConf, &iConf, sizeof(aConfiguration));
2615 bzero(&tempiConf, sizeof(aConfiguration));
2616 #ifdef THROTTLING
2617 {
2618 EventInfo eInfo;
2619 long v;
2620 eInfo.flags = EMOD_EVERY;
2621 if (!THROTTLING_PERIOD)
2622 v = 120;
2623 else
2624 {
2625 v = THROTTLING_PERIOD/2;
2626 if (v > 5)
2627 v = 5; /* accuracy, please */
2628 }
2629 eInfo.every = v;
2630 EventMod(EventFind("bucketcleaning"), &eInfo);
2631 }
2632 #endif
2633
2634 /* initialize conf_files with defaults if the block isn't set: */
2635 if(!conf_files)
2636 _conf_files(NULL, NULL);
2637
2638 if (errors > 0)
2639 {
2640 config_error("%i fatal errors encountered", errors);
2641 }
2642 return (errors > 0 ? -1 : 1);
2643 }
2644
2645
config_binary_flags_search(OperFlag * table,char * cmd,int size)2646 OperFlag *config_binary_flags_search(OperFlag *table, char *cmd, int size) {
2647 int start = 0;
2648 int stop = size-1;
2649 int mid;
2650 while (start <= stop) {
2651 mid = (start+stop)/2;
2652
2653 if (smycmp(cmd,table[mid].name) < 0) {
2654 stop = mid-1;
2655 }
2656 else if (strcmp(cmd,table[mid].name) == 0) {
2657 return &(table[mid]);
2658 }
2659 else
2660 start = mid+1;
2661 }
2662 return NULL;
2663 }
2664
2665
config_test()2666 int config_test()
2667 {
2668 ConfigEntry *ce;
2669 ConfigFile *cfptr;
2670 ConfigCommand *cc;
2671 int errors = 0;
2672 Hook *h;
2673
2674 for (cfptr = conf; cfptr; cfptr = cfptr->cf_next)
2675 {
2676 if (config_verbose > 1)
2677 config_status("Testing %s", cfptr->cf_filename);
2678 for (ce = cfptr->cf_entries; ce; ce = ce->ce_next)
2679 {
2680 if (!ce->ce_varname)
2681 {
2682 config_error("%s:%i: %s:%i: null ce->ce_varname",
2683 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
2684 __FILE__, __LINE__);
2685 return -1;
2686 }
2687 if ((cc = config_binary_search(ce->ce_varname))) {
2688 if (cc->testfunc)
2689 errors += (cc->testfunc(cfptr, ce));
2690 }
2691 else
2692 {
2693 int used = 0;
2694 for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
2695 {
2696 int value, errs = 0;
2697 if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
2698 && !(h->owner->options & MOD_OPT_PERM))
2699
2700
2701 continue;
2702 value = (*(h->func.intfunc))(cfptr,ce,CONFIG_MAIN,&errs);
2703 if (value == 2)
2704 used = 1;
2705 if (value == 1)
2706 {
2707 used = 1;
2708 break;
2709 }
2710 if (value == -1)
2711 {
2712 used = 1;
2713 errors += errs;
2714 break;
2715 }
2716 if (value == -2)
2717 {
2718 used = 1;
2719 errors += errs;
2720 }
2721
2722 }
2723 if (!used)
2724 config_status("%s:%i: unknown directive %s",
2725 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
2726 ce->ce_varname);
2727 }
2728 }
2729 }
2730 errors += config_post_test();
2731 if (errors > 0)
2732 {
2733 config_error("%i errors encountered", errors);
2734 }
2735 return (errors > 0 ? -1 : 1);
2736 }
2737
2738 /*
2739 * Service functions
2740 */
2741
Find_deny_dcc(char * name)2742 ConfigItem_deny_dcc *Find_deny_dcc(char *name)
2743 {
2744 ConfigItem_deny_dcc *p;
2745
2746 if (!name)
2747 return NULL;
2748
2749 for (p = conf_deny_dcc; p; p = (ConfigItem_deny_dcc *) p->next)
2750 {
2751 if (!match(name, p->filename))
2752 return (p);
2753 }
2754 return NULL;
2755 }
2756
Find_alias(char * name)2757 ConfigItem_alias *Find_alias(char *name) {
2758 ConfigItem_alias *alias;
2759
2760 if (!name)
2761 return NULL;
2762
2763 for (alias = conf_alias; alias; alias = (ConfigItem_alias *)alias->next) {
2764 if (!stricmp(alias->alias, name))
2765 return alias;
2766 }
2767 return NULL;
2768 }
2769
Find_class(char * name)2770 ConfigItem_class *Find_class(char *name)
2771 {
2772 ConfigItem_class *p;
2773
2774 if (!name)
2775 return NULL;
2776
2777 for (p = conf_class; p; p = (ConfigItem_class *) p->next)
2778 {
2779 if (!strcmp(name, p->name))
2780 return (p);
2781 }
2782 return NULL;
2783 }
2784
Find_oper(char * name)2785 ConfigItem_oper *Find_oper(char *name)
2786 {
2787 ConfigItem_oper *p;
2788
2789 if (!name)
2790 return NULL;
2791
2792 for (p = conf_oper; p; p = (ConfigItem_oper *) p->next)
2793 {
2794 if (!strcmp(name, p->name))
2795 return (p);
2796 }
2797 return NULL;
2798 }
2799
count_oper_sessions(char * name)2800 int count_oper_sessions(char *name)
2801 {
2802 int i, count = 0;
2803 aClient *cptr;
2804
2805 #ifdef NO_FDLIST
2806 for (i = 0; i <= LastSlot; i++)
2807 #else
2808 int j;
2809 for (i = oper_fdlist.entry[j = 1]; j <= oper_fdlist.last_entry; i = oper_fdlist.entry[++j])
2810 #endif
2811 if ((cptr = local[i]) && IsPerson(cptr) && IsAnOper(cptr) &&
2812 cptr->user && cptr->user->operlogin && !strcmp(cptr->user->operlogin,name))
2813 count++;
2814
2815 return count;
2816 }
2817
Find_listen(char * ipmask,int port)2818 ConfigItem_listen *Find_listen(char *ipmask, int port)
2819 {
2820 ConfigItem_listen *p;
2821
2822 if (!ipmask)
2823 return NULL;
2824
2825 for (p = conf_listen; p; p = (ConfigItem_listen *) p->next)
2826 {
2827 if (!match(p->ip, ipmask) && (port == p->port))
2828 return (p);
2829 if (!match(ipmask, p->ip) && (port == p->port))
2830 return (p);
2831 }
2832 return NULL;
2833 }
2834
Find_uline(char * host)2835 ConfigItem_ulines *Find_uline(char *host) {
2836 ConfigItem_ulines *ulines;
2837
2838 if (!host)
2839 return NULL;
2840
2841 for(ulines = conf_ulines; ulines; ulines =(ConfigItem_ulines *) ulines->next) {
2842 if (!stricmp(host, ulines->servername))
2843 return ulines;
2844 }
2845 return NULL;
2846 }
2847
2848
Find_except(aClient * sptr,char * host,short type)2849 ConfigItem_except *Find_except(aClient *sptr, char *host, short type) {
2850 ConfigItem_except *excepts;
2851
2852 if (!host)
2853 return NULL;
2854
2855 for(excepts = conf_except; excepts; excepts =(ConfigItem_except *) excepts->next) {
2856 if (excepts->flag.type == type)
2857 {
2858 if (match_ip(sptr->ip, host, excepts->mask, excepts->netmask))
2859 return excepts;
2860 }
2861 }
2862 return NULL;
2863 }
2864
Find_tld(aClient * cptr,char * uhost)2865 ConfigItem_tld *Find_tld(aClient *cptr, char *uhost) {
2866 ConfigItem_tld *tld;
2867
2868 if (!uhost || !cptr)
2869 return NULL;
2870
2871 for(tld = conf_tld; tld; tld = (ConfigItem_tld *) tld->next)
2872 {
2873 if (!match(tld->mask, uhost))
2874 {
2875 if ((tld->options & TLD_SSL) && !IsSecure(cptr))
2876 continue;
2877 if ((tld->options & TLD_REMOTE) && MyClient(cptr))
2878 continue;
2879 return tld;
2880 }
2881 }
2882 return NULL;
2883 }
2884
2885
Find_link(char * username,char * hostname,char * ip,char * servername)2886 ConfigItem_link *Find_link(char *username,
2887 char *hostname,
2888 char *ip,
2889 char *servername)
2890 {
2891 ConfigItem_link *link;
2892
2893 if (!username || !hostname || !servername || !ip)
2894 return NULL;
2895
2896 for(link = conf_link; link; link = (ConfigItem_link *) link->next)
2897 {
2898 if (!match(link->servername, servername) &&
2899 !match(link->username, username) &&
2900 (!match(link->hostname, hostname) || !match(link->hostname, ip)))
2901 return link;
2902 }
2903 return NULL;
2904
2905 }
2906
2907 /* ugly ugly ugly */
match_ip46(char * a,char * b)2908 int match_ip46(char *a, char *b)
2909 {
2910 #ifdef INET6
2911 if (!strncmp(a, "::ffff:", 7) && !strcmp(a+7, b))
2912 return 0; // match
2913 #endif
2914 return 1; //nomatch
2915 }
2916
Find_cgiirc(char * username,char * hostname,char * ip,CGIIRCType type)2917 ConfigItem_cgiirc *Find_cgiirc(char *username, char *hostname, char *ip, CGIIRCType type)
2918 {
2919 ConfigItem_cgiirc *e;
2920
2921 if (!username || !hostname || !ip)
2922 return NULL;
2923
2924 for (e = conf_cgiirc; e; e = (ConfigItem_cgiirc *)e->next)
2925 {
2926 if ((e->type == type) && (!e->username || !match(e->username, username)) &&
2927 (!match(e->hostname, hostname) || !match(e->hostname, ip) || !match_ip46(e->hostname, ip)))
2928 return e;
2929 }
2930
2931 return NULL;
2932 }
2933
Find_ban(aClient * sptr,char * host,short type)2934 ConfigItem_ban *Find_ban(aClient *sptr, char *host, short type)
2935 {
2936 ConfigItem_ban *ban;
2937
2938 /* Check for an except ONLY if we find a ban, makes it
2939 * faster since most users will not have a ban so excepts
2940 * don't need to be searched -- codemastr
2941 */
2942
2943 for (ban = conf_ban; ban; ban = (ConfigItem_ban *) ban->next)
2944 {
2945 if (ban->flag.type == type)
2946 {
2947 if (sptr)
2948 {
2949 if (match_ip(sptr->ip, host, ban->mask, ban->netmask))
2950 {
2951 /* Person got a exception */
2952 if ((type == CONF_BAN_USER || type == CONF_BAN_IP)
2953 && Find_except(sptr, host, CONF_EXCEPT_BAN))
2954 return NULL;
2955 return ban;
2956 }
2957 }
2958 else if (!match(ban->mask, host)) /* We don't worry about exceptions */
2959 return ban;
2960 }
2961 }
2962 return NULL;
2963 }
2964
Find_banEx(aClient * sptr,char * host,short type,short type2)2965 ConfigItem_ban *Find_banEx(aClient *sptr, char *host, short type, short type2)
2966 {
2967 ConfigItem_ban *ban;
2968
2969 /* Check for an except ONLY if we find a ban, makes it
2970 * faster since most users will not have a ban so excepts
2971 * don't need to be searched -- codemastr
2972 */
2973
2974 for (ban = conf_ban; ban; ban = (ConfigItem_ban *) ban->next)
2975 {
2976 if ((ban->flag.type == type) && (ban->flag.type2 == type2))
2977 {
2978 if (sptr)
2979 {
2980 if (match_ip(sptr->ip, host, ban->mask, ban->netmask)) {
2981 /* Person got a exception */
2982 if (Find_except(sptr, host, type))
2983 return NULL;
2984 return ban;
2985 }
2986 }
2987 else if (!match(ban->mask, host)) /* We don't worry about exceptions */
2988 return ban;
2989 }
2990 }
2991 return NULL;
2992 }
2993
AllowClient(aClient * cptr,struct hostent * hp,char * sockhost,char * username)2994 int AllowClient(aClient *cptr, struct hostent *hp, char *sockhost, char *username)
2995 {
2996 ConfigItem_allow *aconf;
2997 char *hname;
2998 int i, ii = 0;
2999 static char uhost[HOSTLEN + USERLEN + 3];
3000 static char fullname[HOSTLEN + 1];
3001 #ifdef INET6
3002 short is_ipv4;
3003 #endif /* INET6 */
3004
3005 for (aconf = conf_allow; aconf; aconf = (ConfigItem_allow *) aconf->next)
3006 {
3007 if (!aconf->hostname || !aconf->ip)
3008 goto attach;
3009 if (aconf->auth && !cptr->passwd && aconf->flags.nopasscont)
3010 continue;
3011 if (aconf->flags.ssl && !IsSecure(cptr))
3012 continue;
3013 if (hp && hp->h_name)
3014 {
3015 hname = hp->h_name;
3016 strncpyzt(fullname, hname, sizeof(fullname));
3017 add_local_domain(fullname, HOSTLEN - strlen(fullname));
3018 Debug((DEBUG_DNS, "a_il: %s->%s", sockhost, fullname));
3019 if (index(aconf->hostname, '@'))
3020 {
3021 if (aconf->flags.noident)
3022 strlcpy(uhost, username, sizeof(uhost));
3023 else
3024 strlcpy(uhost, cptr->username, sizeof(uhost));
3025 strlcat(uhost, "@", sizeof(uhost));
3026 }
3027 else
3028 *uhost = '\0';
3029 strlcat(uhost, fullname, sizeof(uhost));
3030 if (!match(aconf->hostname, uhost))
3031 goto attach;
3032 }
3033
3034 if (index(aconf->ip, '@'))
3035 {
3036 if (aconf->flags.noident)
3037 strncpyzt(uhost, username, sizeof(uhost));
3038 else
3039 strncpyzt(uhost, cptr->username, sizeof(uhost));
3040 (void)strlcat(uhost, "@", sizeof(uhost));
3041 }
3042 else
3043 *uhost = '\0';
3044 strlcat(uhost, sockhost, sizeof(uhost));
3045 /* Check the IP */
3046 if (match_ip(cptr->ip, uhost, aconf->ip, aconf->netmask))
3047 goto attach;
3048
3049 /* Hmm, localhost is a special case, hp == NULL and sockhost contains
3050 * 'localhost' instead of an ip... -- Syzop. */
3051 if (!strcmp(sockhost, "localhost"))
3052 {
3053 if (index(aconf->hostname, '@'))
3054 {
3055 if (aconf->flags.noident)
3056 strcpy(uhost, username);
3057 else
3058 strcpy(uhost, cptr->username);
3059 strcat(uhost, "@localhost");
3060 }
3061 else
3062 strcpy(uhost, "localhost");
3063
3064 if (!match(aconf->hostname, uhost))
3065 goto attach;
3066 }
3067
3068 continue;
3069 attach:
3070 /* if (index(uhost, '@')) now flag based -- codemastr */
3071 if (!aconf->flags.noident)
3072 cptr->flags |= FLAGS_DOID;
3073 if (!aconf->flags.useip && hp)
3074 strncpyzt(uhost, fullname, sizeof(uhost));
3075 else
3076 strncpyzt(uhost, sockhost, sizeof(uhost));
3077 get_sockhost(cptr, uhost);
3078 #ifdef INET6
3079 is_ipv4 = IN6_IS_ADDR_V4MAPPED(&cptr->ip);
3080 #endif /* INET6 */
3081
3082 /* FIXME */
3083 if (aconf->maxperip)
3084 {
3085 ii = 1;
3086 for (i = LastSlot; i >= 0; i--)
3087 if (local[i] && MyClient(local[i])
3088 #ifndef INET6
3089 && local[i]->ip.S_ADDR == cptr->ip.S_ADDR)
3090 #else
3091 /*
3092 * match IPv4 exactly and the ipv6
3093 * based on ipv6_clone_mask.
3094 */
3095 && (is_ipv4
3096 ? !bcmp(local[i]->ip.S_ADDR, cptr->ip.S_ADDR, sizeof(cptr->ip.S_ADDR))
3097 : match_ipv6(&local[i]->ip, &cptr->ip, aconf->ipv6_clone_mask)))
3098
3099 #endif
3100 {
3101 ii++;
3102 if (ii > aconf->maxperip)
3103 {
3104 exit_client(cptr, cptr, &me,
3105 "Too many connections from your IP");
3106 return -5; /* Already got one with that ip# */
3107 }
3108 }
3109 }
3110 if ((i = Auth_Check(cptr, aconf->auth, cptr->passwd)) == -1)
3111 {
3112 exit_client(cptr, cptr, &me,
3113 "Password mismatch");
3114 return -5;
3115 }
3116 if ((i == 2) && (cptr->passwd))
3117 {
3118 MyFree(cptr->passwd);
3119 cptr->passwd = NULL;
3120 }
3121 if (!((aconf->class->clients + 1) > aconf->class->maxclients))
3122 {
3123 cptr->class = aconf->class;
3124 cptr->class->clients++;
3125 }
3126 else
3127 {
3128 sendto_one(cptr, rpl_str(RPL_REDIR), me.name, cptr->name, aconf->server ? aconf->server : defserv, aconf->port ? aconf->port : 6667);
3129 return -3;
3130 }
3131 return 0;
3132 }
3133 return -1;
3134 }
3135
Find_vhost(char * name)3136 ConfigItem_vhost *Find_vhost(char *name) {
3137 ConfigItem_vhost *vhost;
3138
3139 for (vhost = conf_vhost; vhost; vhost = (ConfigItem_vhost *)vhost->next) {
3140 if (!strcmp(name, vhost->login))
3141 return vhost;
3142 }
3143 return NULL;
3144 }
3145
3146
3147 /** returns NULL if allowed and struct if denied */
Find_channel_allowed(aClient * cptr,char * name)3148 ConfigItem_deny_channel *Find_channel_allowed(aClient *cptr, char *name)
3149 {
3150 ConfigItem_deny_channel *dchannel;
3151 ConfigItem_allow_channel *achannel;
3152
3153 for (dchannel = conf_deny_channel; dchannel; dchannel = (ConfigItem_deny_channel *)dchannel->next)
3154 {
3155 if (!match(dchannel->channel, name) && (dchannel->class ? !strcmp(cptr->class->name, dchannel->class) : 1))
3156 break;
3157 }
3158 if (dchannel)
3159 {
3160 for (achannel = conf_allow_channel; achannel; achannel = (ConfigItem_allow_channel *)achannel->next)
3161 {
3162 if (!match(achannel->channel, name) && (achannel->class ? !strcmp(cptr->class->name, achannel->class) : 1))
3163 break;
3164 }
3165 if (achannel)
3166 return NULL;
3167 else
3168 return (dchannel);
3169 }
3170 return NULL;
3171 }
3172
init_dynconf(void)3173 void init_dynconf(void)
3174 {
3175 bzero(&iConf, sizeof(iConf));
3176 bzero(&tempiConf, sizeof(iConf));
3177 }
3178
pretty_time_val(long timeval)3179 char *pretty_time_val(long timeval)
3180 {
3181 static char buf[512];
3182
3183 if (timeval == 0)
3184 return "0";
3185
3186 buf[0] = 0;
3187
3188 if (timeval/86400)
3189 sprintf(buf, "%ld day%s ", timeval/86400, timeval/86400 != 1 ? "s" : "");
3190 if ((timeval/3600) % 24)
3191 sprintf(buf, "%s%ld hour%s ", buf, (timeval/3600)%24, (timeval/3600)%24 != 1 ? "s" : "");
3192 if ((timeval/60)%60)
3193 sprintf(buf, "%s%ld minute%s ", buf, (timeval/60)%60, (timeval/60)%60 != 1 ? "s" : "");
3194 if ((timeval%60))
3195 sprintf(buf, "%s%ld second%s", buf, timeval%60, timeval%60 != 1 ? "s" : "");
3196 return buf;
3197 }
3198
3199 /*
3200 * Actual config parser funcs
3201 */
3202
_conf_include(ConfigFile * conf,ConfigEntry * ce)3203 int _conf_include(ConfigFile *conf, ConfigEntry *ce)
3204 {
3205 int ret = 0;
3206 #ifdef GLOBH
3207 glob_t files;
3208 int i;
3209 #elif defined(_WIN32)
3210 HANDLE hFind;
3211 WIN32_FIND_DATA FindData;
3212 char cPath[MAX_PATH], *cSlash = NULL, *path;
3213 #endif
3214 if (!ce->ce_vardata)
3215 {
3216 config_status("%s:%i: include: no filename given",
3217 ce->ce_fileptr->cf_filename,
3218 ce->ce_varlinenum);
3219 return -1;
3220 }
3221 #ifdef USE_LIBCURL
3222 if (url_is_valid(ce->ce_vardata))
3223 return remote_include(ce);
3224 #endif
3225 #if !defined(_WIN32) && !defined(_AMIGA) && !defined(OSXTIGER) && DEFAULT_PERMISSIONS != 0
3226 chmod(ce->ce_vardata, DEFAULT_PERMISSIONS);
3227 #endif
3228 #ifdef GLOBH
3229 #if defined(__OpenBSD__) && defined(GLOB_LIMIT)
3230 glob(ce->ce_vardata, GLOB_NOSORT|GLOB_NOCHECK|GLOB_LIMIT, NULL, &files);
3231 #else
3232 glob(ce->ce_vardata, GLOB_NOSORT|GLOB_NOCHECK, NULL, &files);
3233 #endif
3234 if (!files.gl_pathc) {
3235 globfree(&files);
3236 config_status("%s:%i: include %s: invalid file given",
3237 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
3238 ce->ce_vardata);
3239 return -1;
3240 }
3241 for (i = 0; i < files.gl_pathc; i++) {
3242 add_include(files.gl_pathv[i], ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
3243 ret = load_conf(files.gl_pathv[i], files.gl_pathv[i]);
3244 if (ret < 0)
3245 {
3246 globfree(&files);
3247 return ret;
3248 }
3249 }
3250 globfree(&files);
3251 #elif defined(_WIN32)
3252 bzero(cPath,MAX_PATH);
3253 if (strchr(ce->ce_vardata, '/') || strchr(ce->ce_vardata, '\\')) {
3254 strncpyzt(cPath,ce->ce_vardata,MAX_PATH);
3255 cSlash=cPath+strlen(cPath);
3256 while(*cSlash != '\\' && *cSlash != '/' && cSlash > cPath)
3257 cSlash--;
3258 *(cSlash+1)=0;
3259 }
3260 if ( (hFind = FindFirstFile(ce->ce_vardata, &FindData)) == INVALID_HANDLE_VALUE )
3261 {
3262 config_status("%s:%i: include %s: invalid file given",
3263 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
3264 ce->ce_vardata);
3265 return -1;
3266 }
3267 if (cPath) {
3268 path = MyMalloc(strlen(cPath) + strlen(FindData.cFileName)+1);
3269 strcpy(path, cPath);
3270 strcat(path, FindData.cFileName);
3271
3272 add_include(path, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
3273 ret = load_conf(path, path);
3274 free(path);
3275
3276 }
3277 else
3278 {
3279 add_include(FindData.cFileName, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
3280 ret = load_conf(FindData.cFileName, FindData.cFileName);
3281 }
3282 if (ret < 0)
3283 {
3284 FindClose(hFind);
3285 return ret;
3286 }
3287
3288 ret = 0;
3289 while (FindNextFile(hFind, &FindData) != 0) {
3290 if (cPath) {
3291 path = MyMalloc(strlen(cPath) + strlen(FindData.cFileName)+1);
3292 strcpy(path,cPath);
3293 strcat(path,FindData.cFileName);
3294
3295 add_include(path, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
3296 ret = load_conf(path, path);
3297 free(path);
3298 if (ret < 0)
3299 break;
3300 }
3301 else
3302 {
3303 add_include(FindData.cFileName, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
3304 ret = load_conf(FindData.cFileName, FindData.cFileName);
3305 }
3306 }
3307 FindClose(hFind);
3308 if (ret < 0)
3309 return ret;
3310 #else
3311 add_include(ce->ce_vardata, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
3312 ret = load_conf(ce->ce_vardata, ce->ce_vardata);
3313 return ret;
3314 #endif
3315 return 1;
3316 }
3317
_test_include(ConfigFile * conf,ConfigEntry * ce)3318 int _test_include(ConfigFile *conf, ConfigEntry *ce)
3319 {
3320 return 0;
3321 }
3322
_conf_admin(ConfigFile * conf,ConfigEntry * ce)3323 int _conf_admin(ConfigFile *conf, ConfigEntry *ce)
3324 {
3325 ConfigEntry *cep;
3326 ConfigItem_admin *ca;
3327
3328 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
3329 {
3330 ca = MyMallocEx(sizeof(ConfigItem_admin));
3331 if (!conf_admin)
3332 conf_admin_tail = ca;
3333 ircstrdup(ca->line, cep->ce_varname);
3334 AddListItem(ca, conf_admin);
3335 }
3336 return 1;
3337 }
3338
_test_admin(ConfigFile * conf,ConfigEntry * ce)3339 int _test_admin(ConfigFile *conf, ConfigEntry *ce)
3340 {
3341 ConfigEntry *cep;
3342 int errors = 0;
3343
3344 if (requiredstuff.conf_admin)
3345 {
3346 config_warn_duplicate(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "admin");
3347 return 0;
3348 }
3349
3350 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
3351 {
3352 if (!cep->ce_varname)
3353 {
3354 config_error("%s:%i: blank admin item",
3355 cep->ce_fileptr->cf_filename,
3356 cep->ce_varlinenum);
3357 errors++;
3358 continue;
3359 }
3360 }
3361 requiredstuff.conf_admin = 1;
3362 return errors;
3363 }
3364
_conf_me(ConfigFile * conf,ConfigEntry * ce)3365 int _conf_me(ConfigFile *conf, ConfigEntry *ce)
3366 {
3367 ConfigEntry *cep;
3368
3369 if (!conf_me)
3370 conf_me = MyMallocEx(sizeof(ConfigItem_me));
3371
3372 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
3373 {
3374 if (!strcmp(cep->ce_varname, "name"))
3375 {
3376 ircstrdup(conf_me->name, cep->ce_vardata);
3377 }
3378 else if (!strcmp(cep->ce_varname, "info"))
3379 {
3380 ircstrdup(conf_me->info, cep->ce_vardata);
3381 }
3382 else if (!strcmp(cep->ce_varname, "numeric"))
3383 {
3384 conf_me->numeric = atol(cep->ce_vardata);
3385 }
3386 }
3387 return 1;
3388 }
3389
_test_me(ConfigFile * conf,ConfigEntry * ce)3390 int _test_me(ConfigFile *conf, ConfigEntry *ce)
3391 {
3392 char has_name = 0, has_info = 0, has_numeric = 0;
3393 ConfigEntry *cep;
3394 int errors = 0;
3395
3396 if (requiredstuff.conf_me)
3397 {
3398 config_warn_duplicate(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "me");
3399 return 0;
3400 }
3401
3402 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
3403 {
3404 if (config_is_blankorempty(cep, "me"))
3405 continue;
3406
3407 /* me::name */
3408 if (!strcmp(cep->ce_varname, "name"))
3409 {
3410 if (has_name)
3411 {
3412 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3413 cep->ce_varlinenum, "me::name");
3414 continue;
3415 }
3416 has_name = 1;
3417 if (!strchr(cep->ce_vardata, '.'))
3418 {
3419 config_error("%s:%i: illegal me::name, must be fully qualified hostname",
3420 cep->ce_fileptr->cf_filename,
3421 cep->ce_varlinenum);
3422 errors++;
3423 }
3424 if (!valid_host(cep->ce_vardata))
3425 {
3426 config_error("%s:%i: illegal me::name contains invalid character(s) [only a-z, 0-9, _, -, . are allowed]",
3427 cep->ce_fileptr->cf_filename,
3428 cep->ce_varlinenum);
3429 errors++;
3430 }
3431 if (strlen(cep->ce_vardata) > HOSTLEN)
3432 {
3433 config_error("%s:%i: illegal me::name, must be less or equal to %i characters",
3434 cep->ce_fileptr->cf_filename,
3435 cep->ce_varlinenum, HOSTLEN);
3436 errors++;
3437 }
3438 }
3439 /* me::info */
3440 else if (!strcmp(cep->ce_varname, "info"))
3441 {
3442 char *p;
3443 char valid = 0;
3444 if (has_info)
3445 {
3446 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3447 cep->ce_varlinenum, "me::info");
3448 continue;
3449 }
3450 has_info = 1;
3451 if (strlen(cep->ce_vardata) > (REALLEN-1))
3452 {
3453 config_error("%s:%i: too long me::info, must be max. %i characters",
3454 cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
3455 REALLEN-1);
3456 errors++;
3457 }
3458
3459 /* Valid me::info? Any data except spaces is ok */
3460 for (p=cep->ce_vardata; *p; p++)
3461 {
3462 if (*p != ' ')
3463 {
3464 valid = 1;
3465 break;
3466 }
3467 }
3468 if (!valid)
3469 {
3470 config_error("%s:%i: empty me::info, should be a server description.",
3471 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
3472 errors++;
3473 }
3474 }
3475 /* me::numeric */
3476 else if (!strcmp(cep->ce_varname, "numeric"))
3477 {
3478 long l;
3479
3480 has_numeric = 1;
3481 l = atol(cep->ce_vardata);
3482 if ((l < 0) || (l > 254))
3483 {
3484 config_error("%s:%i: illegal me::numeric error (must be between 0 and 254)",
3485 cep->ce_fileptr->cf_filename,
3486 cep->ce_varlinenum);
3487 errors++;
3488 }
3489 }
3490 /* Unknown entry */
3491 else
3492 {
3493 config_error_unknown(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
3494 "me", cep->ce_varname);
3495 errors++;
3496 }
3497 }
3498 if (!has_name)
3499 {
3500 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "me::name");
3501 errors++;
3502 }
3503 if (!has_info)
3504 {
3505 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "me::info");
3506 errors++;
3507 }
3508 if (!has_numeric)
3509 {
3510 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
3511 "me::numeric");
3512 errors++;
3513 }
3514 requiredstuff.conf_me = 1;
3515 return errors;
3516 }
3517
3518 /*
3519 * The files {} block
3520 */
_conf_files(ConfigFile * conf,ConfigEntry * ce)3521 int _conf_files(ConfigFile *conf, ConfigEntry *ce)
3522 {
3523 ConfigEntry *cep;
3524
3525 if (!conf_files)
3526 {
3527 conf_files = MyMallocEx(sizeof(ConfigItem_files));
3528
3529 /* set defaults */
3530 conf_files->motd_file = strdup(MPATH);
3531 conf_files->rules_file = strdup(RPATH);
3532 conf_files->smotd_file = strdup(SMPATH);
3533 conf_files->botmotd_file = strdup(BPATH);
3534 conf_files->opermotd_file = strdup(OPATH);
3535 conf_files->svsmotd_file = strdup(VPATH);
3536
3537 conf_files->pid_file = strdup(IRCD_PIDFILE);
3538 conf_files->tune_file = strdup(IRCDTUNE);
3539
3540 /* we let actual files get read in later by the motd caching mechanism */
3541 }
3542 /*
3543 * hack to allow initialization of conf_files (above) when there is no files block in
3544 * CPATH. The caller calls _conf_files(NULL, NULL); to do this. We return here because
3545 * the for loop's initialization of cep would segfault otherwise. We return 1 because
3546 * if config_run() calls us with a NULL ce, it's got a bug...but we can't detect that.
3547 */
3548 if(!ce)
3549 return 1;
3550
3551 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
3552 {
3553 if (!strcmp(cep->ce_varname, "motd"))
3554 ircstrdup(conf_files->motd_file, cep->ce_vardata);
3555 else if (!strcmp(cep->ce_varname, "shortmotd"))
3556 ircstrdup(conf_files->smotd_file, cep->ce_vardata);
3557 else if (!strcmp(cep->ce_varname, "opermotd"))
3558 ircstrdup(conf_files->opermotd_file, cep->ce_vardata);
3559 else if (!strcmp(cep->ce_varname, "svsmotd"))
3560 ircstrdup(conf_files->svsmotd_file, cep->ce_vardata);
3561 else if (!strcmp(cep->ce_varname, "botmotd"))
3562 ircstrdup(conf_files->botmotd_file, cep->ce_vardata);
3563 else if (!strcmp(cep->ce_varname, "rules"))
3564 ircstrdup(conf_files->rules_file, cep->ce_vardata);
3565 else if (!strcmp(cep->ce_varname, "tunefile"))
3566 ircstrdup(conf_files->tune_file, cep->ce_vardata);
3567 else if (!strcmp(cep->ce_varname, "pidfile"))
3568 ircstrdup(conf_files->pid_file, cep->ce_vardata);
3569 }
3570 return 1;
3571 }
3572
_test_files(ConfigFile * conf,ConfigEntry * ce)3573 int _test_files(ConfigFile *conf, ConfigEntry *ce)
3574 {
3575 ConfigEntry *cep;
3576 int errors = 0;
3577 char has_motd = 0, has_smotd = 0, has_rules = 0;
3578 char has_botmotd = 0, has_opermotd = 0, has_svsmotd = 0;
3579 char has_pidfile = 0, has_tunefile = 0;
3580
3581 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
3582 {
3583 /* files::motd */
3584 if (!strcmp(cep->ce_varname, "motd"))
3585 {
3586 if (has_motd)
3587 {
3588 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3589 cep->ce_varlinenum, "files::motd");
3590 continue;
3591 }
3592 config_test_openfile(cep, O_RDONLY, 0, "files::motd", 0, 1);
3593 has_motd = 1;
3594 }
3595 /* files::smotd */
3596 else if (!strcmp(cep->ce_varname, "shortmotd"))
3597 {
3598 if (has_smotd)
3599 {
3600 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3601 cep->ce_varlinenum, "files::shortmotd");
3602 continue;
3603 }
3604 config_test_openfile(cep, O_RDONLY, 0, "files::shortmotd", 0, 1);
3605 has_smotd = 1;
3606 }
3607 /* files::rules */
3608 else if (!strcmp(cep->ce_varname, "rules"))
3609 {
3610 if (has_rules)
3611 {
3612 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3613 cep->ce_varlinenum, "files::rules");
3614 continue;
3615 }
3616 config_test_openfile(cep, O_RDONLY, 0, "files::rules", 0, 1);
3617 has_rules = 1;
3618 }
3619 /* files::botmotd */
3620 else if (!strcmp(cep->ce_varname, "botmotd"))
3621 {
3622 if (has_botmotd)
3623 {
3624 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3625 cep->ce_varlinenum, "files::botmotd");
3626 continue;
3627 }
3628 config_test_openfile(cep, O_RDONLY, 0, "files::botmotd", 0, 1);
3629 has_botmotd = 1;
3630 }
3631 /* files::opermotd */
3632 else if (!strcmp(cep->ce_varname, "opermotd"))
3633 {
3634 if (has_opermotd)
3635 {
3636 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3637 cep->ce_varlinenum, "files::opermotd");
3638 continue;
3639 }
3640 config_test_openfile(cep, O_RDONLY, 0, "files::opermotd", 0, 1);
3641 has_opermotd = 1;
3642 }
3643 /* files::svsmotd
3644 * This config stuff should somehow be inside of modules/m_svsmotd.c!!!... right?
3645 */
3646 else if (!strcmp(cep->ce_varname, "svsmotd"))
3647 {
3648 if (has_svsmotd)
3649 {
3650 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3651 cep->ce_varlinenum, "files::svsmotd");
3652 continue;
3653 }
3654 /* svsmotd can't be a URL because we have to be able to write to it */
3655 config_test_openfile(cep, O_RDONLY, 0, "files::svsmotd", 0, 0);
3656 has_svsmotd = 1;
3657 }
3658 /* files::pidfile */
3659 else if (!strcmp(cep->ce_varname, "pidfile"))
3660 {
3661 if (has_pidfile)
3662 {
3663 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3664 cep->ce_varlinenum, "files::pidfile");
3665 continue;
3666 }
3667
3668 errors += config_test_openfile(cep, O_WRONLY | O_CREAT, 0600, "files::pidfile", 1, 0);
3669 has_pidfile = 1;
3670 }
3671 /* files::tunefile */
3672 else if (!strcmp(cep->ce_varname, "tunefile"))
3673 {
3674 if (has_tunefile)
3675 {
3676 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3677 cep->ce_varlinenum, "files::tunefile");
3678 continue;
3679 }
3680 errors += config_test_openfile(cep, O_RDWR | O_CREAT, 0600, "files::tunefile", 1, 0);
3681 has_tunefile = 1;
3682 }
3683 /* <random directive here> */
3684 else
3685 {
3686 config_error("%s:%d: Unknown directive: \"%s\" in files {}", cep->ce_fileptr->cf_filename,
3687 cep->ce_varlinenum, cep->ce_varname);
3688 errors ++;
3689 }
3690 }
3691 return errors;
3692 }
3693
3694 /*
3695 * The oper {} block parser
3696 */
3697
_conf_oper(ConfigFile * conf,ConfigEntry * ce)3698 int _conf_oper(ConfigFile *conf, ConfigEntry *ce)
3699 {
3700 ConfigEntry *cep;
3701 ConfigEntry *cepp;
3702 ConfigItem_oper *oper = NULL;
3703 ConfigItem_oper_from *from;
3704 OperFlag *ofp = NULL;
3705 struct irc_netmask tmp;
3706
3707 oper = MyMallocEx(sizeof(ConfigItem_oper));
3708 oper->name = strdup(ce->ce_vardata);
3709
3710 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
3711 {
3712 if (!strcmp(cep->ce_varname, "password"))
3713 oper->auth = Auth_ConvertConf2AuthStruct(cep);
3714 else if (!strcmp(cep->ce_varname, "class"))
3715 {
3716 oper->class = Find_class(cep->ce_vardata);
3717 if (!oper->class || (oper->class->flag.temporary == 1))
3718 {
3719 config_status("%s:%i: illegal oper::class, unknown class '%s' using default of class 'default'",
3720 cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
3721 cep->ce_vardata);
3722 oper->class = default_class;
3723 }
3724 }
3725 else if (!strcmp(cep->ce_varname, "flags"))
3726 {
3727 if (!cep->ce_entries)
3728 {
3729 char *m = "*";
3730 int *i, flag;
3731
3732 for (m = (*cep->ce_vardata) ? cep->ce_vardata : m; *m; m++)
3733 {
3734 for (i = _OldOperFlags; (flag = *i); i += 2)
3735 if (*m == (char)(*(i + 1)))
3736 {
3737 oper->oflags |= flag;
3738 break;
3739 }
3740 }
3741 }
3742 else
3743 {
3744 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
3745 {
3746 if ((ofp = config_binary_flags_search(_OperFlags, cepp->ce_varname, ARRAY_SIZEOF(_OperFlags))))
3747 oper->oflags |= ofp->flag;
3748 }
3749 }
3750 }
3751 else if (!strcmp(cep->ce_varname, "swhois"))
3752 {
3753 ircstrdup(oper->swhois, cep->ce_vardata);
3754 }
3755 else if (!strcmp(cep->ce_varname, "snomask"))
3756 {
3757 ircstrdup(oper->snomask, cep->ce_vardata);
3758 }
3759 else if (!strcmp(cep->ce_varname, "modes"))
3760 {
3761 oper->modes = set_usermode(cep->ce_vardata);
3762 }
3763 else if (!strcmp(cep->ce_varname, "require-modes"))
3764 {
3765 oper->require_modes = set_usermode(cep->ce_vardata);
3766 }
3767 else if (!strcmp(cep->ce_varname, "maxlogins"))
3768 {
3769 oper->maxlogins = atoi(cep->ce_vardata);
3770 }
3771 else if (!strcmp(cep->ce_varname, "from"))
3772 {
3773 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
3774 {
3775 if (!strcmp(cepp->ce_varname, "userhost"))
3776 {
3777 from = MyMallocEx(sizeof(ConfigItem_oper_from));
3778 ircstrdup(from->name, cepp->ce_vardata);
3779 tmp.type = parse_netmask(from->name, &tmp);
3780 if (tmp.type != HM_HOST)
3781 {
3782 from->netmask = MyMallocEx(sizeof(struct irc_netmask));
3783 bcopy(&tmp, from->netmask, sizeof(struct irc_netmask));
3784 }
3785 AddListItem(from, oper->from);
3786 }
3787 }
3788 }
3789 }
3790 AddListItem(oper, conf_oper);
3791 return 1;
3792 }
3793
_test_oper(ConfigFile * conf,ConfigEntry * ce)3794 int _test_oper(ConfigFile *conf, ConfigEntry *ce)
3795 {
3796 char has_class = 0, has_password = 0, has_flags = 0, has_swhois = 0, has_snomask = 0;
3797 char has_modes = 0, has_require_modes = 0, has_from = 0, has_maxlogins = 0;
3798 int oper_flags = 0;
3799 ConfigEntry *cep;
3800 ConfigEntry *cepp;
3801 OperFlag *ofp;
3802 int errors = 0;
3803
3804 if (!ce->ce_vardata)
3805 {
3806 config_error_noname(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "oper");
3807 errors++;
3808 }
3809 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
3810 {
3811 if (!cep->ce_varname)
3812 {
3813 config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
3814 "oper");
3815 errors++;
3816 continue;
3817 }
3818 if (!strcmp(cep->ce_varname, "password"))
3819 {
3820 if (has_password)
3821 {
3822 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3823 cep->ce_varlinenum, "oper::password");
3824 continue;
3825 }
3826 has_password = 1;
3827 if (Auth_CheckError(cep) < 0)
3828 errors++;
3829 continue;
3830 }
3831 /* Regular variables */
3832 if (!cep->ce_entries)
3833 {
3834 if (config_is_blankorempty(cep, "oper"))
3835 {
3836 errors++;
3837 continue;
3838 }
3839 /* oper::class */
3840 if (!strcmp(cep->ce_varname, "class"))
3841 {
3842 if (has_class)
3843 {
3844 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3845 cep->ce_varlinenum, "oper::class");
3846 continue;
3847 }
3848 has_class = 1;
3849 }
3850 /* oper::swhois */
3851 else if (!strcmp(cep->ce_varname, "swhois"))
3852 {
3853 if (has_swhois)
3854 {
3855 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3856 cep->ce_varlinenum, "oper::swhois");
3857 continue;
3858 }
3859 has_swhois = 1;
3860 }
3861 /* oper::snomask */
3862 else if (!strcmp(cep->ce_varname, "snomask"))
3863 {
3864 if (has_snomask)
3865 {
3866 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3867 cep->ce_varlinenum, "oper::snomask");
3868 continue;
3869 }
3870 has_snomask = 1;
3871 }
3872 /* oper::modes */
3873 else if (!strcmp(cep->ce_varname, "modes"))
3874 {
3875 char *p;
3876 for (p = cep->ce_vardata; *p; p++)
3877 if (strchr("oOaANCrzS", *p))
3878 {
3879 config_error("%s:%i: oper::modes may not include mode '%c'",
3880 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
3881 errors++;
3882 }
3883 if (has_modes)
3884 {
3885 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3886 cep->ce_varlinenum, "oper::modes");
3887 continue;
3888 }
3889 has_modes = 1;
3890 }
3891 /* oper::require-modes */
3892 else if (!strcmp(cep->ce_varname, "require-modes"))
3893 {
3894 char *p;
3895 for (p = cep->ce_vardata; *p; p++)
3896 if (strchr("oOaANC", *p))
3897 {
3898 config_warn("%s:%i: oper::require-modes probably shouldn't include mode '%c'",
3899 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
3900 }
3901 if (has_require_modes)
3902 {
3903 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3904 cep->ce_varlinenum, "oper::require-modes");
3905 continue;
3906 }
3907 has_require_modes = 1;
3908 }
3909 /* oper::maxlogins */
3910 else if (!strcmp(cep->ce_varname, "maxlogins"))
3911 {
3912 int l;
3913
3914 if (has_maxlogins)
3915 {
3916 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3917 cep->ce_varlinenum, "oper::maxlogins");
3918 continue;
3919 }
3920 has_maxlogins = 1;
3921
3922 l = atoi(cep->ce_vardata);
3923 if ((l < 0) || (l > 5000))
3924 {
3925 config_error("%s:%i: oper::maxlogins: value out of range (%d) should be 0-5000",
3926 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, l);
3927 errors++;
3928 continue;
3929 }
3930 }
3931 /* oper::flags */
3932 else if (!strcmp(cep->ce_varname, "flags"))
3933 {
3934 if (has_flags)
3935 {
3936 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3937 cep->ce_varlinenum, "oper::flags");
3938 continue;
3939 }
3940 has_flags = 1;
3941 }
3942 else
3943 {
3944 config_error_unknown(cep->ce_fileptr->cf_filename,
3945 cep->ce_varlinenum, "oper", cep->ce_varname);
3946 errors++;
3947 continue;
3948 }
3949 }
3950 /* Sections */
3951 else
3952 {
3953 /* oper::flags {} */
3954 if (!strcmp(cep->ce_varname, "flags"))
3955 {
3956 if (has_flags)
3957 {
3958 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3959 cep->ce_varlinenum, "oper::flags");
3960 continue;
3961 }
3962 has_flags = 1;
3963 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
3964 {
3965 if (!cepp->ce_varname)
3966 {
3967 config_error_empty(cepp->ce_fileptr->cf_filename,
3968 cepp->ce_varlinenum, "oper::flags",
3969 cep->ce_varname);
3970 errors++;
3971 continue;
3972 }
3973 if (!(ofp = config_binary_flags_search(_OperFlags, cepp->ce_varname, ARRAY_SIZEOF(_OperFlags)))) {
3974 config_error_unknownflag(cepp->ce_fileptr->cf_filename,
3975 cepp->ce_varlinenum, "oper",
3976 cepp->ce_varname);
3977 errors++;
3978 } else
3979 oper_flags |= ofp->flag;
3980 }
3981 continue;
3982 }
3983 /* oper::from {} */
3984 else if (!strcmp(cep->ce_varname, "from"))
3985 {
3986 if (has_from)
3987 {
3988 config_warn_duplicate(cep->ce_fileptr->cf_filename,
3989 cep->ce_varlinenum, "oper::from");
3990 continue;
3991 }
3992 has_from = 1;
3993 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
3994 {
3995 if (config_is_blankorempty(cepp, "oper::from"))
3996 {
3997 errors++;
3998 continue;
3999 }
4000 /* Unknown Entry */
4001 if (strcmp(cepp->ce_varname, "userhost"))
4002 {
4003 config_error_unknown(cepp->ce_fileptr->cf_filename,
4004 cepp->ce_varlinenum, "oper::from",
4005 cepp->ce_varname);
4006 errors++;
4007 continue;
4008 }
4009 }
4010 continue;
4011 }
4012 else
4013 {
4014 config_error_unknown(cep->ce_fileptr->cf_filename,
4015 cep->ce_varlinenum, "oper", cep->ce_varname);
4016 errors++;
4017 continue;
4018 }
4019 }
4020 }
4021 if (!has_password)
4022 {
4023 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
4024 "oper::password");
4025 errors++;
4026 }
4027 if (!has_from)
4028 {
4029 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
4030 "oper::from");
4031 errors++;
4032 }
4033 if (!has_flags)
4034 {
4035 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
4036 "oper::flags");
4037 errors++;
4038 } else {
4039 /* Check oper flags -- warning needed only (autoconvert) */
4040 if (!(oper_flags & (OFLAG_GROUTE|OFLAG_GKILL|OFLAG_GNOTICE)) &&
4041 (oper_flags & (OFLAG_GZL|OFLAG_TKL|OFLAG_OVERRIDE)))
4042 {
4043 config_warn("%s:%i: oper::oflags: can_gzline/can_gkline/can_override (global privileges) "
4044 "are incompatible with local oper -- user will be globop",
4045 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
4046 }
4047 }
4048 if (!has_class)
4049 {
4050 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
4051 "oper::class");
4052 errors++;
4053 }
4054 return errors;
4055
4056 }
4057
4058 /*
4059 * The class {} block parser
4060 */
_conf_class(ConfigFile * conf,ConfigEntry * ce)4061 int _conf_class(ConfigFile *conf, ConfigEntry *ce)
4062 {
4063 ConfigEntry *cep, *cep2;
4064 ConfigItem_class *class;
4065 unsigned char isnew = 0;
4066
4067 if (!(class = Find_class(ce->ce_vardata)))
4068 {
4069 class = MyMallocEx(sizeof(ConfigItem_class));
4070 ircstrdup(class->name, ce->ce_vardata);
4071 isnew = 1;
4072 }
4073 else
4074 {
4075 isnew = 0;
4076 class->flag.temporary = 0;
4077 class->options = 0; /* RESET OPTIONS */
4078 }
4079 ircstrdup(class->name, ce->ce_vardata);
4080
4081 class->connfreq = 60; /* default */
4082
4083 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
4084 {
4085 if (!strcmp(cep->ce_varname, "pingfreq"))
4086 class->pingfreq = atol(cep->ce_vardata);
4087 else if (!strcmp(cep->ce_varname, "connfreq"))
4088 class->connfreq = atol(cep->ce_vardata);
4089 else if (!strcmp(cep->ce_varname, "maxclients"))
4090 class->maxclients = atol(cep->ce_vardata);
4091 else if (!strcmp(cep->ce_varname, "sendq"))
4092 class->sendq = atol(cep->ce_vardata);
4093 else if (!strcmp(cep->ce_varname, "recvq"))
4094 class->recvq = atol(cep->ce_vardata);
4095 else if (!strcmp(cep->ce_varname, "options"))
4096 {
4097 for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
4098 if (!strcmp(cep2->ce_varname, "nofakelag"))
4099 class->options |= CLASS_OPT_NOFAKELAG;
4100 }
4101 }
4102 if (isnew)
4103 AddListItem(class, conf_class);
4104 return 1;
4105 }
4106
_test_class(ConfigFile * conf,ConfigEntry * ce)4107 int _test_class(ConfigFile *conf, ConfigEntry *ce)
4108 {
4109 ConfigEntry *cep, *cep2;
4110 int errors = 0;
4111 char has_pingfreq = 0, has_connfreq = 0, has_maxclients = 0, has_sendq = 0;
4112 char has_recvq = 0;
4113
4114 if (!ce->ce_vardata)
4115 {
4116 config_error_noname(ce->ce_fileptr->cf_filename, ce->ce_varlinenum, "class");
4117 errors++;
4118 }
4119 if (!strcasecmp(ce->ce_vardata, "default"))
4120 {
4121 config_error("%s:%d: Class cannot be named 'default', this class name is reserved for internal use.",
4122 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
4123 errors++;
4124 }
4125 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
4126 {
4127 if (!strcmp(cep->ce_varname, "options"))
4128 {
4129 for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
4130 {
4131 #ifdef FAKELAG_CONFIGURABLE
4132 if (!strcmp(cep2->ce_varname, "nofakelag"))
4133 ;
4134 else
4135 #endif
4136 {
4137 config_error("%s:%d: Unknown option '%s' in class::options",
4138 cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, cep2->ce_varname);
4139 errors++;
4140 }
4141 }
4142 }
4143 else if (config_is_blankorempty(cep, "class"))
4144 {
4145 errors++;
4146 continue;
4147 }
4148 /* class::pingfreq */
4149 else if (!strcmp(cep->ce_varname, "pingfreq"))
4150 {
4151 int v = atol(cep->ce_vardata);
4152 if (has_pingfreq)
4153 {
4154 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4155 cep->ce_varlinenum, "class::pingfreq");
4156 continue;
4157 }
4158 has_pingfreq = 1;
4159 if ((v < 30) || (v > 600))
4160 {
4161 config_error("%s:%i: class::pingfreq should be a reasonable value (30-600)",
4162 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
4163 errors++;
4164 continue;
4165 }
4166 }
4167 /* class::maxclients */
4168 else if (!strcmp(cep->ce_varname, "maxclients"))
4169 {
4170 long l;
4171 if (has_maxclients)
4172 {
4173 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4174 cep->ce_varlinenum, "class::maxclients");
4175 continue;
4176 }
4177 has_maxclients = 1;
4178 l = atol(cep->ce_vardata);
4179 if ((l < 1) || (l > 1000000))
4180 {
4181 config_error("%s:%i: class::maxclients with illegal value",
4182 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
4183 errors++;
4184 }
4185 }
4186 /* class::connfreq */
4187 else if (!strcmp(cep->ce_varname, "connfreq"))
4188 {
4189 long l;
4190 if (has_connfreq)
4191 {
4192 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4193 cep->ce_varlinenum, "class::connfreq");
4194 continue;
4195 }
4196 has_connfreq = 1;
4197 l = atol(cep->ce_vardata);
4198 if ((l < 10) || (l > 604800))
4199 {
4200 config_error("%s:%i: class::connfreq with illegal value (must be >10 and <7d)",
4201 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
4202 errors++;
4203 }
4204 }
4205 /* class::sendq */
4206 else if (!strcmp(cep->ce_varname, "sendq"))
4207 {
4208 long l;
4209 if (has_sendq)
4210 {
4211 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4212 cep->ce_varlinenum, "class::sendq");
4213 continue;
4214 }
4215 has_sendq = 1;
4216 l = atol(cep->ce_vardata);
4217 if ((l <= 0) || (l > 2000000000))
4218 {
4219 config_error("%s:%i: class::sendq with illegal value",
4220 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
4221 errors++;
4222 }
4223 }
4224 /* class::recvq */
4225 else if (!strcmp(cep->ce_varname, "recvq"))
4226 {
4227 long l;
4228 if (has_recvq)
4229 {
4230 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4231 cep->ce_varlinenum, "class::recvq");
4232 continue;
4233 }
4234 has_recvq = 1;
4235 l = atol(cep->ce_vardata);
4236 if ((l < 512) || (l > 32768))
4237 {
4238 config_error("%s:%i: class::recvq with illegal value (must be >512 and <32k)",
4239 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
4240 errors++;
4241 }
4242 }
4243 /* Unknown */
4244 else
4245 {
4246 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
4247 "class", cep->ce_varname);
4248 errors++;
4249 continue;
4250 }
4251 }
4252 if (!has_pingfreq)
4253 {
4254 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
4255 "class::pingfreq");
4256 errors++;
4257 }
4258 if (!has_maxclients)
4259 {
4260 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
4261 "class::maxclients");
4262 errors++;
4263 }
4264 if (!has_sendq)
4265 {
4266 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
4267 "class::sendq");
4268 errors++;
4269 }
4270
4271 return errors;
4272 }
4273
_conf_drpass(ConfigFile * conf,ConfigEntry * ce)4274 int _conf_drpass(ConfigFile *conf, ConfigEntry *ce)
4275 {
4276 ConfigEntry *cep;
4277
4278 if (!conf_drpass)
4279 {
4280 conf_drpass = MyMallocEx(sizeof(ConfigItem_drpass));
4281 }
4282
4283 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
4284 {
4285 if (!strcmp(cep->ce_varname, "restart"))
4286 {
4287 if (conf_drpass->restartauth)
4288 Auth_DeleteAuthStruct(conf_drpass->restartauth);
4289
4290 conf_drpass->restartauth = Auth_ConvertConf2AuthStruct(cep);
4291 }
4292 else if (!strcmp(cep->ce_varname, "die"))
4293 {
4294 if (conf_drpass->dieauth)
4295 Auth_DeleteAuthStruct(conf_drpass->dieauth);
4296
4297 conf_drpass->dieauth = Auth_ConvertConf2AuthStruct(cep);
4298 }
4299 }
4300 return 1;
4301 }
4302
_test_drpass(ConfigFile * conf,ConfigEntry * ce)4303 int _test_drpass(ConfigFile *conf, ConfigEntry *ce)
4304 {
4305 ConfigEntry *cep;
4306 int errors = 0;
4307 char has_restart = 0, has_die = 0;
4308
4309 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
4310 {
4311 if (config_is_blankorempty(cep, "drpass"))
4312 {
4313 errors++;
4314 continue;
4315 }
4316 /* drpass::restart */
4317 if (!strcmp(cep->ce_varname, "restart"))
4318 {
4319 if (has_restart)
4320 {
4321 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4322 cep->ce_varlinenum, "drpass::restart");
4323 continue;
4324 }
4325 has_restart = 1;
4326 if (Auth_CheckError(cep) < 0)
4327 errors++;
4328 continue;
4329 }
4330 /* drpass::die */
4331 else if (!strcmp(cep->ce_varname, "die"))
4332 {
4333 if (has_die)
4334 {
4335 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4336 cep->ce_varlinenum, "drpass::die");
4337 continue;
4338 }
4339 has_die = 1;
4340 if (Auth_CheckError(cep) < 0)
4341 errors++;
4342 continue;
4343 }
4344 /* Unknown */
4345 else
4346 {
4347 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
4348 "drpass", cep->ce_varname);
4349 errors++;
4350 continue;
4351 }
4352 }
4353 return errors;
4354 }
4355
4356 /*
4357 * The ulines {} block parser
4358 */
_conf_ulines(ConfigFile * conf,ConfigEntry * ce)4359 int _conf_ulines(ConfigFile *conf, ConfigEntry *ce)
4360 {
4361 ConfigEntry *cep;
4362 ConfigItem_ulines *ca;
4363
4364 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
4365 {
4366 ca = MyMallocEx(sizeof(ConfigItem_ulines));
4367 ircstrdup(ca->servername, cep->ce_varname);
4368 AddListItem(ca, conf_ulines);
4369 }
4370 return 1;
4371 }
4372
_test_ulines(ConfigFile * conf,ConfigEntry * ce)4373 int _test_ulines(ConfigFile *conf, ConfigEntry *ce)
4374 {
4375 ConfigEntry *cep;
4376 int errors = 0;
4377 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
4378 {
4379 if (!cep->ce_varname)
4380 {
4381 config_error_blank(cep->ce_fileptr->cf_filename,
4382 cep->ce_varlinenum, "ulines");
4383 errors++;
4384 continue;
4385 }
4386 }
4387 return errors;
4388 }
4389
_conf_tld(ConfigFile * conf,ConfigEntry * ce)4390 int _conf_tld(ConfigFile *conf, ConfigEntry *ce)
4391 {
4392 ConfigEntry *cep;
4393 ConfigItem_tld *ca;
4394
4395 ca = MyMallocEx(sizeof(ConfigItem_tld));
4396
4397 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
4398 {
4399 if (!strcmp(cep->ce_varname, "mask"))
4400 ca->mask = strdup(cep->ce_vardata);
4401 else if (!strcmp(cep->ce_varname, "motd"))
4402 {
4403 ca->motd_file = strdup(cep->ce_vardata);
4404 read_motd(cep->ce_vardata, &ca->motd);
4405 }
4406 else if (!strcmp(cep->ce_varname, "shortmotd"))
4407 {
4408 ca->smotd_file = strdup(cep->ce_vardata);
4409 read_motd(cep->ce_vardata, &ca->smotd);
4410 }
4411 else if (!strcmp(cep->ce_varname, "opermotd"))
4412 {
4413 ca->opermotd_file = strdup(cep->ce_vardata);
4414 read_motd(cep->ce_vardata, &ca->opermotd);
4415 }
4416 else if (!strcmp(cep->ce_varname, "botmotd"))
4417 {
4418 ca->botmotd_file = strdup(cep->ce_vardata);
4419 read_motd(cep->ce_vardata, &ca->botmotd);
4420 }
4421 else if (!strcmp(cep->ce_varname, "rules"))
4422 {
4423 ca->rules_file = strdup(cep->ce_vardata);
4424 read_motd(cep->ce_vardata, &ca->rules);
4425 }
4426 else if (!strcmp(cep->ce_varname, "options"))
4427 {
4428 ConfigEntry *cepp;
4429 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
4430 {
4431 if (!strcmp(cepp->ce_varname, "ssl"))
4432 ca->options |= TLD_SSL;
4433 else if (!strcmp(cepp->ce_varname, "remote"))
4434 ca->options |= TLD_REMOTE;
4435 }
4436 }
4437 else if (!strcmp(cep->ce_varname, "channel"))
4438 ca->channel = strdup(cep->ce_vardata);
4439 }
4440 AddListItem(ca, conf_tld);
4441 return 1;
4442 }
4443
_test_tld(ConfigFile * conf,ConfigEntry * ce)4444 int _test_tld(ConfigFile *conf, ConfigEntry *ce)
4445 {
4446 ConfigEntry *cep;
4447 int errors = 0;
4448 int fd = -1;
4449 char has_mask = 0, has_motd = 0, has_rules = 0, has_shortmotd = 0, has_channel = 0;
4450 char has_opermotd = 0, has_botmotd = 0, has_options = 0;
4451
4452 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
4453 {
4454 if (!cep->ce_varname)
4455 {
4456 config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
4457 "tld");
4458 errors++;
4459 continue;
4460 }
4461 if (!cep->ce_vardata && strcmp(cep->ce_varname, "options"))
4462 {
4463 config_error_empty(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
4464 "tld", cep->ce_varname);
4465 errors++;
4466 continue;
4467 }
4468 /* tld::mask */
4469 if (!strcmp(cep->ce_varname, "mask"))
4470 {
4471 if (has_mask)
4472 {
4473 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4474 cep->ce_varlinenum, "tld::mask");
4475 continue;
4476 }
4477 has_mask = 1;
4478 }
4479 /* tld::motd */
4480 else if (!strcmp(cep->ce_varname, "motd"))
4481 {
4482 if (has_motd)
4483 {
4484 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4485 cep->ce_varlinenum, "tld::motd");
4486 continue;
4487 }
4488 has_motd = 1;
4489 if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
4490 {
4491 config_error("%s:%i: tld::motd: %s: %s",
4492 cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
4493 cep->ce_vardata, strerror(errno));
4494 errors++;
4495 }
4496 else
4497 close(fd);
4498 }
4499 /* tld::rules */
4500 else if (!strcmp(cep->ce_varname, "rules"))
4501 {
4502 if (has_rules)
4503 {
4504 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4505 cep->ce_varlinenum, "tld::rules");
4506 continue;
4507 }
4508 has_rules = 1;
4509 if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
4510 {
4511 config_error("%s:%i: tld::rules: %s: %s",
4512 cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
4513 cep->ce_vardata, strerror(errno));
4514 errors++;
4515 }
4516 else
4517 close(fd);
4518 }
4519 /* tld::channel */
4520 else if (!strcmp(cep->ce_varname, "channel"))
4521 {
4522 if (has_channel)
4523 {
4524 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4525 cep->ce_varlinenum, "tld::channel");
4526 continue;
4527 }
4528 has_channel = 1;
4529 }
4530 /* tld::shortmotd */
4531 else if (!strcmp(cep->ce_varname, "shortmotd"))
4532 {
4533 if (has_shortmotd)
4534 {
4535 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4536 cep->ce_varlinenum, "tld::shortmotd");
4537 continue;
4538 }
4539 has_shortmotd = 1;
4540 if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
4541 {
4542 config_error("%s:%i: tld::shortmotd: %s: %s",
4543 cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
4544 cep->ce_vardata, strerror(errno));
4545 errors++;
4546 }
4547 else
4548 close(fd);
4549 }
4550 /* tld::opermotd */
4551 else if (!strcmp(cep->ce_varname, "opermotd"))
4552 {
4553 if (has_opermotd)
4554 {
4555 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4556 cep->ce_varlinenum, "tld::opermotd");
4557 continue;
4558 }
4559 has_opermotd = 1;
4560 if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
4561 {
4562 config_error("%s:%i: tld::opermotd: %s: %s",
4563 cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
4564 cep->ce_vardata, strerror(errno));
4565 errors++;
4566 }
4567 else
4568 close(fd);
4569 }
4570 /* tld::botmotd */
4571 else if (!strcmp(cep->ce_varname, "botmotd"))
4572 {
4573 if (has_botmotd)
4574 {
4575 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4576 cep->ce_varlinenum, "tld::botmotd");
4577 continue;
4578 }
4579 has_botmotd = 1;
4580 if (((fd = open(cep->ce_vardata, O_RDONLY)) == -1))
4581 {
4582 config_error("%s:%i: tld::botmotd: %s: %s",
4583 cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
4584 cep->ce_vardata, strerror(errno));
4585 errors++;
4586 }
4587 else
4588 close(fd);
4589 }
4590 /* tld::options */
4591 else if (!strcmp(cep->ce_varname, "options")) {
4592 ConfigEntry *cep2;
4593
4594 if (has_options)
4595 {
4596 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4597 cep->ce_varlinenum, "tld::options");
4598 continue;
4599 }
4600 has_options = 1;
4601
4602 for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
4603 {
4604 if (!cep2->ce_varname)
4605 {
4606 config_error_blank(cep2->ce_fileptr->cf_filename,
4607 cep2->ce_varlinenum, "tld::options");
4608 continue;
4609 }
4610 if (strcmp(cep2->ce_varname, "ssl") &&
4611 strcmp(cep2->ce_varname, "remote"))
4612 {
4613 config_error_unknownopt(cep2->ce_fileptr->cf_filename,
4614 cep2->ce_varlinenum, "tld", cep2->ce_varname);
4615 errors++;
4616 }
4617 }
4618 }
4619 else
4620 {
4621 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
4622 "tld", cep->ce_varname);
4623 errors++;
4624 continue;
4625 }
4626 }
4627 if (!has_mask)
4628 {
4629 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
4630 "tld::mask");
4631 errors++;
4632 }
4633 if (!has_motd)
4634 {
4635 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
4636 "tld::motd");
4637 errors++;
4638 }
4639 if (!has_rules)
4640 {
4641 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
4642 "tld::rules");
4643 errors++;
4644 }
4645 return errors;
4646 }
4647
_conf_listen(ConfigFile * conf,ConfigEntry * ce)4648 int _conf_listen(ConfigFile *conf, ConfigEntry *ce)
4649 {
4650 ConfigEntry *cep;
4651 ConfigEntry *cepp;
4652 ConfigItem_listen *listen = NULL;
4653 OperFlag *ofp;
4654 char copy[256];
4655 char *ip;
4656 char *port;
4657 int start, end, iport, isnew;
4658 int tmpflags =0;
4659
4660 strcpy(copy, ce->ce_vardata);
4661 /* Seriously cheap hack to make listen <port> work -Stskeeps */
4662 ipport_seperate(copy, &ip, &port);
4663 if (!ip || !*ip)
4664 {
4665 return -1;
4666 }
4667 if (strchr(ip, '*') && strcmp(ip, "*"))
4668 {
4669 return -1;
4670 }
4671 if (!port || !*port)
4672 {
4673 return -1;
4674 }
4675 port_range(port, &start, &end);
4676 if ((start < 0) || (start > 65535) || (end < 0) || (end > 65535))
4677 {
4678 return -1;
4679 }
4680 end++;
4681 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
4682 {
4683 if (!strcmp(cep->ce_varname, "options"))
4684 {
4685 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
4686 {
4687 if ((ofp = config_binary_flags_search(_ListenerFlags, cepp->ce_varname, ARRAY_SIZEOF(_ListenerFlags))))
4688 tmpflags |= ofp->flag;
4689 }
4690 }
4691 }
4692 #ifndef USE_SSL
4693 tmpflags &= ~LISTENER_SSL;
4694 #endif
4695 for (iport = start; iport < end; iport++)
4696 {
4697 if (!(listen = Find_listen(ip, iport)))
4698 {
4699 listen = MyMallocEx(sizeof(ConfigItem_listen));
4700 listen->ip = strdup(ip);
4701 listen->port = iport;
4702 isnew = 1;
4703 } else
4704 isnew = 0;
4705
4706 if (listen->options & LISTENER_BOUND)
4707 tmpflags |= LISTENER_BOUND;
4708
4709 listen->options = tmpflags;
4710 if (isnew)
4711 AddListItem(listen, conf_listen);
4712 listen->flag.temporary = 0;
4713 }
4714 return 1;
4715 }
4716
_test_listen(ConfigFile * conf,ConfigEntry * ce)4717 int _test_listen(ConfigFile *conf, ConfigEntry *ce)
4718 {
4719 ConfigEntry *cep;
4720 ConfigEntry *cepp;
4721 char copy[256];
4722 char *ip;
4723 char *port;
4724 int start, end;
4725 int errors = 0;
4726 char has_options = 0;
4727 OperFlag *ofp;
4728
4729 if (!ce->ce_vardata)
4730 {
4731 config_error("%s:%i: listen without ip:port",
4732 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
4733 return 1;
4734 }
4735
4736 strcpy(copy, ce->ce_vardata);
4737 /* Seriously cheap hack to make listen <port> work -Stskeeps */
4738 ipport_seperate(copy, &ip, &port);
4739 if (!ip || !*ip)
4740 {
4741 config_error("%s:%i: listen: illegal ip:port mask",
4742 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
4743 return 1;
4744 }
4745 if (strchr(ip, '*') && strcmp(ip, "*"))
4746 {
4747 config_error("%s:%i: listen: illegal ip, (mask, and not '*')",
4748 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
4749 return 1;
4750 }
4751 if (!port || !*port)
4752 {
4753 config_error("%s:%i: listen: missing port in mask",
4754 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
4755 return 1;
4756 }
4757 #ifdef INET6
4758 if ((strlen(ip) > 6) && !strchr(ip, ':') && isdigit(ip[strlen(ip)-1]))
4759 {
4760 char crap[32];
4761 if (inet_pton(AF_INET, ip, crap) != 0)
4762 {
4763 char ipv6buf[128];
4764 snprintf(ipv6buf, sizeof(ipv6buf), "[::ffff:%s]:%s", ip, port);
4765 ce->ce_vardata = strdup(ipv6buf);
4766 } else {
4767 /* Insert IPv6 validation here */
4768 config_error("%s:%i: listen: '%s' looks like it might be IPv4, but is not a valid address.",
4769 ce->ce_fileptr->cf_filename, ce->ce_varlinenum, ip);
4770 return 1;
4771 }
4772 }
4773 #endif
4774 port_range(port, &start, &end);
4775 if (start == end)
4776 {
4777 if ((start < 0) || (start > 65535))
4778 {
4779 config_error("%s:%i: listen: illegal port (must be 0..65535)",
4780 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
4781 return 1;
4782 }
4783 }
4784 else
4785 {
4786 if (end < start)
4787 {
4788 config_error("%s:%i: listen: illegal port range end value is less than starting value",
4789 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
4790 return 1;
4791 }
4792 if (end - start >= 100)
4793 {
4794 config_error("%s:%i: listen: you requested port %d-%d, that's %d ports "
4795 "(and thus consumes %d sockets) this is probably not what you want.",
4796 ce->ce_fileptr->cf_filename, ce->ce_varlinenum, start, end,
4797 end - start + 1, end - start + 1);
4798 return 1;
4799 }
4800 if ((start < 0) || (start > 65535) || (end < 0) || (end > 65535))
4801 {
4802 config_error("%s:%i: listen: illegal port range values must be between 0 and 65535",
4803 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
4804 return 1;
4805 }
4806 }
4807 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
4808 {
4809 if (!cep->ce_varname)
4810 {
4811 config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
4812 "listen");
4813 errors++;
4814 continue;
4815 }
4816 if (!strcmp(cep->ce_varname, "options"))
4817 {
4818 if (has_options)
4819 {
4820 config_warn_duplicate(cep->ce_fileptr->cf_filename,
4821 cep->ce_varlinenum, "listen::options");
4822 continue;
4823 }
4824 has_options = 1;
4825 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
4826 {
4827 if (!cepp->ce_varname)
4828 {
4829 config_error_blank(cepp->ce_fileptr->cf_filename,
4830 cepp->ce_varlinenum, "listen::options");
4831 errors++;
4832 continue;
4833 }
4834 if (!(ofp = config_binary_flags_search(_ListenerFlags, cepp->ce_varname, ARRAY_SIZEOF(_ListenerFlags))))
4835 {
4836 config_error_unknownopt(cepp->ce_fileptr->cf_filename,
4837 cepp->ce_varlinenum, "class", cepp->ce_varname);
4838 errors++;
4839 continue;
4840 }
4841 #ifndef USE_SSL
4842 else if (ofp->flag & LISTENER_SSL)
4843 {
4844 config_warn("%s:%i: listen with SSL flag enabled on a non SSL compile",
4845 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
4846 }
4847 #endif
4848 }
4849 }
4850 else
4851 {
4852 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
4853 "listen", cep->ce_varname);
4854 errors++;
4855 continue;
4856 }
4857
4858 }
4859 requiredstuff.conf_listen = 1;
4860 return errors;
4861 }
4862
4863
_conf_allow(ConfigFile * conf,ConfigEntry * ce)4864 int _conf_allow(ConfigFile *conf, ConfigEntry *ce)
4865 {
4866 ConfigEntry *cep, *cepp;
4867 ConfigItem_allow *allow;
4868 Hook *h;
4869 struct irc_netmask tmp;
4870 if (ce->ce_vardata)
4871 {
4872 if (!strcmp(ce->ce_vardata, "channel"))
4873 return (_conf_allow_channel(conf, ce));
4874 else if (!strcmp(ce->ce_vardata, "dcc"))
4875 return (_conf_allow_dcc(conf, ce));
4876 else
4877 {
4878 int value;
4879 for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
4880 {
4881 value = (*(h->func.intfunc))(conf,ce,CONFIG_ALLOW);
4882 if (value == 1)
4883 break;
4884 }
4885 return 0;
4886 }
4887 }
4888 allow = MyMallocEx(sizeof(ConfigItem_allow));
4889
4890 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
4891 {
4892 if (!strcmp(cep->ce_varname, "ip"))
4893 {
4894 allow->ip = strdup(cep->ce_vardata);
4895 /* CIDR */
4896 tmp.type = parse_netmask(allow->ip, &tmp);
4897 if (tmp.type != HM_HOST)
4898 {
4899 allow->netmask = MyMallocEx(sizeof(struct irc_netmask));
4900 bcopy(&tmp, allow->netmask, sizeof(struct irc_netmask));
4901 }
4902 }
4903 else if (!strcmp(cep->ce_varname, "hostname"))
4904 allow->hostname = strdup(cep->ce_vardata);
4905 else if (!strcmp(cep->ce_varname, "password"))
4906 allow->auth = Auth_ConvertConf2AuthStruct(cep);
4907 else if (!strcmp(cep->ce_varname, "class"))
4908 {
4909 allow->class = Find_class(cep->ce_vardata);
4910 if (!allow->class || (allow->class->flag.temporary == 1))
4911 {
4912 config_status("%s:%i: illegal allow::class, unknown class '%s' using default of class 'default'",
4913 cep->ce_fileptr->cf_filename,
4914 cep->ce_varlinenum,
4915 cep->ce_vardata);
4916 allow->class = default_class;
4917 }
4918 }
4919 else if (!strcmp(cep->ce_varname, "maxperip"))
4920 allow->maxperip = atoi(cep->ce_vardata);
4921 else if (!strcmp(cep->ce_varname, "redirect-server"))
4922 allow->server = strdup(cep->ce_vardata);
4923 else if (!strcmp(cep->ce_varname, "redirect-port"))
4924 allow->port = atoi(cep->ce_vardata);
4925 else if (!strcmp(cep->ce_varname, "ipv6-clone-mask"))
4926 {
4927 #ifdef INET6
4928 /*
4929 * If this item isn't set explicitly by the
4930 * user, the value will temporarily be
4931 * zero. Defaults are applied in config_run().
4932 */
4933 allow->ipv6_clone_mask = atoi(cep->ce_vardata);
4934 #endif /* INET6 */
4935 }
4936 else if (!strcmp(cep->ce_varname, "options"))
4937 {
4938 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
4939 {
4940 if (!strcmp(cepp->ce_varname, "noident"))
4941 allow->flags.noident = 1;
4942 else if (!strcmp(cepp->ce_varname, "useip"))
4943 allow->flags.useip = 1;
4944 else if (!strcmp(cepp->ce_varname, "ssl"))
4945 allow->flags.ssl = 1;
4946 else if (!strcmp(cepp->ce_varname, "nopasscont"))
4947 allow->flags.nopasscont = 1;
4948 }
4949 }
4950 }
4951 AddListItem(allow, conf_allow);
4952 return 1;
4953 }
4954
_test_allow(ConfigFile * conf,ConfigEntry * ce)4955 int _test_allow(ConfigFile *conf, ConfigEntry *ce)
4956 {
4957 ConfigEntry *cep, *cepp;
4958 int errors = 0;
4959 Hook *h;
4960 char has_ip = 0, has_hostname = 0, has_maxperip = 0, has_password = 0, has_class = 0;
4961 char has_redirectserver = 0, has_redirectport = 0, has_options = 0;
4962
4963 if (ce->ce_vardata)
4964 {
4965 if (!strcmp(ce->ce_vardata, "channel"))
4966 return (_test_allow_channel(conf, ce));
4967 else if (!strcmp(ce->ce_vardata, "dcc"))
4968 return (_test_allow_dcc(conf, ce));
4969 else
4970 {
4971 int used = 0;
4972 for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
4973 {
4974 int value, errs = 0;
4975 if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
4976 && !(h->owner->options & MOD_OPT_PERM))
4977 continue;
4978 value = (*(h->func.intfunc))(conf,ce,CONFIG_ALLOW,&errs);
4979 if (value == 2)
4980 used = 1;
4981 if (value == 1)
4982 {
4983 used = 1;
4984 break;
4985 }
4986 if (value == -1)
4987 {
4988 used = 1;
4989 errors += errs;
4990 break;
4991 }
4992 if (value == -2)
4993 {
4994 used = 1;
4995 errors += errs;
4996 }
4997 }
4998 if (!used) {
4999 config_error("%s:%i: allow item with unknown type",
5000 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
5001 return 1;
5002 }
5003 return errors;
5004 }
5005 }
5006
5007 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5008 {
5009 if (strcmp(cep->ce_varname, "options") && config_is_blankorempty(cep, "allow"))
5010 {
5011 errors++;
5012 continue;
5013 }
5014 if (!strcmp(cep->ce_varname, "ip"))
5015 {
5016 if (has_ip)
5017 {
5018 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5019 cep->ce_varlinenum, "allow::ip");
5020 continue;
5021 }
5022 has_ip = 1;
5023 }
5024 else if (!strcmp(cep->ce_varname, "maxperip"))
5025 {
5026 int v = atoi(cep->ce_vardata);
5027 if (has_maxperip)
5028 {
5029 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5030 cep->ce_varlinenum, "allow::maxperip");
5031 continue;
5032 }
5033 has_maxperip = 1;
5034 if ((v <= 0) || (v > 65535))
5035 {
5036 config_error("%s:%i: allow::maxperip with illegal value (must be 1-65535)",
5037 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
5038 errors++;
5039 }
5040 }
5041 else if (!strcmp(cep->ce_varname, "ipv6-clone-mask"))
5042 {
5043 /* keep this in sync with _test_set() */
5044 int ipv6mask;
5045 ipv6mask = atoi(cep->ce_vardata);
5046 if (ipv6mask == 0)
5047 {
5048 config_error("%s:%d: allow::ipv6-clone-mask given a value of zero. This cannnot be correct, as it would treat all IPv6 hosts as one host.",
5049 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
5050 errors++;
5051 }
5052 if (ipv6mask > 128)
5053 {
5054 config_error("%s:%d: set::default-ipv6-clone-mask was set to %d. The maximum value is 128.",
5055 cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
5056 ipv6mask);
5057 errors++;
5058 }
5059 if (ipv6mask <= 32)
5060 {
5061 config_warn("%s:%d: allow::ipv6-clone-mask was given a very small value.",
5062 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
5063 }
5064 }
5065 else if (!strcmp(cep->ce_varname, "hostname"))
5066 {
5067 if (has_hostname)
5068 {
5069 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5070 cep->ce_varlinenum, "allow::hostname");
5071 continue;
5072 }
5073 has_hostname = 1;
5074 }
5075 else if (!strcmp(cep->ce_varname, "password"))
5076 {
5077 if (has_password)
5078 {
5079 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5080 cep->ce_varlinenum, "allow::password");
5081 continue;
5082 }
5083 has_password = 1;
5084 /* some auth check stuff? */
5085 if (Auth_CheckError(cep) < 0)
5086 errors++;
5087 }
5088 else if (!strcmp(cep->ce_varname, "class"))
5089 {
5090 if (has_class)
5091 {
5092 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5093 cep->ce_varlinenum, "allow::class");
5094 continue;
5095 }
5096 has_class = 1;
5097 }
5098 else if (!strcmp(cep->ce_varname, "redirect-server"))
5099 {
5100 if (has_redirectserver)
5101 {
5102 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5103 cep->ce_varlinenum, "allow::redirect-server");
5104 continue;
5105 }
5106 has_redirectserver = 1;
5107 }
5108 else if (!strcmp(cep->ce_varname, "redirect-port"))
5109 {
5110 if (has_redirectport)
5111 {
5112 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5113 cep->ce_varlinenum, "allow::redirect-port");
5114 continue;
5115 }
5116 has_redirectport = 1;
5117 }
5118 else if (!strcmp(cep->ce_varname, "options"))
5119 {
5120 if (has_options)
5121 {
5122 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5123 cep->ce_varlinenum, "allow::options");
5124 continue;
5125 }
5126 has_options = 1;
5127 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
5128 {
5129 if (!strcmp(cepp->ce_varname, "noident"))
5130 {}
5131 else if (!strcmp(cepp->ce_varname, "useip"))
5132 {}
5133 else if (!strcmp(cepp->ce_varname, "ssl"))
5134 {}
5135 else if (!strcmp(cepp->ce_varname, "nopasscont"))
5136 {}
5137 else
5138 {
5139 config_error_unknownopt(cepp->ce_fileptr->cf_filename,
5140 cepp->ce_varlinenum, "allow", cepp->ce_varname);
5141 errors++;
5142 }
5143 }
5144 }
5145 else
5146 {
5147 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
5148 "allow", cep->ce_varname);
5149 errors++;
5150 continue;
5151 }
5152 }
5153 if (!has_ip)
5154 {
5155 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
5156 "allow::ip");
5157 errors++;
5158 }
5159 if (!has_hostname)
5160 {
5161 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
5162 "allow::hostname");
5163 errors++;
5164 }
5165 if (!has_class)
5166 {
5167 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
5168 "allow::class");
5169 errors++;
5170 }
5171 return errors;
5172 }
5173
_conf_allow_channel(ConfigFile * conf,ConfigEntry * ce)5174 int _conf_allow_channel(ConfigFile *conf, ConfigEntry *ce)
5175 {
5176 ConfigItem_allow_channel *allow = NULL;
5177 ConfigEntry *cep;
5178 char *class = NULL;
5179
5180 /* First, search for ::class, if any */
5181 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5182 {
5183 if (!strcmp(cep->ce_varname, "class"))
5184 class = cep->ce_vardata;
5185 }
5186
5187 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5188 {
5189 if (!strcmp(cep->ce_varname, "channel"))
5190 {
5191 /* This way, we permit multiple ::channel items in one allow block */
5192 allow = MyMallocEx(sizeof(ConfigItem_allow_channel));
5193 ircstrdup(allow->channel, cep->ce_vardata);
5194 if (class)
5195 ircstrdup(allow->class, class);
5196 AddListItem(allow, conf_allow_channel);
5197 }
5198 }
5199 return 1;
5200 }
5201
_test_allow_channel(ConfigFile * conf,ConfigEntry * ce)5202 int _test_allow_channel(ConfigFile *conf, ConfigEntry *ce)
5203 {
5204 ConfigEntry *cep;
5205 int errors = 0;
5206 char has_channel = 0, has_class = 0;
5207 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5208 {
5209 if (config_is_blankorempty(cep, "allow channel"))
5210 {
5211 errors++;
5212 continue;
5213 }
5214
5215 if (!strcmp(cep->ce_varname, "channel"))
5216 {
5217 has_channel = 1;
5218 }
5219 else if (!strcmp(cep->ce_varname, "class"))
5220 {
5221
5222 if (has_class)
5223 {
5224 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5225 cep->ce_varlinenum, "allow channel::class");
5226 continue;
5227 }
5228 has_class = 1;
5229 }
5230 else
5231 {
5232 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
5233 "allow channel", cep->ce_varname);
5234 errors++;
5235 }
5236 }
5237 if (!has_channel)
5238 {
5239 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
5240 "allow channel::channel");
5241 errors++;
5242 }
5243 return errors;
5244 }
5245
_conf_allow_dcc(ConfigFile * conf,ConfigEntry * ce)5246 int _conf_allow_dcc(ConfigFile *conf, ConfigEntry *ce)
5247 {
5248 ConfigItem_allow_dcc *allow = NULL;
5249 ConfigEntry *cep;
5250
5251 allow = MyMallocEx(sizeof(ConfigItem_allow_dcc));
5252
5253 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5254 {
5255 if (!strcmp(cep->ce_varname, "filename"))
5256 ircstrdup(allow->filename, cep->ce_vardata);
5257 else if (!strcmp(cep->ce_varname, "soft"))
5258 {
5259 int x = config_checkval(cep->ce_vardata,CFG_YESNO);
5260 if (x)
5261 allow->flag.type = DCCDENY_SOFT;
5262 }
5263 }
5264 AddListItem(allow, conf_allow_dcc);
5265 return 1;
5266 }
5267
_test_allow_dcc(ConfigFile * conf,ConfigEntry * ce)5268 int _test_allow_dcc(ConfigFile *conf, ConfigEntry *ce)
5269 {
5270 ConfigEntry *cep;
5271 int errors = 0, has_filename = 0, has_soft = 0;
5272
5273 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5274 {
5275 if (config_is_blankorempty(cep, "allow dcc"))
5276 {
5277 errors++;
5278 continue;
5279 }
5280 if (!strcmp(cep->ce_varname, "filename"))
5281 {
5282 if (has_filename)
5283 {
5284 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5285 cep->ce_varlinenum, "allow dcc::filename");
5286 continue;
5287 }
5288 has_filename = 1;
5289 }
5290 else if (!strcmp(cep->ce_varname, "soft"))
5291 {
5292 if (has_soft)
5293 {
5294 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5295 cep->ce_varlinenum, "allow dcc::soft");
5296 continue;
5297 }
5298 has_soft = 1;
5299 }
5300 else
5301 {
5302 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
5303 "allow dcc", cep->ce_varname);
5304 errors++;
5305 }
5306 }
5307 if (!has_filename)
5308 {
5309 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
5310 "allow dcc::filename");
5311 errors++;
5312 }
5313 return errors;
5314 }
5315
create_tkl_except_ii(char * mask,char * type)5316 void create_tkl_except_ii(char *mask, char *type)
5317 {
5318 ConfigItem_except *ca;
5319 struct irc_netmask tmp;
5320 OperFlag *opf;
5321 ca = MyMallocEx(sizeof(ConfigItem_except));
5322 ca->mask = strdup(mask);
5323
5324 opf = config_binary_flags_search(ExceptTklFlags, type, ARRAY_SIZEOF(ExceptTklFlags));
5325 ca->type = opf->flag;
5326
5327 if (ca->type & TKL_KILL || ca->type & TKL_ZAP || ca->type & TKL_SHUN)
5328 {
5329 tmp.type = parse_netmask(ca->mask, &tmp);
5330 if (tmp.type != HM_HOST)
5331 {
5332 ca->netmask = MyMallocEx(sizeof(struct irc_netmask));
5333 bcopy(&tmp, ca->netmask, sizeof(struct irc_netmask));
5334 }
5335 }
5336 ca->flag.type = CONF_EXCEPT_TKL;
5337 AddListItem(ca, conf_except);
5338 }
5339
create_tkl_except(char * mask,char * type)5340 void create_tkl_except(char *mask, char *type)
5341 {
5342 if (!strcmp(type, "all"))
5343 {
5344 /* Special treatment */
5345 int i;
5346 for (i = 0; i < ARRAY_SIZEOF(ExceptTklFlags); i++)
5347 if (ExceptTklFlags[i].flag)
5348 create_tkl_except_ii(mask, ExceptTklFlags[i].name);
5349 }
5350 else
5351 create_tkl_except_ii(mask, type);
5352 }
5353
_conf_except(ConfigFile * conf,ConfigEntry * ce)5354 int _conf_except(ConfigFile *conf, ConfigEntry *ce)
5355 {
5356
5357 ConfigEntry *cep;
5358 ConfigItem_except *ca;
5359 Hook *h;
5360 struct irc_netmask tmp;
5361
5362 if (!strcmp(ce->ce_vardata, "ban")) {
5363 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5364 {
5365 if (!strcmp(cep->ce_varname, "mask")) {
5366 ca = MyMallocEx(sizeof(ConfigItem_except));
5367 ca->mask = strdup(cep->ce_vardata);
5368 tmp.type = parse_netmask(ca->mask, &tmp);
5369 if (tmp.type != HM_HOST)
5370 {
5371 ca->netmask = MyMallocEx(sizeof(struct irc_netmask));
5372 bcopy(&tmp, ca->netmask, sizeof(struct irc_netmask));
5373 }
5374 ca->flag.type = CONF_EXCEPT_BAN;
5375 AddListItem(ca, conf_except);
5376 }
5377 else {
5378 }
5379 }
5380 }
5381 #ifdef THROTTLING
5382 else if (!strcmp(ce->ce_vardata, "throttle")) {
5383 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5384 {
5385 if (!strcmp(cep->ce_varname, "mask")) {
5386 ca = MyMallocEx(sizeof(ConfigItem_except));
5387 ca->mask = strdup(cep->ce_vardata);
5388 tmp.type = parse_netmask(ca->mask, &tmp);
5389 if (tmp.type != HM_HOST)
5390 {
5391 ca->netmask = MyMallocEx(sizeof(struct irc_netmask));
5392 bcopy(&tmp, ca->netmask, sizeof(struct irc_netmask));
5393 }
5394 ca->flag.type = CONF_EXCEPT_THROTTLE;
5395 AddListItem(ca, conf_except);
5396 }
5397 else {
5398 }
5399 }
5400
5401 }
5402 #endif
5403 else if (!strcmp(ce->ce_vardata, "tkl")) {
5404 ConfigEntry *mask = NULL, *type = NULL;
5405 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5406 {
5407 if (!strcmp(cep->ce_varname, "mask"))
5408 mask = cep;
5409 else if (!strcmp(cep->ce_varname, "type"))
5410 type = cep;
5411 }
5412 if (type->ce_vardata)
5413 create_tkl_except(mask->ce_vardata, type->ce_vardata);
5414 else
5415 {
5416 ConfigEntry *cepp;
5417 for (cepp = type->ce_entries; cepp; cepp = cepp->ce_next)
5418 create_tkl_except(mask->ce_vardata, cepp->ce_varname);
5419 }
5420 }
5421 else {
5422 int value;
5423 for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
5424 {
5425 value = (*(h->func.intfunc))(conf,ce,CONFIG_EXCEPT);
5426 if (value == 1)
5427 break;
5428 }
5429 }
5430 return 1;
5431 }
5432
_test_except(ConfigFile * conf,ConfigEntry * ce)5433 int _test_except(ConfigFile *conf, ConfigEntry *ce)
5434 {
5435 ConfigEntry *cep;
5436 int errors = 0;
5437 Hook *h;
5438 char has_mask = 0;
5439
5440 if (!ce->ce_vardata)
5441 {
5442 config_error("%s:%i: except without type",
5443 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
5444 return 1;
5445 }
5446
5447 if (!strcmp(ce->ce_vardata, "ban"))
5448 {
5449 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5450 {
5451 if (config_is_blankorempty(cep, "except ban"))
5452 {
5453 errors++;
5454 continue;
5455 }
5456 if (!strcmp(cep->ce_varname, "mask"))
5457 {
5458 if (has_mask)
5459 {
5460 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5461 cep->ce_varlinenum, "except ban::mask");
5462 continue;
5463 }
5464 has_mask = 1;
5465 }
5466 else
5467 {
5468 config_error_unknown(cep->ce_fileptr->cf_filename,
5469 cep->ce_varlinenum, "except ban", cep->ce_varname);
5470 errors++;
5471 continue;
5472 }
5473 }
5474 if (!has_mask)
5475 {
5476 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
5477 "except ban::mask");
5478 errors++;
5479 }
5480 return errors;
5481 }
5482 #ifdef THROTTLING
5483 else if (!strcmp(ce->ce_vardata, "throttle")) {
5484 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5485 {
5486 if (config_is_blankorempty(cep, "except throttle"))
5487 {
5488 errors++;
5489 continue;
5490 }
5491 if (!strcmp(cep->ce_varname, "mask"))
5492 {
5493 if (has_mask)
5494 {
5495 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5496 cep->ce_varlinenum, "except throttle::mask");
5497 continue;
5498 }
5499 has_mask = 1;
5500 }
5501 else
5502 {
5503 config_error_unknown(cep->ce_fileptr->cf_filename,
5504 cep->ce_varlinenum, "except throttle", cep->ce_varname);
5505 errors++;
5506 continue;
5507 }
5508 }
5509 if (!has_mask)
5510 {
5511 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
5512 "except throttle::mask");
5513 errors++;
5514 }
5515 return errors;
5516 }
5517 #endif
5518 else if (!strcmp(ce->ce_vardata, "tkl")) {
5519 char has_type = 0;
5520
5521 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5522 {
5523 if (!cep->ce_varname)
5524 {
5525 config_error_blank(cep->ce_fileptr->cf_filename,
5526 cep->ce_varlinenum, "except tkl");
5527 errors++;
5528 continue;
5529 }
5530 if (!strcmp(cep->ce_varname, "mask"))
5531 {
5532 if (!cep->ce_vardata)
5533 {
5534 config_error_empty(cep->ce_fileptr->cf_filename,
5535 cep->ce_varlinenum, "except tkl", "mask");
5536 errors++;
5537 continue;
5538 }
5539 if (has_mask)
5540 {
5541 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5542 cep->ce_varlinenum, "except tkl::mask");
5543 continue;
5544 }
5545 has_mask = 1;
5546 }
5547 else if (!strcmp(cep->ce_varname, "type"))
5548 {
5549 if (has_type)
5550 {
5551 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5552 cep->ce_varlinenum, "except tkl::type");
5553 continue;
5554 }
5555 if (cep->ce_vardata)
5556 {
5557 if (!strcmp(cep->ce_vardata, "tkline") ||
5558 !strcmp(cep->ce_vardata, "tzline"))
5559 {
5560 config_error("%s:%i: except tkl of type %s is"
5561 " deprecated. Use except ban {}"
5562 " instead",
5563 cep->ce_fileptr->cf_filename,
5564 cep->ce_varlinenum,
5565 cep->ce_vardata);
5566 errors++;
5567 }
5568 if (!config_binary_flags_search(ExceptTklFlags,
5569 cep->ce_vardata, ARRAY_SIZEOF(ExceptTklFlags)))
5570 {
5571 config_error("%s:%i: unknown except tkl type %s",
5572 cep->ce_fileptr->cf_filename,
5573 cep->ce_varlinenum,
5574 cep->ce_vardata);
5575 return 1;
5576 }
5577 }
5578 else if (cep->ce_entries)
5579 {
5580 ConfigEntry *cepp;
5581 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
5582 {
5583 if (!strcmp(cepp->ce_varname, "tkline") ||
5584 !strcmp(cepp->ce_varname, "tzline"))
5585 {
5586 config_error("%s:%i: except tkl of type %s is"
5587 " deprecated. Use except ban {}"
5588 " instead",
5589 cepp->ce_fileptr->cf_filename,
5590 cepp->ce_varlinenum,
5591 cepp->ce_varname);
5592 errors++;
5593 }
5594 if (!config_binary_flags_search(ExceptTklFlags,
5595 cepp->ce_varname, ARRAY_SIZEOF(ExceptTklFlags)))
5596 {
5597 config_error("%s:%i: unknown except tkl type %s",
5598 cepp->ce_fileptr->cf_filename,
5599 cepp->ce_varlinenum,
5600 cepp->ce_varname);
5601 return 1;
5602 }
5603 }
5604 }
5605 else
5606 {
5607 config_error_empty(cep->ce_fileptr->cf_filename,
5608 cep->ce_varlinenum, "except tkl", "type");
5609 errors++;
5610 continue;
5611 }
5612 has_type = 1;
5613 }
5614 else
5615 {
5616 config_error_unknown(cep->ce_fileptr->cf_filename,
5617 cep->ce_varlinenum, "except tkl", cep->ce_varname);
5618 errors++;
5619 continue;
5620 }
5621 }
5622 if (!has_mask)
5623 {
5624 config_error("%s:%i: except tkl without mask item",
5625 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
5626 return 1;
5627 }
5628 if (!has_type)
5629 {
5630 config_error("%s:%i: except tkl without type item",
5631 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
5632 return 1;
5633 }
5634 return errors;
5635 }
5636 else {
5637 int used = 0;
5638 for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
5639 {
5640 int value, errs = 0;
5641 if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
5642 && !(h->owner->options & MOD_OPT_PERM))
5643 continue;
5644 value = (*(h->func.intfunc))(conf,ce,CONFIG_EXCEPT,&errs);
5645 if (value == 2)
5646 used = 1;
5647 if (value == 1)
5648 {
5649 used = 1;
5650 break;
5651 }
5652 if (value == -1)
5653 {
5654 used = 1;
5655 errors += errs;
5656 break;
5657 }
5658 if (value == -2)
5659 {
5660 used = 1;
5661 errors += errs;
5662 }
5663 }
5664 if (!used) {
5665 config_error("%s:%i: unknown except type %s",
5666 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
5667 ce->ce_vardata);
5668 return 1;
5669 }
5670 }
5671 return errors;
5672 }
5673
5674 /*
5675 * vhost {} block parser
5676 */
_conf_vhost(ConfigFile * conf,ConfigEntry * ce)5677 int _conf_vhost(ConfigFile *conf, ConfigEntry *ce)
5678 {
5679 ConfigItem_vhost *vhost;
5680 ConfigItem_oper_from *from;
5681 ConfigEntry *cep, *cepp;
5682 vhost = MyMallocEx(sizeof(ConfigItem_vhost));
5683
5684 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5685 {
5686 if (!strcmp(cep->ce_varname, "vhost"))
5687 {
5688 char *user, *host;
5689 user = strtok(cep->ce_vardata, "@");
5690 host = strtok(NULL, "");
5691 if (!host)
5692 vhost->virthost = strdup(user);
5693 else
5694 {
5695 vhost->virtuser = strdup(user);
5696 vhost->virthost = strdup(host);
5697 }
5698 }
5699 else if (!strcmp(cep->ce_varname, "login"))
5700 vhost->login = strdup(cep->ce_vardata);
5701 else if (!strcmp(cep->ce_varname, "password"))
5702 vhost->auth = Auth_ConvertConf2AuthStruct(cep);
5703 else if (!strcmp(cep->ce_varname, "from"))
5704 {
5705 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
5706 {
5707 if (!strcmp(cepp->ce_varname, "userhost"))
5708 {
5709 from = MyMallocEx(sizeof(ConfigItem_oper_from));
5710 ircstrdup(from->name, cepp->ce_vardata);
5711 AddListItem(from, vhost->from);
5712 }
5713 }
5714 }
5715 else if (!strcmp(cep->ce_varname, "swhois"))
5716 vhost->swhois = strdup(cep->ce_vardata);
5717 }
5718 AddListItem(vhost, conf_vhost);
5719 return 1;
5720 }
5721
_test_vhost(ConfigFile * conf,ConfigEntry * ce)5722 int _test_vhost(ConfigFile *conf, ConfigEntry *ce)
5723 {
5724 int errors = 0;
5725 ConfigEntry *cep;
5726 char has_vhost = 0, has_login = 0, has_password = 0, has_swhois = 0, has_from = 0;
5727 char has_userhost = 0;
5728
5729 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5730 {
5731 if (!cep->ce_varname)
5732 {
5733 config_error_blank(cep->ce_fileptr->cf_filename,
5734 cep->ce_varlinenum, "vhost");
5735 errors++;
5736 continue;
5737 }
5738 if (!strcmp(cep->ce_varname, "vhost"))
5739 {
5740 char *at, *tmp, *host;
5741 if (has_vhost)
5742 {
5743 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5744 cep->ce_varlinenum, "vhost::vhost");
5745 continue;
5746 }
5747 has_vhost = 1;
5748 if (!cep->ce_vardata)
5749 {
5750 config_error_empty(cep->ce_fileptr->cf_filename,
5751 cep->ce_varlinenum, "vhost", "vhost");
5752 errors++;
5753 continue;
5754 }
5755 if ((at = strchr(cep->ce_vardata, '@')))
5756 {
5757 for (tmp = cep->ce_vardata; tmp != at; tmp++)
5758 {
5759 if (*tmp == '~' && tmp == cep->ce_vardata)
5760 continue;
5761 if (!isallowed(*tmp))
5762 break;
5763 }
5764 if (tmp != at)
5765 {
5766 config_error("%s:%i: vhost::vhost contains an invalid ident",
5767 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
5768 errors++;
5769 }
5770 host = at+1;
5771 }
5772 else
5773 host = cep->ce_vardata;
5774 if (!*host)
5775 {
5776 config_error("%s:%i: vhost::vhost does not have a host set",
5777 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
5778 errors++;
5779 }
5780 else
5781 {
5782 if (!valid_host(host))
5783 {
5784 config_error("%s:%i: vhost::vhost contains an invalid host",
5785 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
5786 errors++;
5787 }
5788 }
5789 }
5790 else if (!strcmp(cep->ce_varname, "login"))
5791 {
5792 if (has_login)
5793 {
5794 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5795 cep->ce_varlinenum, "vhost::login");
5796 }
5797 has_login = 1;
5798 if (!cep->ce_vardata)
5799 {
5800 config_error_empty(cep->ce_fileptr->cf_filename,
5801 cep->ce_varlinenum, "vhost", "login");
5802 errors++;
5803 continue;
5804 }
5805 }
5806 else if (!strcmp(cep->ce_varname, "password"))
5807 {
5808 if (has_password)
5809 {
5810 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5811 cep->ce_varlinenum, "vhost::password");
5812 }
5813 has_password = 1;
5814 if (!cep->ce_vardata)
5815 {
5816 config_error_empty(cep->ce_fileptr->cf_filename,
5817 cep->ce_varlinenum, "vhost", "password");
5818 errors++;
5819 continue;
5820 }
5821 if (Auth_CheckError(cep) < 0)
5822 errors++;
5823 }
5824 else if (!strcmp(cep->ce_varname, "from"))
5825 {
5826 ConfigEntry *cepp;
5827
5828 if (has_from)
5829 {
5830 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5831 cep->ce_varlinenum, "vhost::from");
5832 continue;
5833 }
5834 has_from = 1;
5835 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
5836 {
5837 if (config_is_blankorempty(cepp, "vhost::from"))
5838 {
5839 errors++;
5840 continue;
5841 }
5842 if (!strcmp(cepp->ce_varname, "userhost"))
5843 has_userhost = 1;
5844 else
5845 {
5846 config_error_unknown(cepp->ce_fileptr->cf_filename,
5847 cepp->ce_varlinenum, "vhost::from",
5848 cepp->ce_varname);
5849 errors++;
5850 continue;
5851 }
5852 }
5853 }
5854 else if (!strcmp(cep->ce_varname, "swhois"))
5855 {
5856 if (has_swhois)
5857 {
5858 config_warn_duplicate(cep->ce_fileptr->cf_filename,
5859 cep->ce_varlinenum, "vhost::swhois");
5860 continue;
5861 }
5862 has_swhois = 1;
5863 }
5864 else
5865 {
5866 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
5867 "vhost", cep->ce_varname);
5868 errors++;
5869 }
5870 }
5871 if (!has_vhost)
5872 {
5873 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
5874 "vhost::vhost");
5875 errors++;
5876 }
5877 if (!has_login)
5878 {
5879 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
5880 "vhost::login");
5881 errors++;
5882
5883 }
5884 if (!has_password)
5885 {
5886 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
5887 "vhost::password");
5888 errors++;
5889 }
5890 if (!has_from)
5891 {
5892 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
5893 "vhost::from");
5894 errors++;
5895 }
5896 if (!has_userhost)
5897 {
5898 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
5899 "vhost::userhost");
5900 errors++;
5901 }
5902 return errors;
5903 }
5904
5905 #ifdef STRIPBADWORDS
5906
copy_badword_struct(ConfigItem_badword * ca,int regex,int regflags)5907 static ConfigItem_badword *copy_badword_struct(ConfigItem_badword *ca, int regex, int regflags)
5908 {
5909 ConfigItem_badword *x = MyMalloc(sizeof(ConfigItem_badword));
5910 memcpy(x, ca, sizeof(ConfigItem_badword));
5911 x->word = strdup(ca->word);
5912 if (ca->replace)
5913 x->replace = strdup(ca->replace);
5914 if (regex)
5915 {
5916 memset(&x->expr, 0, sizeof(regex_t));
5917 regcomp(&x->expr, x->word, regflags);
5918 }
5919 return x;
5920 }
5921
_conf_badword(ConfigFile * conf,ConfigEntry * ce)5922 int _conf_badword(ConfigFile *conf, ConfigEntry *ce)
5923 {
5924 ConfigEntry *cep, *word = NULL;
5925 ConfigItem_badword *ca;
5926 char *tmp;
5927 short regex = 0;
5928 int regflags = 0;
5929 #ifdef FAST_BADWORD_REPLACE
5930 int ast_l = 0, ast_r = 0;
5931 #endif
5932
5933 ca = MyMallocEx(sizeof(ConfigItem_badword));
5934 ca->action = BADWORD_REPLACE;
5935 regflags = REG_ICASE|REG_EXTENDED;
5936
5937 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
5938 {
5939 if (!strcmp(cep->ce_varname, "action"))
5940 {
5941 if (!strcmp(cep->ce_vardata, "block"))
5942 {
5943 ca->action = BADWORD_BLOCK;
5944 /* If it is set to just block, then we don't need to worry about
5945 * replacements
5946 */
5947 regflags |= REG_NOSUB;
5948 }
5949 }
5950 else if (!strcmp(cep->ce_varname, "replace"))
5951 {
5952 ircstrdup(ca->replace, cep->ce_vardata);
5953 }
5954 else if (!strcmp(cep->ce_varname, "word"))
5955 word = cep;
5956 }
5957 #ifdef FAST_BADWORD_REPLACE
5958 /* The fast badwords routine can do: "blah" "*blah" "blah*" and "*blah*",
5959 * in all other cases use regex.
5960 */
5961 for (tmp = word->ce_vardata; *tmp; tmp++) {
5962 if (!isalnum(*tmp) && !(*tmp >= 128)) {
5963 if ((word->ce_vardata == tmp) && (*tmp == '*')) {
5964 ast_l = 1; /* Asterisk at the left */
5965 continue;
5966 }
5967 if ((*(tmp + 1) == '\0') && (*tmp == '*')) {
5968 ast_r = 1; /* Asterisk at the right */
5969 continue;
5970 }
5971 regex = 1;
5972 break;
5973 }
5974 }
5975 if (regex)
5976 {
5977 ca->type = BADW_TYPE_REGEX;
5978 ircstrdup(ca->word, word->ce_vardata);
5979 regcomp(&ca->expr, ca->word, regflags);
5980 }
5981 else
5982 {
5983 char *tmpw;
5984 ca->type = BADW_TYPE_FAST;
5985 ca->word = tmpw = MyMalloc(strlen(word->ce_vardata) - ast_l - ast_r + 1);
5986 /* Copy except for asterisks */
5987 for (tmp = word->ce_vardata; *tmp; tmp++)
5988 if (*tmp != '*')
5989 *tmpw++ = *tmp;
5990 *tmpw = '\0';
5991 if (ast_l)
5992 ca->type |= BADW_TYPE_FAST_L;
5993 if (ast_r)
5994 ca->type |= BADW_TYPE_FAST_R;
5995 }
5996 #else
5997 for (tmp = word->ce_vardata; *tmp; tmp++)
5998 {
5999 if (!isalnum(*tmp) && !(*tmp >= 128))
6000 {
6001 regex = 1;
6002 break;
6003 }
6004 }
6005 if (regex)
6006 {
6007 ircstrdup(ca->word, word->ce_vardata);
6008 }
6009 else
6010 {
6011 ca->word = MyMalloc(strlen(word->ce_vardata) + strlen(PATTERN) -1);
6012 ircsprintf(ca->word, PATTERN, word->ce_vardata);
6013 }
6014 /* Yes this is called twice, once in test, and once here, but it is still MUCH
6015 faster than calling it each time a message is received like before. -- codemastr
6016 */
6017 regcomp(&ca->expr, ca->word, regflags);
6018 #endif
6019 if (!strcmp(ce->ce_vardata, "channel"))
6020 AddListItem(ca, conf_badword_channel);
6021 else if (!strcmp(ce->ce_vardata, "message"))
6022 AddListItem(ca, conf_badword_message);
6023 else if (!strcmp(ce->ce_vardata, "quit"))
6024 AddListItem(ca, conf_badword_quit);
6025 else if (!strcmp(ce->ce_vardata, "all"))
6026 {
6027 AddListItem(ca, conf_badword_channel);
6028 AddListItem(copy_badword_struct(ca,regex,regflags), conf_badword_message);
6029 AddListItem(copy_badword_struct(ca,regex,regflags), conf_badword_quit);
6030 }
6031 return 1;
6032 }
6033
_test_badword(ConfigFile * conf,ConfigEntry * ce)6034 int _test_badword(ConfigFile *conf, ConfigEntry *ce)
6035 {
6036 int errors = 0;
6037 ConfigEntry *cep;
6038 char has_word = 0, has_replace = 0, has_action = 0, action = 'r';
6039
6040 if (!ce->ce_vardata)
6041 {
6042 config_error("%s:%i: badword without type",
6043 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
6044 return 1;
6045 }
6046 else if (strcmp(ce->ce_vardata, "channel") && strcmp(ce->ce_vardata, "message") &&
6047 strcmp(ce->ce_vardata, "quit") && strcmp(ce->ce_vardata, "all")) {
6048 config_error("%s:%i: badword with unknown type",
6049 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
6050 return 1;
6051 }
6052 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
6053 {
6054 if (config_is_blankorempty(cep, "badword"))
6055 {
6056 errors++;
6057 continue;
6058 }
6059 if (!strcmp(cep->ce_varname, "word"))
6060 {
6061 char *errbuf;
6062 if (has_word)
6063 {
6064 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6065 cep->ce_varlinenum, "badword::word");
6066 continue;
6067 }
6068 has_word = 1;
6069 if ((errbuf = unreal_checkregex(cep->ce_vardata,1,1)))
6070 {
6071 config_error("%s:%i: badword::%s contains an invalid regex: %s",
6072 cep->ce_fileptr->cf_filename,
6073 cep->ce_varlinenum,
6074 cep->ce_varname, errbuf);
6075 errors++;
6076 }
6077 }
6078 else if (!strcmp(cep->ce_varname, "replace"))
6079 {
6080 if (has_replace)
6081 {
6082 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6083 cep->ce_varlinenum, "badword::replace");
6084 continue;
6085 }
6086 has_replace = 1;
6087 }
6088 else if (!strcmp(cep->ce_varname, "action"))
6089 {
6090 if (has_action)
6091 {
6092 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6093 cep->ce_varlinenum, "badword::action");
6094 continue;
6095 }
6096 has_action = 1;
6097 if (!strcmp(cep->ce_vardata, "replace"))
6098 action = 'r';
6099 else if (!strcmp(cep->ce_vardata, "block"))
6100 action = 'b';
6101 else
6102 {
6103 config_error("%s:%d: Unknown badword::action '%s'",
6104 cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
6105 cep->ce_vardata);
6106 errors++;
6107 }
6108
6109 }
6110 else
6111 {
6112 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
6113 "badword", cep->ce_varname);
6114 errors++;
6115 }
6116 }
6117
6118 if (!has_word)
6119 {
6120 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
6121 "badword::word");
6122 errors++;
6123 }
6124 if (has_action)
6125 {
6126 if (has_replace && action == 'b')
6127 {
6128 config_error("%s:%i: badword::action is block but badword::replace exists",
6129 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
6130 errors++;
6131 }
6132 }
6133 return errors;
6134 }
6135 #endif
6136
_conf_spamfilter(ConfigFile * conf,ConfigEntry * ce)6137 int _conf_spamfilter(ConfigFile *conf, ConfigEntry *ce)
6138 {
6139 ConfigEntry *cep;
6140 ConfigEntry *cepp;
6141 aTKline *nl = MyMallocEx(sizeof(aTKline));
6142 char *word = NULL, *reason = NULL, *bantime = NULL;
6143 int action = 0, target = 0;
6144 char has_reason = 0, has_bantime = 0;
6145
6146 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
6147 {
6148 if (!strcmp(cep->ce_varname, "regex"))
6149 {
6150 nl->reason = strdup(cep->ce_vardata);
6151
6152 word = cep->ce_vardata;
6153 }
6154 else if (!strcmp(cep->ce_varname, "target"))
6155 {
6156 if (cep->ce_vardata)
6157 target = spamfilter_getconftargets(cep->ce_vardata);
6158 else
6159 {
6160 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
6161 target |= spamfilter_getconftargets(cepp->ce_varname);
6162 }
6163 }
6164 else if (!strcmp(cep->ce_varname, "action"))
6165 {
6166 action = banact_stringtoval(cep->ce_vardata);
6167 nl->hostmask = strdup(cep->ce_vardata);
6168 }
6169 else if (!strcmp(cep->ce_varname, "reason"))
6170 {
6171 has_reason = 1;
6172 reason = cep->ce_vardata;
6173 }
6174 else if (!strcmp(cep->ce_varname, "ban-time"))
6175 {
6176 has_bantime = 1;
6177 bantime = cep->ce_vardata;
6178 }
6179 }
6180 nl->type = TKL_SPAMF;
6181 nl->expire_at = 0;
6182 nl->set_at = TStime();
6183
6184 strncpyzt(nl->usermask, spamfilter_target_inttostring(target), sizeof(nl->usermask));
6185 nl->subtype = target;
6186
6187 nl->setby = BadPtr(me.name) ? NULL : strdup(me.name); /* Hmm! */
6188 nl->ptr.spamf = unreal_buildspamfilter(word);
6189 nl->ptr.spamf->action = action;
6190
6191 if (has_reason && reason)
6192 nl->ptr.spamf->tkl_reason = strdup(unreal_encodespace(reason));
6193 else
6194 nl->ptr.spamf->tkl_reason = strdup("<internally added by ircd>");
6195
6196 if (has_bantime)
6197 nl->ptr.spamf->tkl_duration = config_checkval(bantime, CFG_TIME);
6198 else
6199 nl->ptr.spamf->tkl_duration = (SPAMFILTER_BAN_TIME ? SPAMFILTER_BAN_TIME : 86400);
6200
6201 AddListItem(nl, tklines[tkl_hash('f')]);
6202 return 1;
6203 }
6204
_test_spamfilter(ConfigFile * conf,ConfigEntry * ce)6205 int _test_spamfilter(ConfigFile *conf, ConfigEntry *ce)
6206 {
6207 ConfigEntry *cep, *cepp;
6208 int errors = 0;
6209 char *regex = NULL, *reason = NULL;
6210 char has_target = 0, has_regex = 0, has_action = 0, has_reason = 0, has_bantime = 0;
6211
6212 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
6213 {
6214 if (!cep->ce_varname)
6215 {
6216 config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
6217 "spamfilter");
6218 errors++;
6219 continue;
6220 }
6221 if (!strcmp(cep->ce_varname, "target"))
6222 {
6223 if (has_target)
6224 {
6225 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6226 cep->ce_varlinenum, "spamfilter::target");
6227 continue;
6228 }
6229 has_target = 1;
6230 if (cep->ce_vardata)
6231 {
6232 if (!spamfilter_getconftargets(cep->ce_vardata))
6233 {
6234 config_error("%s:%i: unknown spamfiler target type '%s'",
6235 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_vardata);
6236 errors++;
6237 }
6238 }
6239 else if (cep->ce_entries)
6240 {
6241 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
6242 {
6243 if (!cepp->ce_varname)
6244 {
6245 config_error_blank(cepp->ce_fileptr->cf_filename,
6246 cepp->ce_varlinenum,
6247 "spamfilter::target");
6248 errors++;
6249 continue;
6250 }
6251 if (!spamfilter_getconftargets(cepp->ce_varname))
6252 {
6253 config_error("%s:%i: unknown spamfiler target type '%s'",
6254 cepp->ce_fileptr->cf_filename,
6255 cepp->ce_varlinenum, cepp->ce_varname);
6256 errors++;
6257 }
6258 }
6259 }
6260 else
6261 {
6262 config_error_empty(cep->ce_fileptr->cf_filename,
6263 cep->ce_varlinenum, "spamfilter", cep->ce_varname);
6264 errors++;
6265 }
6266 continue;
6267 }
6268 if (!cep->ce_vardata)
6269 {
6270 config_error_empty(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
6271 "spamfilter", cep->ce_varname);
6272 errors++;
6273 continue;
6274 }
6275 if (!strcmp(cep->ce_varname, "reason"))
6276 {
6277 if (has_reason)
6278 {
6279 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6280 cep->ce_varlinenum, "spamfilter::reason");
6281 continue;
6282 }
6283 has_reason = 1;
6284 reason = cep->ce_vardata;
6285 }
6286 else if (!strcmp(cep->ce_varname, "regex"))
6287 {
6288 char *errbuf;
6289 if (has_regex)
6290 {
6291 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6292 cep->ce_varlinenum, "spamfilter::regex");
6293 continue;
6294 }
6295 has_regex = 1;
6296 if ((errbuf = unreal_checkregex(cep->ce_vardata,0,0)))
6297 {
6298 config_error("%s:%i: spamfilter::regex contains an invalid regex: %s",
6299 cep->ce_fileptr->cf_filename,
6300 cep->ce_varlinenum,
6301 errbuf);
6302 errors++;
6303 continue;
6304 }
6305 regex = cep->ce_vardata;
6306 }
6307 else if (!strcmp(cep->ce_varname, "action"))
6308 {
6309 if (has_action)
6310 {
6311 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6312 cep->ce_varlinenum, "spamfilter::action");
6313 continue;
6314 }
6315 has_action = 1;
6316 if (!banact_stringtoval(cep->ce_vardata))
6317 {
6318 config_error("%s:%i: spamfilter::action has unknown action type '%s'",
6319 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_vardata);
6320 errors++;
6321 }
6322 }
6323 else if (!strcmp(cep->ce_varname, "ban-time"))
6324 {
6325 if (has_bantime)
6326 {
6327 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6328 cep->ce_varlinenum, "spamfilter::ban-time");
6329 continue;
6330 }
6331 has_bantime = 1;
6332 }
6333 else
6334 {
6335 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
6336 "spamfilter", cep->ce_varname);
6337 errors++;
6338 continue;
6339 }
6340 }
6341
6342 if (!has_regex)
6343 {
6344 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
6345 "spamfilter::regex");
6346 errors++;
6347 }
6348 if (!has_target)
6349 {
6350 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
6351 "spamfilter::target");
6352 errors++;
6353 }
6354 if (!has_action)
6355 {
6356 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
6357 "spamfilter::action");
6358 errors++;
6359 }
6360 if (regex && reason && (strlen(regex) + strlen(reason) > 505))
6361 {
6362 config_error("%s:%i: spamfilter block problem: regex + reason field are together over 505 bytes, "
6363 "please choose a shorter regex or reason",
6364 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
6365 errors++;
6366 }
6367
6368 return errors;
6369 }
6370
_conf_help(ConfigFile * conf,ConfigEntry * ce)6371 int _conf_help(ConfigFile *conf, ConfigEntry *ce)
6372 {
6373 ConfigEntry *cep;
6374 ConfigItem_help *ca;
6375 aMotdLine *last = NULL, *temp;
6376 ca = MyMallocEx(sizeof(ConfigItem_help));
6377
6378 if (!ce->ce_vardata)
6379 ca->command = NULL;
6380 else
6381 ca->command = strdup(ce->ce_vardata);
6382
6383 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
6384 {
6385 temp = MyMalloc(sizeof(aMotdLine));
6386 temp->line = strdup(cep->ce_varname);
6387 temp->next = NULL;
6388 if (!ca->text)
6389 ca->text = temp;
6390 else
6391 last->next = temp;
6392 last = temp;
6393 }
6394 AddListItem(ca, conf_help);
6395 return 1;
6396
6397 }
6398
_test_help(ConfigFile * conf,ConfigEntry * ce)6399 int _test_help(ConfigFile *conf, ConfigEntry *ce) {
6400 int errors = 0;
6401 ConfigEntry *cep;
6402 if (!ce->ce_entries)
6403 {
6404 config_error("%s:%i: empty help block",
6405 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
6406 return 1;
6407 }
6408 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
6409 {
6410 if (!cep->ce_varname)
6411 {
6412 config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
6413 "help");
6414 errors++;
6415 continue;
6416 }
6417 }
6418 return errors;
6419 }
6420
_conf_log(ConfigFile * conf,ConfigEntry * ce)6421 int _conf_log(ConfigFile *conf, ConfigEntry *ce)
6422 {
6423 ConfigEntry *cep, *cepp;
6424 ConfigItem_log *ca;
6425 OperFlag *ofp = NULL;
6426
6427 ca = MyMallocEx(sizeof(ConfigItem_log));
6428 ircstrdup(ca->file, ce->ce_vardata);
6429
6430 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
6431 {
6432 if (!strcmp(cep->ce_varname, "maxsize"))
6433 {
6434 ca->maxsize = config_checkval(cep->ce_vardata,CFG_SIZE);
6435 }
6436 else if (!strcmp(cep->ce_varname, "flags"))
6437 {
6438 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
6439 {
6440 if ((ofp = config_binary_flags_search(_LogFlags, cepp->ce_varname, ARRAY_SIZEOF(_LogFlags))))
6441 ca->flags |= ofp->flag;
6442 }
6443 }
6444 }
6445 AddListItem(ca, conf_log);
6446 return 1;
6447
6448 }
6449
_test_log(ConfigFile * conf,ConfigEntry * ce)6450 int _test_log(ConfigFile *conf, ConfigEntry *ce) {
6451 int errors = 0;
6452 ConfigEntry *cep, *cepp;
6453 char has_flags = 0, has_maxsize = 0;
6454
6455 if (!ce->ce_vardata)
6456 {
6457 config_error("%s:%i: log block without filename",
6458 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
6459 return 1;
6460 }
6461 if (!ce->ce_entries)
6462 {
6463 config_error("%s:%i: empty log block",
6464 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
6465 return 1;
6466 }
6467 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
6468 {
6469 if (!cep->ce_varname)
6470 {
6471 config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
6472 "log");
6473 errors++;
6474 continue;
6475 }
6476 if (!strcmp(cep->ce_varname, "flags"))
6477 {
6478 if (has_flags)
6479 {
6480 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6481 cep->ce_varlinenum, "log::flags");
6482 continue;
6483 }
6484 has_flags = 1;
6485 if (!cep->ce_entries)
6486 {
6487 config_error_empty(cep->ce_fileptr->cf_filename,
6488 cep->ce_varlinenum, "log", cep->ce_varname);
6489 errors++;
6490 continue;
6491 }
6492 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
6493 {
6494 if (!cepp->ce_varname)
6495 {
6496 config_error_blank(cepp->ce_fileptr->cf_filename,
6497 cepp->ce_varlinenum, "log::flags");
6498 errors++;
6499 continue;
6500 }
6501 if (!config_binary_flags_search(_LogFlags, cepp->ce_varname, ARRAY_SIZEOF(_LogFlags)))
6502 {
6503 config_error_unknownflag(cepp->ce_fileptr->cf_filename,
6504 cepp->ce_varlinenum, "log", cepp->ce_varname);
6505 errors++;
6506 }
6507 }
6508 }
6509 else if (!strcmp(cep->ce_varname, "maxsize"))
6510 {
6511 if (has_maxsize)
6512 {
6513 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6514 cep->ce_varlinenum, "log::maxsize");
6515 continue;
6516 }
6517 has_maxsize = 1;
6518 if (!cep->ce_vardata)
6519 {
6520 config_error_empty(cep->ce_fileptr->cf_filename,
6521 cep->ce_varlinenum, "log", cep->ce_varname);
6522 errors++;
6523 }
6524 }
6525 else
6526 {
6527 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
6528 "log", cep->ce_varname);
6529 errors++;
6530 continue;
6531 }
6532 }
6533 if (!has_flags)
6534 {
6535 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
6536 "log::flags");
6537 errors++;
6538 }
6539 return errors;
6540 }
6541
6542
_conf_link(ConfigFile * conf,ConfigEntry * ce)6543 int _conf_link(ConfigFile *conf, ConfigEntry *ce)
6544 {
6545 ConfigEntry *cep;
6546 ConfigEntry *cepp;
6547 ConfigItem_link *link = NULL;
6548 OperFlag *ofp;
6549
6550 link = (ConfigItem_link *) MyMallocEx(sizeof(ConfigItem_link));
6551 link->servername = strdup(ce->ce_vardata);
6552 /* ugly, but it works. if it fails, we know _test_link failed miserably */
6553 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
6554 {
6555 if (!strcmp(cep->ce_varname, "username"))
6556 link->username = strdup(cep->ce_vardata);
6557 else if (!strcmp(cep->ce_varname, "hostname"))
6558 link->hostname = strdup(cep->ce_vardata);
6559 else if (!strcmp(cep->ce_varname, "bind-ip"))
6560 link->bindip = strdup(cep->ce_vardata);
6561 else if (!strcmp(cep->ce_varname, "port"))
6562 link->port = atol(cep->ce_vardata);
6563 else if (!strcmp(cep->ce_varname, "password-receive"))
6564 link->recvauth = Auth_ConvertConf2AuthStruct(cep);
6565 else if (!strcmp(cep->ce_varname, "password-connect"))
6566 link->connpwd = strdup(cep->ce_vardata);
6567 else if (!strcmp(cep->ce_varname, "class"))
6568 {
6569 link->class = Find_class(cep->ce_vardata);
6570 if (!link->class || (link->class->flag.temporary == 1))
6571 {
6572 config_status("%s:%i: illegal link::class, unknown class '%s' using default of class 'default'",
6573 cep->ce_fileptr->cf_filename,
6574 cep->ce_varlinenum,
6575 cep->ce_vardata);
6576 link->class = default_class;
6577 }
6578 link->class->xrefcount++;
6579 }
6580 else if (!strcmp(cep->ce_varname, "options"))
6581 {
6582 link->options = 0;
6583 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
6584 {
6585 if ((ofp = config_binary_flags_search(_LinkFlags, cepp->ce_varname, ARRAY_SIZEOF(_LinkFlags))))
6586 link->options |= ofp->flag;
6587 }
6588 }
6589 else if (!strcmp(cep->ce_varname, "hub"))
6590 link->hubmask = strdup(cep->ce_vardata);
6591 else if (!strcmp(cep->ce_varname, "leaf"))
6592 link->leafmask = strdup(cep->ce_vardata);
6593 else if (!strcmp(cep->ce_varname, "leafdepth"))
6594 link->leafdepth = atol(cep->ce_vardata);
6595 #ifdef USE_SSL
6596 else if (!strcmp(cep->ce_varname, "ciphers"))
6597 link->ciphers = strdup(cep->ce_vardata);
6598 #endif
6599 #ifdef ZIP_LINKS
6600 else if (!strcmp(cep->ce_varname, "compression-level"))
6601 link->compression_level = atoi(cep->ce_vardata);
6602 #endif
6603 }
6604 AddListItem(link, conf_link);
6605 return 0;
6606 }
6607
_test_link(ConfigFile * conf,ConfigEntry * ce)6608 int _test_link(ConfigFile *conf, ConfigEntry *ce)
6609 {
6610 ConfigEntry *cep, *cepp;
6611 OperFlag *ofp;
6612 int errors = 0;
6613 char has_username = 0, has_hostname = 0, has_bindip = 0, has_port = 0;
6614 char has_passwordreceive = 0, has_passwordconnect = 0, has_class = 0;
6615 char has_hub = 0, has_leaf = 0, has_leafdepth = 0, has_ciphers = 0;
6616 char has_options = 0;
6617 char has_autoconnect = 0;
6618 char has_hostname_wildcards = 0;
6619 #ifdef ZIP_LINKS
6620 char has_compressionlevel = 0;
6621 #endif
6622 if (!ce->ce_vardata)
6623 {
6624 config_error("%s:%i: link without servername",
6625 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
6626 return 1;
6627
6628 }
6629 if (!strchr(ce->ce_vardata, '.'))
6630 {
6631 config_error("%s:%i: link: bogus server name",
6632 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
6633 return 1;
6634 }
6635
6636 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
6637 {
6638 if (!cep->ce_varname)
6639 {
6640 config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
6641 "link");
6642 errors++;
6643 continue;
6644 }
6645 if (!strcmp(cep->ce_varname, "options"))
6646 {
6647 if (has_options)
6648 {
6649 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6650 cep->ce_varlinenum, "link::options");
6651 continue;
6652 }
6653 has_options = 1;
6654 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
6655 {
6656 if (!cepp->ce_varname)
6657 {
6658 config_error_blank(cepp->ce_fileptr->cf_filename,
6659 cepp->ce_varlinenum, "link::options");
6660 errors++;
6661 continue;
6662 }
6663 if (!(ofp = config_binary_flags_search(_LinkFlags, cepp->ce_varname, ARRAY_SIZEOF(_LinkFlags))))
6664 {
6665 config_error_unknownopt(cepp->ce_fileptr->cf_filename,
6666 cepp->ce_varlinenum, "link", cepp->ce_varname);
6667 errors++;
6668 continue;
6669 }
6670 #ifndef USE_SSL
6671 if (ofp->flag == CONNECT_SSL)
6672 {
6673 config_error("%s:%i: link %s with SSL option enabled on a non-SSL compile",
6674 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, ce->ce_vardata);
6675 errors++;
6676 }
6677 #endif
6678 #ifndef ZIP_LINKS
6679 if (ofp->flag == CONNECT_ZIP)
6680 {
6681 config_error("%s:%i: link %s with ZIP option enabled on a non-ZIP compile",
6682 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, ce->ce_vardata);
6683 errors++;
6684 }
6685 #endif
6686 if (ofp->flag == CONNECT_AUTO)
6687 {
6688 has_autoconnect = 1;
6689 }
6690 }
6691 continue;
6692 }
6693 if (!cep->ce_vardata)
6694 {
6695 config_error_empty(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
6696 "link", cep->ce_varname);
6697 errors++;
6698 continue;
6699 }
6700 if (!strcmp(cep->ce_varname, "username"))
6701 {
6702 if (has_username)
6703 {
6704 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6705 cep->ce_varlinenum, "link::username");
6706 continue;
6707 }
6708 has_username = 1;
6709 }
6710 else if (!strcmp(cep->ce_varname, "hostname"))
6711 {
6712 if (has_hostname)
6713 {
6714 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6715 cep->ce_varlinenum, "link::hostname");
6716 continue;
6717 }
6718 has_hostname = 1;
6719 #ifdef INET6
6720 /* I'm nice... I'll help those poor ipv6 users. -- Syzop */
6721 /* [ not null && len>6 && has not a : in it && last character is a digit ] */
6722 if (cep->ce_vardata && (strlen(cep->ce_vardata) > 6) && !strchr(cep->ce_vardata, ':') &&
6723 isdigit(cep->ce_vardata[strlen(cep->ce_vardata)-1]))
6724 {
6725 char crap[32];
6726 if (inet_pton(AF_INET, cep->ce_vardata, crap) != 0)
6727 {
6728 char ipv6buf[48];
6729 snprintf(ipv6buf, sizeof(ipv6buf), "::ffff:%s", cep->ce_vardata);
6730 MyFree(cep->ce_vardata);
6731 cep->ce_vardata = strdup(ipv6buf);
6732 } else {
6733 /* Insert IPv6 validation here */
6734 config_error( "%s:%i: listen: '%s' looks like "
6735 "it might be IPv4, but is not a valid address.",
6736 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
6737 cep->ce_vardata);
6738 errors++;
6739 }
6740 }
6741 #endif
6742 if (strchr(cep->ce_vardata, '*') != NULL || strchr(cep->ce_vardata, '?'))
6743 {
6744 has_hostname_wildcards = 1;
6745 }
6746 }
6747 else if (!strcmp(cep->ce_varname, "bind-ip"))
6748 {
6749 if (has_bindip)
6750 {
6751 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6752 cep->ce_varlinenum, "link::bind-ip");
6753 continue;
6754 }
6755 has_bindip = 1;
6756 #ifdef INET6
6757 /* I'm nice... I'll help those poor ipv6 users. -- Syzop */
6758 /* [ not null && len>6 && has not a : in it && last character is a digit ] */
6759 if (cep->ce_vardata && (strlen(cep->ce_vardata) > 6) && !strchr(cep->ce_vardata, ':') &&
6760 isdigit(cep->ce_vardata[strlen(cep->ce_vardata)-1]))
6761 {
6762 char crap[32];
6763 if (inet_pton(AF_INET, cep->ce_vardata, crap) != 0)
6764 {
6765 char ipv6buf[48];
6766 snprintf(ipv6buf, sizeof(ipv6buf), "::ffff:%s", cep->ce_vardata);
6767 MyFree(cep->ce_vardata);
6768 cep->ce_vardata = strdup(ipv6buf);
6769 } else {
6770 /* Insert IPv6 validation here */
6771 config_error( "%s:%i: bind-ip: '%s' looks like "
6772 "it might be IPv4, but is not a valid address.",
6773 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
6774 cep->ce_vardata);
6775 errors++;
6776 }
6777 }
6778 #endif
6779 }
6780 else if (!strcmp(cep->ce_varname, "port"))
6781 {
6782 if (has_port)
6783 {
6784 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6785 cep->ce_varlinenum, "link::port");
6786 continue;
6787 }
6788 has_port = 1;
6789 }
6790 else if (!strcmp(cep->ce_varname, "password-receive"))
6791 {
6792 if (has_passwordreceive)
6793 {
6794 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6795 cep->ce_varlinenum, "link::password-receive");
6796 continue;
6797 }
6798 has_passwordreceive = 1;
6799 if (Auth_CheckError(cep) < 0)
6800 errors++;
6801 }
6802 else if (!strcmp(cep->ce_varname, "password-connect"))
6803 {
6804 if (has_passwordconnect)
6805 {
6806 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6807 cep->ce_varlinenum, "link::password-connect");
6808 continue;
6809 }
6810 has_passwordconnect = 1;
6811 if (cep->ce_entries)
6812 {
6813 config_error("%s:%i: link::password-connect cannot be encrypted",
6814 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
6815 errors++;
6816 }
6817 if (strlen(cep->ce_vardata) > PASSWDLEN)
6818 {
6819 config_error("%s:%i: link::password-connect cannot exceed %d characters in length",
6820 ce->ce_fileptr->cf_filename, ce->ce_varlinenum, PASSWDLEN);
6821 errors++;
6822 }
6823 }
6824 else if (!strcmp(cep->ce_varname, "class"))
6825 {
6826 if (has_class)
6827 {
6828 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6829 cep->ce_varlinenum, "link::class");
6830 continue;
6831 }
6832 has_class = 1;
6833 }
6834 else if (!strcmp(cep->ce_varname, "hub"))
6835 {
6836 if (has_hub)
6837 {
6838 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6839 cep->ce_varlinenum, "link::hub");
6840 continue;
6841 }
6842 has_hub = 1;
6843 }
6844 else if (!strcmp(cep->ce_varname, "leaf"))
6845 {
6846 if (has_leaf)
6847 {
6848 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6849 cep->ce_varlinenum, "link::leaf");
6850 continue;
6851 }
6852 has_leaf = 1;
6853 }
6854 else if (!strcmp(cep->ce_varname, "leafdepth"))
6855 {
6856 if (has_leafdepth)
6857 {
6858 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6859 cep->ce_varlinenum, "link::leafdepth");
6860 continue;
6861 }
6862 has_leafdepth = 1;
6863 }
6864 else if (!strcmp(cep->ce_varname, "ciphers"))
6865 {
6866 if (has_ciphers)
6867 {
6868 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6869 cep->ce_varlinenum, "link::ciphers");
6870 continue;
6871 }
6872 has_ciphers = 1;
6873 }
6874 #ifdef ZIP_LINKS
6875 else if (!strcmp(cep->ce_varname, "compression-level"))
6876 {
6877 if (has_compressionlevel)
6878 {
6879 config_warn_duplicate(cep->ce_fileptr->cf_filename,
6880 cep->ce_varlinenum, "link::compression-level");
6881 continue;
6882 }
6883 has_compressionlevel = 1;
6884 if ((atoi(cep->ce_vardata) < 1) || (atoi(cep->ce_vardata) > 9))
6885 {
6886 config_error("%s:%i: compression-level should be in range 1..9",
6887 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
6888 errors++;
6889 }
6890 }
6891 #endif
6892 else
6893 {
6894 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
6895 "link", cep->ce_varname);
6896 errors++;
6897 }
6898 }
6899 if (!has_username)
6900 {
6901 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
6902 "link::username");
6903 errors++;
6904 }
6905 if (!has_hostname)
6906 {
6907 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
6908 "link::hostname");
6909 errors++;
6910 }
6911 if (!has_port)
6912 {
6913 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
6914 "link::port");
6915 errors++;
6916 }
6917 if (!has_passwordreceive)
6918 {
6919 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
6920 "link::password-receive");
6921 errors++;
6922 }
6923 if (!has_passwordconnect)
6924 {
6925 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
6926 "link::password-connect");
6927 errors++;
6928 }
6929 if (!has_class)
6930 {
6931 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
6932 "link::class");
6933 errors++;
6934 }
6935 if (has_autoconnect && has_hostname_wildcards)
6936 {
6937 config_error("%s:%i: link block with autoconnect and wildcards (* and/or ? in hostname)",
6938 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
6939 errors++;
6940 }
6941 if (errors > 0)
6942 return errors;
6943 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
6944 {
6945 if (!strcmp(cep->ce_varname, "options"))
6946 {
6947 continue;
6948 }
6949 }
6950 return errors;
6951
6952 }
6953
_conf_cgiirc(ConfigFile * conf,ConfigEntry * ce)6954 int _conf_cgiirc(ConfigFile *conf, ConfigEntry *ce)
6955 {
6956 ConfigEntry *cep;
6957 ConfigEntry *cepp;
6958 ConfigItem_cgiirc *cgiirc = NULL;
6959
6960 cgiirc = (ConfigItem_cgiirc *) MyMallocEx(sizeof(ConfigItem_cgiirc));
6961
6962 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
6963 {
6964 if (!strcmp(cep->ce_varname, "username"))
6965 cgiirc->username = strdup(cep->ce_vardata);
6966 else if (!strcmp(cep->ce_varname, "hostname"))
6967 cgiirc->hostname = strdup(cep->ce_vardata);
6968 else if (!strcmp(cep->ce_varname, "password"))
6969 cgiirc->auth = Auth_ConvertConf2AuthStruct(cep);
6970 else if (!strcmp(cep->ce_varname, "type"))
6971 {
6972 if (!strcmp(cep->ce_vardata, "webirc"))
6973 cgiirc->type = CGIIRC_WEBIRC;
6974 else if (!strcmp(cep->ce_vardata, "old"))
6975 cgiirc->type = CGIIRC_PASS;
6976 else
6977 abort();
6978 }
6979 }
6980 AddListItem(cgiirc, conf_cgiirc);
6981 return 0;
6982 }
6983
_test_cgiirc(ConfigFile * conf,ConfigEntry * ce)6984 int _test_cgiirc(ConfigFile *conf, ConfigEntry *ce)
6985 {
6986 ConfigEntry *cep, *cepp;
6987 OperFlag *ofp;
6988 int errors = 0;
6989 char has_username = 0; /* dup checking only, not mandatory */
6990 char has_type = 0; /* mandatory */
6991 char has_hostname = 0; /* mandatory */
6992 char has_password = 0; /* mandatory */
6993 CGIIRCType type;
6994
6995 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
6996 {
6997 if (!cep->ce_varname)
6998 {
6999 config_error_blank(cep->ce_fileptr->cf_filename, cep->ce_varlinenum, "cgiirc");
7000 errors++;
7001 continue;
7002 }
7003 if (!cep->ce_vardata)
7004 {
7005 config_error_empty(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
7006 "cgiirc", cep->ce_varname);
7007 errors++;
7008 continue;
7009 }
7010 if (!strcmp(cep->ce_varname, "username"))
7011 {
7012 if (has_username)
7013 {
7014 config_warn_duplicate(cep->ce_fileptr->cf_filename,
7015 cep->ce_varlinenum, "cgiirc::username");
7016 continue;
7017 }
7018 has_username = 1;
7019 }
7020 else if (!strcmp(cep->ce_varname, "hostname"))
7021 {
7022 if (has_hostname)
7023 {
7024 config_warn_duplicate(cep->ce_fileptr->cf_filename,
7025 cep->ce_varlinenum, "cgiirc::hostname");
7026 continue;
7027 }
7028 has_hostname = 1;
7029 #ifdef INET6
7030 /* I'm nice... I'll help those poor ipv6 users. -- Syzop */
7031 /* [ not null && len>6 && has not a : in it && last character is a digit ] */
7032 if (cep->ce_vardata && (strlen(cep->ce_vardata) > 6) && !strchr(cep->ce_vardata, ':') &&
7033 isdigit(cep->ce_vardata[strlen(cep->ce_vardata)-1]))
7034 {
7035 char crap[32];
7036 if (inet_pton(AF_INET, cep->ce_vardata, crap) != 0)
7037 {
7038 char ipv6buf[48];
7039 snprintf(ipv6buf, sizeof(ipv6buf), "::ffff:%s", cep->ce_vardata);
7040 MyFree(cep->ce_vardata);
7041 cep->ce_vardata = strdup(ipv6buf);
7042 } else {
7043 /* Insert IPv6 validation here */
7044 config_error( "%s:%i: cgiirc::hostname: '%s' looks like "
7045 "it might be IPv4, but is not a valid address.",
7046 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
7047 cep->ce_vardata);
7048 errors++;
7049 }
7050 }
7051 #endif
7052 }
7053 else if (!strcmp(cep->ce_varname, "password"))
7054 {
7055 if (has_password)
7056 {
7057 config_warn_duplicate(cep->ce_fileptr->cf_filename,
7058 cep->ce_varlinenum, "cgiirc::password");
7059 continue;
7060 }
7061 has_password = 1;
7062 if (Auth_CheckError(cep) < 0)
7063 errors++;
7064 }
7065 else if (!strcmp(cep->ce_varname, "type"))
7066 {
7067 if (has_type)
7068 {
7069 config_warn_duplicate(cep->ce_fileptr->cf_filename,
7070 cep->ce_varlinenum, "cgiirc::type");
7071 }
7072 has_type = 1;
7073 if (!strcmp(cep->ce_vardata, "webirc"))
7074 type = CGIIRC_WEBIRC;
7075 else if (!strcmp(cep->ce_vardata, "old"))
7076 type = CGIIRC_PASS;
7077 else
7078 {
7079 config_error("%s:%i: unknown cgiirc::type '%s', should be either 'webirc' or 'old'",
7080 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_vardata);
7081 errors++;
7082 }
7083 }
7084 else
7085 {
7086 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
7087 "cgiirc", cep->ce_varname);
7088 errors++;
7089 }
7090 }
7091 if (!has_hostname)
7092 {
7093 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
7094 "cgiirc::hostname");
7095 errors++;
7096 }
7097 if (!has_type)
7098 {
7099 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
7100 "cgiirc::type");
7101 errors++;
7102 } else
7103 {
7104 if (!has_password && (type == CGIIRC_WEBIRC))
7105 {
7106 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
7107 "cgiirc::password");
7108 errors++;
7109 } else
7110 if (has_password && (type == CGIIRC_PASS))
7111 {
7112 config_error("%s:%i: cgiirc block has type set to 'old' but has a password set. "
7113 "Passwords are not used with type 'old'. Either remove the password or "
7114 "use the 'webirc' method instead.",
7115 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
7116 errors++;
7117 }
7118 }
7119
7120 return errors;
7121 }
7122
_conf_ban(ConfigFile * conf,ConfigEntry * ce)7123 int _conf_ban(ConfigFile *conf, ConfigEntry *ce)
7124 {
7125
7126 ConfigEntry *cep;
7127 ConfigItem_ban *ca;
7128 Hook *h;
7129
7130 ca = MyMallocEx(sizeof(ConfigItem_ban));
7131 if (!strcmp(ce->ce_vardata, "nick"))
7132 {
7133 aTKline *nl = MyMallocEx(sizeof(aTKline));
7134 nl->type = TKL_NICK;
7135 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
7136 {
7137 if (!strcmp(cep->ce_varname, "mask"))
7138 nl->hostmask = strdup(cep->ce_vardata);
7139 else if (!strcmp(cep->ce_varname, "reason"))
7140 nl->reason = strdup(cep->ce_vardata);
7141 }
7142 strcpy(nl->usermask, "*");
7143 AddListItem(nl, tklines[tkl_hash('q')]);
7144 free(ca);
7145 return 0;
7146 }
7147 else if (!strcmp(ce->ce_vardata, "ip"))
7148 ca->flag.type = CONF_BAN_IP;
7149 else if (!strcmp(ce->ce_vardata, "server"))
7150 ca->flag.type = CONF_BAN_SERVER;
7151 else if (!strcmp(ce->ce_vardata, "user"))
7152 ca->flag.type = CONF_BAN_USER;
7153 else if (!strcmp(ce->ce_vardata, "realname"))
7154 ca->flag.type = CONF_BAN_REALNAME;
7155 else if (!strcmp(ce->ce_vardata, "version"))
7156 {
7157 ca->flag.type = CONF_BAN_VERSION;
7158 tempiConf.use_ban_version = 1;
7159 }
7160 else {
7161 int value;
7162 free(ca); /* ca isn't used, modules have their own list. */
7163 for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
7164 {
7165 value = (*(h->func.intfunc))(conf,ce,CONFIG_BAN);
7166 if (value == 1)
7167 break;
7168 }
7169 return 0;
7170 }
7171 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
7172 {
7173 if (!strcmp(cep->ce_varname, "mask"))
7174 {
7175 ca->mask = strdup(cep->ce_vardata);
7176 if (ca->flag.type == CONF_BAN_IP || ca->flag.type == CONF_BAN_USER)
7177 {
7178 struct irc_netmask tmp;
7179 tmp.type = parse_netmask(ca->mask, &tmp);
7180 if (tmp.type != HM_HOST)
7181 {
7182 ca->netmask = MyMallocEx(sizeof(struct irc_netmask));
7183 bcopy(&tmp, ca->netmask, sizeof(struct irc_netmask));
7184 }
7185 }
7186 }
7187 else if (!strcmp(cep->ce_varname, "reason"))
7188 ca->reason = strdup(cep->ce_vardata);
7189 else if (!strcmp(cep->ce_varname, "action"))
7190 ca ->action = banact_stringtoval(cep->ce_vardata);
7191 }
7192 AddListItem(ca, conf_ban);
7193 return 0;
7194 }
7195
_test_ban(ConfigFile * conf,ConfigEntry * ce)7196 int _test_ban(ConfigFile *conf, ConfigEntry *ce)
7197 {
7198 ConfigEntry *cep;
7199 int errors = 0;
7200 Hook *h;
7201 char type = 0;
7202 char has_mask = 0, has_action = 0, has_reason = 0;
7203
7204 if (!ce->ce_vardata)
7205 {
7206 config_error("%s:%i: ban without type",
7207 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
7208 return 1;
7209 }
7210 if (!strcmp(ce->ce_vardata, "nick"))
7211 {}
7212 else if (!strcmp(ce->ce_vardata, "ip"))
7213 {}
7214 else if (!strcmp(ce->ce_vardata, "server"))
7215 {}
7216 else if (!strcmp(ce->ce_vardata, "user"))
7217 {}
7218 else if (!strcmp(ce->ce_vardata, "realname"))
7219 {}
7220 else if (!strcmp(ce->ce_vardata, "version"))
7221 type = 'v';
7222 else
7223 {
7224 int used = 0;
7225 for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
7226 {
7227 int value, errs = 0;
7228 if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
7229 && !(h->owner->options & MOD_OPT_PERM))
7230 continue;
7231 value = (*(h->func.intfunc))(conf,ce,CONFIG_BAN, &errs);
7232 if (value == 2)
7233 used = 1;
7234 if (value == 1)
7235 {
7236 used = 1;
7237 break;
7238 }
7239 if (value == -1)
7240 {
7241 used = 1;
7242 errors += errs;
7243 break;
7244 }
7245 if (value == -2)
7246 {
7247 used = 1;
7248 errors += errs;
7249 }
7250 }
7251 if (!used) {
7252 config_error("%s:%i: unknown ban type %s",
7253 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
7254 ce->ce_vardata);
7255 return 1;
7256 }
7257 return errors;
7258 }
7259
7260 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
7261 {
7262 if (config_is_blankorempty(cep, "ban"))
7263 {
7264 errors++;
7265 continue;
7266 }
7267 if (!strcmp(cep->ce_varname, "mask"))
7268 {
7269 if (has_mask)
7270 {
7271 config_warn_duplicate(cep->ce_fileptr->cf_filename,
7272 cep->ce_varlinenum, "ban::mask");
7273 continue;
7274 }
7275 has_mask = 1;
7276 }
7277 else if (!strcmp(cep->ce_varname, "reason"))
7278 {
7279 if (has_reason)
7280 {
7281 config_warn_duplicate(cep->ce_fileptr->cf_filename,
7282 cep->ce_varlinenum, "ban::reason");
7283 continue;
7284 }
7285 has_reason = 1;
7286 }
7287 else if (!strcmp(cep->ce_varname, "action"))
7288 {
7289 if (has_action)
7290 {
7291 config_warn_duplicate(cep->ce_fileptr->cf_filename,
7292 cep->ce_varlinenum, "ban::action");
7293 }
7294 has_action = 1;
7295 if (!banact_stringtoval(cep->ce_vardata))
7296 {
7297 config_error("%s:%i: ban::action has unknown action type '%s'",
7298 cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
7299 cep->ce_vardata);
7300 errors++;
7301 }
7302 }
7303 }
7304
7305 if (!has_mask)
7306 {
7307 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
7308 "ban::mask");
7309 errors++;
7310 }
7311 if (!has_reason)
7312 {
7313 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
7314 "ban::reason");
7315 errors++;
7316 }
7317 if (has_action && type != 'v')
7318 {
7319 config_error("%s:%d: ban::action specified even though type is not 'version'",
7320 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
7321 errors++;
7322 }
7323 return errors;
7324 }
7325
_conf_set(ConfigFile * conf,ConfigEntry * ce)7326 int _conf_set(ConfigFile *conf, ConfigEntry *ce)
7327 {
7328 ConfigEntry *cep, *cepp, *ceppp;
7329 OperFlag *ofl = NULL;
7330 Hook *h;
7331
7332 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
7333 {
7334 if (!strcmp(cep->ce_varname, "kline-address")) {
7335 ircstrdup(tempiConf.kline_address, cep->ce_vardata);
7336 }
7337 if (!strcmp(cep->ce_varname, "gline-address")) {
7338 ircstrdup(tempiConf.gline_address, cep->ce_vardata);
7339 }
7340 else if (!strcmp(cep->ce_varname, "modes-on-connect")) {
7341 tempiConf.conn_modes = (long) set_usermode(cep->ce_vardata);
7342 }
7343 else if (!strcmp(cep->ce_varname, "modes-on-oper")) {
7344 tempiConf.oper_modes = (long) set_usermode(cep->ce_vardata);
7345 }
7346 else if (!strcmp(cep->ce_varname, "modes-on-join")) {
7347 set_channelmodes(cep->ce_vardata, &tempiConf.modes_on_join, 0);
7348 }
7349 else if (!strcmp(cep->ce_varname, "snomask-on-oper")) {
7350 ircstrdup(tempiConf.oper_snomask, cep->ce_vardata);
7351 }
7352 else if (!strcmp(cep->ce_varname, "snomask-on-connect")) {
7353 ircstrdup(tempiConf.user_snomask, cep->ce_vardata);
7354 }
7355 else if (!strcmp(cep->ce_varname, "level-on-join")) {
7356 tempiConf.level_on_join = channellevel_to_int(cep->ce_vardata);
7357 }
7358 else if (!strcmp(cep->ce_varname, "static-quit")) {
7359 ircstrdup(tempiConf.static_quit, cep->ce_vardata);
7360 }
7361 else if (!strcmp(cep->ce_varname, "static-part")) {
7362 ircstrdup(tempiConf.static_part, cep->ce_vardata);
7363 }
7364 else if (!strcmp(cep->ce_varname, "who-limit")) {
7365 tempiConf.who_limit = atol(cep->ce_vardata);
7366 }
7367 else if (!strcmp(cep->ce_varname, "maxbans")) {
7368 tempiConf.maxbans = atol(cep->ce_vardata);
7369 }
7370 else if (!strcmp(cep->ce_varname, "maxbanlength")) {
7371 tempiConf.maxbanlength = atol(cep->ce_vardata);
7372 }
7373 else if (!strcmp(cep->ce_varname, "silence-limit")) {
7374 tempiConf.silence_limit = atol(cep->ce_vardata);
7375 if (loop.ircd_booted)
7376 IsupportSetValue(IsupportFind("SILENCE"), cep->ce_vardata);
7377 }
7378 else if (!strcmp(cep->ce_varname, "auto-join")) {
7379 ircstrdup(tempiConf.auto_join_chans, cep->ce_vardata);
7380 }
7381 else if (!strcmp(cep->ce_varname, "oper-auto-join")) {
7382 ircstrdup(tempiConf.oper_auto_join_chans, cep->ce_vardata);
7383 }
7384 else if (!strcmp(cep->ce_varname, "check-target-nick-bans")) {
7385 tempiConf.check_target_nick_bans = config_checkval(cep->ce_vardata, CFG_YESNO);
7386 }
7387 else if (!strcmp(cep->ce_varname, "pingpong-warning")) {
7388 tempiConf.pingpong_warning = config_checkval(cep->ce_vardata, CFG_YESNO);
7389 }
7390 else if (!strcmp(cep->ce_varname, "ping-cookie")) {
7391 tempiConf.ping_cookie = config_checkval(cep->ce_vardata, CFG_YESNO);
7392 }
7393 else if (!strcmp(cep->ce_varname, "watch-away-notification")) {
7394 tempiConf.watch_away_notification = config_checkval(cep->ce_vardata, CFG_YESNO);
7395 }
7396 else if (!strcmp(cep->ce_varname, "uhnames")) {
7397 tempiConf.uhnames = config_checkval(cep->ce_vardata, CFG_YESNO);
7398 }
7399 else if (!strcmp(cep->ce_varname, "allow-userhost-change")) {
7400 if (!stricmp(cep->ce_vardata, "always"))
7401 tempiConf.userhost_allowed = UHALLOW_ALWAYS;
7402 else if (!stricmp(cep->ce_vardata, "never"))
7403 tempiConf.userhost_allowed = UHALLOW_NEVER;
7404 else if (!stricmp(cep->ce_vardata, "not-on-channels"))
7405 tempiConf.userhost_allowed = UHALLOW_NOCHANS;
7406 else
7407 tempiConf.userhost_allowed = UHALLOW_REJOIN;
7408 }
7409 else if (!strcmp(cep->ce_varname, "allowed-nickchars")) {
7410 for (cepp = cep->ce_entries; cepp; cepp=cepp->ce_next)
7411 charsys_add_language(cepp->ce_varname);
7412 }
7413 else if (!strcmp(cep->ce_varname, "channel-command-prefix")) {
7414 ircstrdup(tempiConf.channel_command_prefix, cep->ce_vardata);
7415 }
7416 else if (!strcmp(cep->ce_varname, "restrict-usermodes")) {
7417 int i;
7418 char *p = MyMalloc(strlen(cep->ce_vardata) + 1), *x = p;
7419 /* The data should be something like 'Gw' or something,
7420 * but just in case users use '+Gw' then ignore the + (and -).
7421 */
7422 for (i=0; i < strlen(cep->ce_vardata); i++)
7423 if ((cep->ce_vardata[i] != '+') && (cep->ce_vardata[i] != '-'))
7424 *x++ = cep->ce_vardata[i];
7425 *x = '\0';
7426 tempiConf.restrict_usermodes = p;
7427 }
7428 else if (!strcmp(cep->ce_varname, "restrict-channelmodes")) {
7429 int i;
7430 char *p = MyMalloc(strlen(cep->ce_vardata) + 1), *x = p;
7431 /* The data should be something like 'GL' or something,
7432 * but just in case users use '+GL' then ignore the + (and -).
7433 */
7434 for (i=0; i < strlen(cep->ce_vardata); i++)
7435 if ((cep->ce_vardata[i] != '+') && (cep->ce_vardata[i] != '-'))
7436 *x++ = cep->ce_vardata[i];
7437 *x = '\0';
7438 tempiConf.restrict_channelmodes = p;
7439 }
7440 else if (!strcmp(cep->ce_varname, "restrict-extendedbans")) {
7441 ircstrdup(tempiConf.restrict_extendedbans, cep->ce_vardata);
7442 }
7443 else if (!strcmp(cep->ce_varname, "new-linking-protocol")) {
7444 tempiConf.new_linking_protocol = atoi(cep->ce_vardata);
7445 }
7446 else if (!strcmp(cep->ce_varname, "anti-spam-quit-message-time")) {
7447 tempiConf.anti_spam_quit_message_time = config_checkval(cep->ce_vardata,CFG_TIME);
7448 }
7449 else if (!strcmp(cep->ce_varname, "oper-only-stats")) {
7450 if (!cep->ce_entries)
7451 {
7452 ircstrdup(tempiConf.oper_only_stats, cep->ce_vardata);
7453 }
7454 else
7455 {
7456 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
7457 {
7458 OperStat *os = MyMallocEx(sizeof(OperStat));
7459 ircstrdup(os->flag, cepp->ce_varname);
7460 AddListItem(os, tempiConf.oper_only_stats_ext);
7461 }
7462 }
7463 }
7464 else if (!strcmp(cep->ce_varname, "maxchannelsperuser")) {
7465 tempiConf.maxchannelsperuser = atoi(cep->ce_vardata);
7466 if (loop.ircd_booted)
7467 {
7468 char tmpbuf[512];
7469 IsupportSetValue(IsupportFind("MAXCHANNELS"), cep->ce_vardata);
7470 ircsprintf(tmpbuf, "#:%s", cep->ce_vardata);
7471 IsupportSetValue(IsupportFind("CHANLIMIT"), tmpbuf);
7472 }
7473 }
7474 else if (!strcmp(cep->ce_varname, "maxdccallow")) {
7475 tempiConf.maxdccallow = atoi(cep->ce_vardata);
7476 }
7477 else if (!strcmp(cep->ce_varname, "network-name")) {
7478 char *tmp;
7479 ircstrdup(tempiConf.network.x_ircnetwork, cep->ce_vardata);
7480 for (tmp = cep->ce_vardata; *cep->ce_vardata; cep->ce_vardata++) {
7481 if (*cep->ce_vardata == ' ')
7482 *cep->ce_vardata='-';
7483 }
7484 ircstrdup(tempiConf.network.x_ircnet005, tmp);
7485 if (loop.ircd_booted)
7486 IsupportSetValue(IsupportFind("NETWORK"), tmp);
7487 cep->ce_vardata = tmp;
7488 }
7489 else if (!strcmp(cep->ce_varname, "default-server")) {
7490 ircstrdup(tempiConf.network.x_defserv, cep->ce_vardata);
7491 }
7492 else if (!strcmp(cep->ce_varname, "services-server")) {
7493 ircstrdup(tempiConf.network.x_services_name, cep->ce_vardata);
7494 }
7495 else if (!strcmp(cep->ce_varname, "sasl-server")) {
7496 ircstrdup(tempiConf.network.x_sasl_server, cep->ce_vardata);
7497 }
7498 else if (!strcmp(cep->ce_varname, "stats-server")) {
7499 ircstrdup(tempiConf.network.x_stats_server, cep->ce_vardata);
7500 }
7501 else if (!strcmp(cep->ce_varname, "help-channel")) {
7502 ircstrdup(tempiConf.network.x_helpchan, cep->ce_vardata);
7503 }
7504 else if (!strcmp(cep->ce_varname, "hiddenhost-prefix")) {
7505 ircstrdup(tempiConf.network.x_hidden_host, cep->ce_vardata);
7506 }
7507 else if (!strcmp(cep->ce_varname, "prefix-quit")) {
7508 if (*cep->ce_vardata == '0')
7509 {
7510 ircstrdup(tempiConf.network.x_prefix_quit, "");
7511 }
7512 else
7513 ircstrdup(tempiConf.network.x_prefix_quit, cep->ce_vardata);
7514 }
7515 else if (!strcmp(cep->ce_varname, "dns")) {
7516 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
7517 if (!strcmp(cepp->ce_varname, "timeout")) {
7518 tempiConf.host_timeout = config_checkval(cepp->ce_vardata,CFG_TIME);
7519 }
7520 else if (!strcmp(cepp->ce_varname, "retries")) {
7521 tempiConf.host_retries = config_checkval(cepp->ce_vardata,CFG_TIME);
7522 }
7523 else if (!strcmp(cepp->ce_varname, "nameserver")) {
7524 ircstrdup(tempiConf.name_server, cepp->ce_vardata);
7525 }
7526 else if (!strcmp(cepp->ce_varname, "bind-ip")) {
7527 ircstrdup(tempiConf.dns_bindip, cepp->ce_vardata);
7528 }
7529 }
7530 }
7531 #ifdef THROTTLING
7532 else if (!strcmp(cep->ce_varname, "throttle")) {
7533 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
7534 if (!strcmp(cepp->ce_varname, "period"))
7535 tempiConf.throttle_period = config_checkval(cepp->ce_vardata,CFG_TIME);
7536 else if (!strcmp(cepp->ce_varname, "connections"))
7537 tempiConf.throttle_count = atoi(cepp->ce_vardata);
7538 }
7539 }
7540 #endif
7541 else if (!strcmp(cep->ce_varname, "anti-flood")) {
7542 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
7543 if (!strcmp(cepp->ce_varname, "unknown-flood-bantime"))
7544 tempiConf.unknown_flood_bantime = config_checkval(cepp->ce_vardata,CFG_TIME);
7545 else if (!strcmp(cepp->ce_varname, "unknown-flood-amount"))
7546 tempiConf.unknown_flood_amount = atol(cepp->ce_vardata);
7547 #ifdef NO_FLOOD_AWAY
7548 else if (!strcmp(cepp->ce_varname, "away-count"))
7549 tempiConf.away_count = atol(cepp->ce_vardata);
7550 else if (!strcmp(cepp->ce_varname, "away-period"))
7551 tempiConf.away_period = config_checkval(cepp->ce_vardata, CFG_TIME);
7552 else if (!strcmp(cepp->ce_varname, "away-flood"))
7553 {
7554 int cnt, period;
7555 config_parse_flood(cepp->ce_vardata, &cnt, &period);
7556 tempiConf.away_count = cnt;
7557 tempiConf.away_period = period;
7558 }
7559 #endif
7560 else if (!strcmp(cepp->ce_varname, "nick-flood"))
7561 {
7562 int cnt, period;
7563 config_parse_flood(cepp->ce_vardata, &cnt, &period);
7564 tempiConf.nick_count = cnt;
7565 tempiConf.nick_period = period;
7566 }
7567
7568 }
7569 }
7570 else if (!strcmp(cep->ce_varname, "options")) {
7571 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
7572 if (!strcmp(cepp->ce_varname, "webtv-support")) {
7573 tempiConf.webtv_support = 1;
7574 }
7575 else if (!strcmp(cepp->ce_varname, "hide-ulines")) {
7576 tempiConf.hide_ulines = 1;
7577 }
7578 else if (!strcmp(cepp->ce_varname, "flat-map")) {
7579 tempiConf.flat_map = 1;
7580 }
7581 else if (!strcmp(cepp->ce_varname, "no-stealth")) {
7582 tempiConf.no_oper_hiding = 1;
7583 }
7584 else if (!strcmp(cepp->ce_varname, "show-opermotd")) {
7585 tempiConf.som = 1;
7586 }
7587 else if (!strcmp(cepp->ce_varname, "identd-check")) {
7588 tempiConf.ident_check = 1;
7589 }
7590 else if (!strcmp(cepp->ce_varname, "fail-oper-warn")) {
7591 tempiConf.fail_oper_warn = 1;
7592 }
7593 else if (!strcmp(cepp->ce_varname, "show-connect-info")) {
7594 tempiConf.show_connect_info = 1;
7595 }
7596 else if (!strcmp(cepp->ce_varname, "dont-resolve")) {
7597 tempiConf.dont_resolve = 1;
7598 }
7599 else if (!strcmp(cepp->ce_varname, "mkpasswd-for-everyone")) {
7600 tempiConf.mkpasswd_for_everyone = 1;
7601 }
7602 else if (!strcmp(cepp->ce_varname, "allow-insane-bans")) {
7603 tempiConf.allow_insane_bans = 1;
7604 }
7605 else if (!strcmp(cepp->ce_varname, "allow-part-if-shunned")) {
7606 tempiConf.allow_part_if_shunned = 1;
7607 }
7608 else if (!strcmp(cepp->ce_varname, "disable-cap")) {
7609 tempiConf.disable_cap = 1;
7610 }
7611 }
7612 }
7613 else if (!strcmp(cep->ce_varname, "hosts")) {
7614 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
7615 {
7616 if (!strcmp(cepp->ce_varname, "local")) {
7617 ircstrdup(tempiConf.network.x_locop_host, cepp->ce_vardata);
7618 }
7619 else if (!strcmp(cepp->ce_varname, "global")) {
7620 ircstrdup(tempiConf.network.x_oper_host, cepp->ce_vardata);
7621 }
7622 else if (!strcmp(cepp->ce_varname, "coadmin")) {
7623 ircstrdup(tempiConf.network.x_coadmin_host, cepp->ce_vardata);
7624 }
7625 else if (!strcmp(cepp->ce_varname, "admin")) {
7626 ircstrdup(tempiConf.network.x_admin_host, cepp->ce_vardata);
7627 }
7628 else if (!strcmp(cepp->ce_varname, "servicesadmin")) {
7629 ircstrdup(tempiConf.network.x_sadmin_host, cepp->ce_vardata);
7630 }
7631 else if (!strcmp(cepp->ce_varname, "netadmin")) {
7632 ircstrdup(tempiConf.network.x_netadmin_host, cepp->ce_vardata);
7633 }
7634 else if (!strcmp(cepp->ce_varname, "host-on-oper-up")) {
7635 tempiConf.network.x_inah = config_checkval(cepp->ce_vardata,CFG_YESNO);
7636 }
7637 }
7638 }
7639 else if (!strcmp(cep->ce_varname, "cloak-keys"))
7640 {
7641 for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
7642 {
7643 int value;
7644 value = (*(h->func.intfunc))(conf, cep, CONFIG_CLOAKKEYS);
7645 if (value == 1)
7646 break;
7647 }
7648 }
7649 else if (!strcmp(cep->ce_varname, "ident"))
7650 {
7651 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
7652 {
7653 if (!strcmp(cepp->ce_varname, "connect-timeout"))
7654 tempiConf.ident_connect_timeout = config_checkval(cepp->ce_vardata,CFG_TIME);
7655 if (!strcmp(cepp->ce_varname, "read-timeout"))
7656 tempiConf.ident_read_timeout = config_checkval(cepp->ce_vardata,CFG_TIME);
7657 }
7658 }
7659 else if (!strcmp(cep->ce_varname, "timesync") || !strcmp(cep->ce_varname, "timesynch"))
7660 {
7661 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
7662 {
7663 if (!strcmp(cepp->ce_varname, "enabled"))
7664 tempiConf.timesynch_enabled = config_checkval(cepp->ce_vardata,CFG_YESNO);
7665 else if (!strcmp(cepp->ce_varname, "timeout"))
7666 tempiConf.timesynch_timeout = config_checkval(cepp->ce_vardata,CFG_TIME);
7667 else if (!strcmp(cepp->ce_varname, "server"))
7668 ircstrdup(tempiConf.timesynch_server, cepp->ce_vardata);
7669 }
7670 }
7671 else if (!strcmp(cep->ce_varname, "spamfilter"))
7672 {
7673 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
7674 {
7675 if (!strcmp(cepp->ce_varname, "ban-time"))
7676 tempiConf.spamfilter_ban_time = config_checkval(cepp->ce_vardata,CFG_TIME);
7677 else if (!strcmp(cepp->ce_varname, "ban-reason"))
7678 ircstrdup(tempiConf.spamfilter_ban_reason, cepp->ce_vardata);
7679 else if (!strcmp(cepp->ce_varname, "virus-help-channel"))
7680 ircstrdup(tempiConf.spamfilter_virus_help_channel, cepp->ce_vardata);
7681 else if (!strcmp(cepp->ce_varname, "virus-help-channel-deny"))
7682 tempiConf.spamfilter_vchan_deny = config_checkval(cepp->ce_vardata,CFG_YESNO);
7683 else if (!strcmp(cepp->ce_varname, "except"))
7684 {
7685 char *name, *p;
7686 SpamExcept *e;
7687 ircstrdup(tempiConf.spamexcept_line, cepp->ce_vardata);
7688 for (name = strtoken(&p, cepp->ce_vardata, ","); name; name = strtoken(&p, NULL, ","))
7689 {
7690 if (*name == ' ')
7691 name++;
7692 if (*name)
7693 {
7694 e = MyMallocEx(sizeof(SpamExcept) + strlen(name));
7695 strcpy(e->name, name);
7696 AddListItem(e, tempiConf.spamexcept);
7697 }
7698 }
7699 }
7700 else if (!strcmp(cepp->ce_varname, "detect-slow-warn"))
7701 {
7702 tempiConf.spamfilter_detectslow_warn = atol(cepp->ce_vardata);
7703 }
7704 else if (!strcmp(cepp->ce_varname, "detect-slow-fatal"))
7705 {
7706 tempiConf.spamfilter_detectslow_fatal = atol(cepp->ce_vardata);
7707 }
7708 else if (!strcmp(cepp->ce_varname, "stop-on-first-match"))
7709 {
7710 tempiConf.spamfilter_stop_on_first_match = config_checkval(cepp->ce_vardata, CFG_YESNO);
7711 }
7712 }
7713 }
7714 else if (!strcmp(cep->ce_varname, "default-bantime"))
7715 {
7716 tempiConf.default_bantime = config_checkval(cep->ce_vardata,CFG_TIME);
7717 }
7718 else if (!strcmp(cep->ce_varname, "ban-version-tkl-time"))
7719 {
7720 tempiConf.ban_version_tkl_time = config_checkval(cep->ce_vardata,CFG_TIME);
7721 }
7722 #ifdef NEWCHFLOODPROT
7723 else if (!strcmp(cep->ce_varname, "modef-default-unsettime")) {
7724 int v = atoi(cep->ce_vardata);
7725 tempiConf.modef_default_unsettime = (unsigned char)v;
7726 }
7727 else if (!strcmp(cep->ce_varname, "modef-max-unsettime")) {
7728 int v = atoi(cep->ce_vardata);
7729 tempiConf.modef_max_unsettime = (unsigned char)v;
7730 }
7731 #endif
7732 else if (!strcmp(cep->ce_varname, "ssl")) {
7733 #ifdef USE_SSL
7734 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
7735 if (!strcmp(cepp->ce_varname, "egd")) {
7736 tempiConf.use_egd = 1;
7737 if (cepp->ce_vardata)
7738 tempiConf.egd_path = strdup(cepp->ce_vardata);
7739 }
7740 else if (!strcmp(cepp->ce_varname, "server-cipher-list"))
7741 {
7742 ircstrdup(tempiConf.x_server_cipher_list, cepp->ce_vardata);
7743 }
7744 else if (!strcmp(cepp->ce_varname, "certificate"))
7745 {
7746 ircstrdup(tempiConf.x_server_cert_pem, cepp->ce_vardata);
7747 }
7748 else if (!strcmp(cepp->ce_varname, "key"))
7749 {
7750 ircstrdup(tempiConf.x_server_key_pem, cepp->ce_vardata);
7751 }
7752 else if (!strcmp(cepp->ce_varname, "trusted-ca-file"))
7753 {
7754 ircstrdup(tempiConf.trusted_ca_file, cepp->ce_vardata);
7755 }
7756 else if (!strcmp(cepp->ce_varname, "renegotiate-bytes"))
7757 {
7758 tempiConf.ssl_renegotiate_bytes = config_checkval(cepp->ce_vardata, CFG_SIZE);
7759 }
7760 else if (!strcmp(cepp->ce_varname, "renegotiate-timeout"))
7761 {
7762 tempiConf.ssl_renegotiate_timeout = config_checkval(cepp->ce_vardata, CFG_TIME);
7763 }
7764 else if (!strcmp(cepp->ce_varname, "options"))
7765 {
7766 tempiConf.ssl_options = 0;
7767 for (ceppp = cepp->ce_entries; ceppp; ceppp = ceppp->ce_next)
7768 {
7769 ofl = config_binary_flags_search(_SSLFlags, ceppp->ce_varname, ARRAY_SIZEOF(_SSLFlags));
7770 if (ofl) /* this should always be true */
7771 tempiConf.ssl_options |= ofl->flag;
7772 }
7773 if (tempiConf.ssl_options & SSLFLAG_DONOTACCEPTSELFSIGNED)
7774 if (!tempiConf.ssl_options & SSLFLAG_VERIFYCERT)
7775 tempiConf.ssl_options |= SSLFLAG_VERIFYCERT;
7776 }
7777
7778 }
7779 #endif /* USE_SSL */
7780 }
7781 else if (!strcmp(cep->ce_varname, "default-ipv6-clone-mask"))
7782 {
7783 #ifdef INET6
7784 tempiConf.default_ipv6_clone_mask = atoi(cep->ce_vardata);
7785 #endif /* INET6 */
7786 }
7787 else
7788 {
7789 int value;
7790 for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
7791 {
7792 value = (*(h->func.intfunc))(conf,cep,CONFIG_SET);
7793 if (value == 1)
7794 break;
7795 }
7796 }
7797 }
7798 return 0;
7799 }
7800
_test_set(ConfigFile * conf,ConfigEntry * ce)7801 int _test_set(ConfigFile *conf, ConfigEntry *ce)
7802 {
7803 ConfigEntry *cep, *cepp, *ceppp;
7804 long templong;
7805 int tempi;
7806 int errors = 0;
7807 Hook *h;
7808 #define CheckNull(x) if ((!(x)->ce_vardata) || (!(*((x)->ce_vardata)))) { config_error("%s:%i: missing parameter", (x)->ce_fileptr->cf_filename, (x)->ce_varlinenum); errors++; continue; }
7809 #define CheckNullAllowEmpty(x) if ((!(x)->ce_vardata)) { config_error("%s:%i: missing parameter", (x)->ce_fileptr->cf_filename, (x)->ce_varlinenum); errors++; continue; }
7810 #define CheckDuplicate(cep, name, display) if (settings.has_##name) { config_warn_duplicate((cep)->ce_fileptr->cf_filename, cep->ce_varlinenum, "set::" display); continue; } else settings.has_##name = 1
7811
7812 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
7813 {
7814 if (!cep->ce_varname)
7815 {
7816 config_error_blank(cep->ce_fileptr->cf_filename,
7817 cep->ce_varlinenum, "set");
7818 errors++;
7819 continue;
7820 }
7821 if (!strcmp(cep->ce_varname, "kline-address")) {
7822 CheckNull(cep);
7823 CheckDuplicate(cep, kline_address, "kline-address");
7824 if (!strchr(cep->ce_vardata, '@') && !strchr(cep->ce_vardata, ':'))
7825 {
7826 config_error("%s:%i: set::kline-address must be an e-mail or an URL",
7827 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
7828 errors++;
7829 continue;
7830 }
7831 else if (!match("*@unrealircd.com", cep->ce_vardata) || !match("*@unrealircd.org",cep->ce_vardata) || !match("unreal-*@lists.sourceforge.net",cep->ce_vardata))
7832 {
7833 config_error("%s:%i: set::kline-address may not be an UnrealIRCd Team address",
7834 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
7835 errors++; continue;
7836 }
7837 }
7838 else if (!strcmp(cep->ce_varname, "gline-address")) {
7839 CheckNull(cep);
7840 CheckDuplicate(cep, gline_address, "gline-address");
7841 if (!strchr(cep->ce_vardata, '@') && !strchr(cep->ce_vardata, ':'))
7842 {
7843 config_error("%s:%i: set::gline-address must be an e-mail or an URL",
7844 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
7845 errors++;
7846 continue;
7847 }
7848 else if (!match("*@unrealircd.com", cep->ce_vardata) || !match("*@unrealircd.org",cep->ce_vardata) || !match("unreal-*@lists.sourceforge.net",cep->ce_vardata))
7849 {
7850 config_error("%s:%i: set::gline-address may not be an UnrealIRCd Team address",
7851 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
7852 errors++; continue;
7853 }
7854 }
7855 else if (!strcmp(cep->ce_varname, "modes-on-connect")) {
7856 char *p;
7857 CheckNull(cep);
7858 CheckDuplicate(cep, modes_on_connect, "modes-on-connect");
7859 for (p = cep->ce_vardata; *p; p++)
7860 if (strchr("oOaANCrzSgHhqtW", *p))
7861 {
7862 config_error("%s:%i: set::modes-on-connect may not include mode '%c'",
7863 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
7864 errors++;
7865 }
7866 templong = (long) set_usermode(cep->ce_vardata);
7867 }
7868 else if (!strcmp(cep->ce_varname, "modes-on-join")) {
7869 char *c;
7870 struct ChMode temp;
7871 bzero(&temp, sizeof(temp));
7872 CheckNull(cep);
7873 CheckDuplicate(cep, modes_on_join, "modes-on-join");
7874 for (c = cep->ce_vardata; *c; c++)
7875 {
7876 if (*c == ' ')
7877 break; /* don't check the parameter ;p */
7878 switch (*c)
7879 {
7880 case 'q':
7881 case 'a':
7882 case 'o':
7883 case 'h':
7884 case 'v':
7885 case 'b':
7886 case 'e':
7887 case 'I':
7888 case 'O':
7889 case 'A':
7890 case 'z':
7891 case 'l':
7892 case 'k':
7893 case 'L':
7894 config_error("%s:%i: set::modes-on-join contains +%c",
7895 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *c);
7896 errors++;
7897 break;
7898 }
7899 }
7900 set_channelmodes(cep->ce_vardata, &temp, 1);
7901 if (temp.mode & MODE_NOKNOCK && !(temp.mode & MODE_INVITEONLY))
7902 {
7903 config_error("%s:%i: set::modes-on-join has +K but not +i",
7904 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
7905 errors++;
7906 }
7907 if (temp.mode & MODE_NOCOLOR && temp.mode & MODE_STRIP)
7908 {
7909 config_error("%s:%i: set::modes-on-join has +c and +S",
7910 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
7911 errors++;
7912 }
7913 if (temp.mode & MODE_SECRET && temp.mode & MODE_PRIVATE)
7914 {
7915 config_error("%s:%i: set::modes-on-join has +s and +p",
7916 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
7917 errors++;
7918 }
7919
7920 }
7921 else if (!strcmp(cep->ce_varname, "modes-on-oper")) {
7922 char *p;
7923 CheckNull(cep);
7924 CheckDuplicate(cep, modes_on_oper, "modes-on-oper");
7925 for (p = cep->ce_vardata; *p; p++)
7926 if (strchr("oOaANCrzS", *p))
7927 {
7928 config_error("%s:%i: set::modes-on-oper may not include mode '%c'",
7929 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
7930 errors++;
7931 }
7932 templong = (long) set_usermode(cep->ce_vardata);
7933 }
7934 else if (!strcmp(cep->ce_varname, "snomask-on-oper")) {
7935 CheckNull(cep);
7936 CheckDuplicate(cep, snomask_on_oper, "snomask-on-oper");
7937 }
7938 else if (!strcmp(cep->ce_varname, "snomask-on-connect")) {
7939 CheckNull(cep);
7940 CheckDuplicate(cep, snomask_on_connect, "snomask-on-connect");
7941 }
7942 else if (!strcmp(cep->ce_varname, "level-on-join")) {
7943 char *p;
7944 CheckNull(cep);
7945 CheckDuplicate(cep, level_on_join, "level-on-join");
7946 if (!channellevel_to_int(cep->ce_vardata))
7947 {
7948 config_error("%s:%i: set::level-on-join: unknown value '%s', should be one of: none, voice, halfop, op, protect, owner",
7949 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_vardata);
7950 errors++;
7951 }
7952 }
7953 else if (!strcmp(cep->ce_varname, "static-quit")) {
7954 CheckNull(cep);
7955 CheckDuplicate(cep, static_quit, "static-quit");
7956 }
7957 else if (!strcmp(cep->ce_varname, "static-part")) {
7958 CheckNull(cep);
7959 CheckDuplicate(cep, static_part, "static-part");
7960 }
7961 else if (!strcmp(cep->ce_varname, "who-limit")) {
7962 CheckNull(cep);
7963 CheckDuplicate(cep, who_limit, "who-limit");
7964 }
7965 else if (!strcmp(cep->ce_varname, "maxbans")) {
7966 CheckNull(cep);
7967 CheckDuplicate(cep, maxbans, "maxbans");
7968 }
7969 else if (!strcmp(cep->ce_varname, "maxbanlength")) {
7970 CheckNull(cep);
7971 CheckDuplicate(cep, maxbanlength, "maxbanlength");
7972 }
7973 else if (!strcmp(cep->ce_varname, "silence-limit")) {
7974 CheckNull(cep);
7975 CheckDuplicate(cep, silence_limit, "silence-limit");
7976 }
7977 else if (!strcmp(cep->ce_varname, "auto-join")) {
7978 CheckNull(cep);
7979 CheckDuplicate(cep, auto_join, "auto-join");
7980 }
7981 else if (!strcmp(cep->ce_varname, "oper-auto-join")) {
7982 CheckNull(cep);
7983 CheckDuplicate(cep, oper_auto_join, "oper-auto-join");
7984 }
7985 else if (!strcmp(cep->ce_varname, "check-target-nick-bans")) {
7986 CheckNull(cep);
7987 CheckDuplicate(cep, check_target_nick_bans, "check-target-nick-bans");
7988 }
7989 else if (!strcmp(cep->ce_varname, "pingpong-warning")) {
7990 CheckNull(cep);
7991 CheckDuplicate(cep, pingpong_warning, "pingpong-warning");
7992 }
7993 else if (!strcmp(cep->ce_varname, "ping-cookie")) {
7994 CheckNull(cep);
7995 CheckDuplicate(cep, ping_cookie, "ping-cookie");
7996 }
7997 else if (!strcmp(cep->ce_varname, "watch-away-notification")) {
7998 CheckNull(cep);
7999 CheckDuplicate(cep, watch_away_notification, "watch-away-notification");
8000 }
8001 else if (!strcmp(cep->ce_varname, "uhnames")) {
8002 CheckNull(cep);
8003 CheckDuplicate(cep, uhnames, "uhnames");
8004 }
8005 else if (!strcmp(cep->ce_varname, "channel-command-prefix")) {
8006 CheckNullAllowEmpty(cep);
8007 CheckDuplicate(cep, channel_command_prefix, "channel-command-prefix");
8008 }
8009 else if (!strcmp(cep->ce_varname, "allow-userhost-change")) {
8010 CheckNull(cep);
8011 CheckDuplicate(cep, allow_userhost_change, "allow-userhost-change");
8012 if (stricmp(cep->ce_vardata, "always") &&
8013 stricmp(cep->ce_vardata, "never") &&
8014 stricmp(cep->ce_vardata, "not-on-channels") &&
8015 stricmp(cep->ce_vardata, "force-rejoin"))
8016 {
8017 config_error("%s:%i: set::allow-userhost-change is invalid",
8018 cep->ce_fileptr->cf_filename,
8019 cep->ce_varlinenum);
8020 errors++;
8021 continue;
8022 }
8023 }
8024 else if (!strcmp(cep->ce_varname, "allowed-nickchars")) {
8025 if (cep->ce_vardata)
8026 {
8027 config_error("%s:%i: set::allowed-nickchars: please use 'allowed-nickchars { name; };' "
8028 "and not 'allowed-nickchars name;'",
8029 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
8030 errors++;
8031 continue;
8032 }
8033 for (cepp = cep->ce_entries; cepp; cepp=cepp->ce_next)
8034 {
8035 if (!charsys_test_language(cepp->ce_varname))
8036 {
8037 config_error("%s:%i: set::allowed-nickchars: Unknown (sub)language '%s'",
8038 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cepp->ce_varname);
8039 errors++;
8040 }
8041 }
8042 }
8043 else if (!strcmp(cep->ce_varname, "anti-spam-quit-message-time")) {
8044 CheckNull(cep);
8045 CheckDuplicate(cep, anti_spam_quit_message_time, "anti-spam-quit-message-time");
8046 }
8047 else if (!strcmp(cep->ce_varname, "oper-only-stats")) {
8048 CheckDuplicate(cep, oper_only_stats, "oper-only-stats");
8049 if (!cep->ce_entries)
8050 {
8051 CheckNull(cep);
8052 }
8053 else
8054 {
8055 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
8056 {
8057 if (!cepp->ce_varname)
8058 config_error("%s:%i: blank set::oper-only-stats item",
8059 cepp->ce_fileptr->cf_filename,
8060 cepp->ce_varlinenum);
8061 }
8062 }
8063 }
8064 else if (!strcmp(cep->ce_varname, "maxchannelsperuser")) {
8065 CheckNull(cep);
8066 CheckDuplicate(cep, maxchannelsperuser, "maxchannelsperuser");
8067 tempi = atoi(cep->ce_vardata);
8068 if (tempi < 1)
8069 {
8070 config_error("%s:%i: set::maxchannelsperuser must be > 0",
8071 cep->ce_fileptr->cf_filename,
8072 cep->ce_varlinenum);
8073 errors++;
8074 continue;
8075 }
8076 }
8077 else if (!strcmp(cep->ce_varname, "maxdccallow")) {
8078 CheckNull(cep);
8079 CheckDuplicate(cep, maxdccallow, "maxdccallow");
8080 }
8081 else if (!strcmp(cep->ce_varname, "network-name")) {
8082 char *p;
8083 CheckNull(cep);
8084 CheckDuplicate(cep, network_name, "network-name");
8085 for (p = cep->ce_vardata; *p; p++)
8086 if ((*p < ' ') || (*p > '~'))
8087 {
8088 config_error("%s:%i: set::network-name can only contain ASCII characters 33-126. Invalid character = '%c'",
8089 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, *p);
8090 errors++;
8091 break;
8092 }
8093 }
8094 else if (!strcmp(cep->ce_varname, "default-server")) {
8095 CheckNull(cep);
8096 CheckDuplicate(cep, default_server, "default-server");
8097 }
8098 else if (!strcmp(cep->ce_varname, "services-server")) {
8099 CheckNull(cep);
8100 CheckDuplicate(cep, services_server, "services-server");
8101 }
8102 else if (!strcmp(cep->ce_varname, "sasl-server")) {
8103 CheckNull(cep);
8104 CheckDuplicate(cep, sasl_server, "sasl-server");
8105 }
8106 else if (!strcmp(cep->ce_varname, "stats-server")) {
8107 CheckNull(cep);
8108 CheckDuplicate(cep, stats_server, "stats-server");
8109 }
8110 else if (!strcmp(cep->ce_varname, "help-channel")) {
8111 CheckNull(cep);
8112 CheckDuplicate(cep, help_channel, "help-channel");
8113 }
8114 else if (!strcmp(cep->ce_varname, "hiddenhost-prefix")) {
8115 CheckNull(cep);
8116 CheckDuplicate(cep, hiddenhost_prefix, "hiddenhost-prefix");
8117 if (strchr(cep->ce_vardata, ' ') || (*cep->ce_vardata == ':'))
8118 {
8119 config_error("%s:%i: set::hiddenhost-prefix must not contain spaces or be prefixed with ':'",
8120 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
8121 errors++;
8122 continue;
8123 }
8124 }
8125 else if (!strcmp(cep->ce_varname, "prefix-quit")) {
8126 CheckNull(cep);
8127 CheckDuplicate(cep, prefix_quit, "prefix-quit");
8128 }
8129 else if (!strcmp(cep->ce_varname, "restrict-usermodes"))
8130 {
8131 CheckNull(cep);
8132 CheckDuplicate(cep, restrict_usermodes, "restrict-usermodes");
8133 if (cep->ce_varname) {
8134 int warn = 0;
8135 char *p;
8136 for (p = cep->ce_vardata; *p; p++)
8137 if ((*p == '+') || (*p == '-'))
8138 warn = 1;
8139 if (warn) {
8140 config_status("%s:%i: warning: set::restrict-usermodes: should only contain modechars, no + or -.\n",
8141 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
8142 }
8143 }
8144 }
8145 else if (!strcmp(cep->ce_varname, "restrict-channelmodes"))
8146 {
8147 CheckNull(cep);
8148 CheckDuplicate(cep, restrict_channelmodes, "restrict-channelmodes");
8149 if (cep->ce_varname) {
8150 int warn = 0;
8151 char *p;
8152 for (p = cep->ce_vardata; *p; p++)
8153 if ((*p == '+') || (*p == '-'))
8154 warn = 1;
8155 if (warn) {
8156 config_status("%s:%i: warning: set::restrict-channelmodes: should only contain modechars, no + or -.\n",
8157 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
8158 }
8159 }
8160 }
8161 else if (!strcmp(cep->ce_varname, "restrict-extendedbans"))
8162 {
8163 CheckDuplicate(cep, restrict_extendedbans, "restrict-extendedbans");
8164 CheckNull(cep);
8165 }
8166 else if (!strcmp(cep->ce_varname, "new-linking-protocol"))
8167 {
8168 CheckDuplicate(cep, new_linking_protocol, "new-linking-protocol");
8169 CheckNull(cep);
8170 }
8171 else if (!strcmp(cep->ce_varname, "dns")) {
8172 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
8173 CheckNull(cepp);
8174 if (!strcmp(cepp->ce_varname, "timeout")) {
8175 CheckDuplicate(cepp, dns_timeout, "dns::timeout");
8176 }
8177 else if (!strcmp(cepp->ce_varname, "retries")) {
8178 CheckDuplicate(cepp, dns_retries, "dns::retries");
8179 }
8180 else if (!strcmp(cepp->ce_varname, "nameserver")) {
8181 struct in_addr in;
8182 CheckDuplicate(cepp, dns_nameserver, "dns::nameserver");
8183
8184 in.s_addr = inet_addr(cepp->ce_vardata);
8185 if (strcmp((char *)inet_ntoa(in), cepp->ce_vardata))
8186 {
8187 config_error("%s:%i: set::dns::nameserver (%s) is not a valid IP",
8188 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
8189 cepp->ce_vardata);
8190 errors++;
8191 continue;
8192 }
8193 }
8194 else if (!strcmp(cepp->ce_varname, "bind-ip")) {
8195 struct in_addr in;
8196 CheckDuplicate(cepp, dns_bind_ip, "dns::bind-ip");
8197 if (strcmp(cepp->ce_vardata, "*"))
8198 {
8199 in.s_addr = inet_addr(cepp->ce_vardata);
8200 if (strcmp((char *)inet_ntoa(in), cepp->ce_vardata))
8201 {
8202 config_error("%s:%i: set::dns::bind-ip (%s) is not a valid IP",
8203 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
8204 cepp->ce_vardata);
8205 errors++;
8206 continue;
8207 }
8208 }
8209 }
8210 else
8211 {
8212 config_error_unknownopt(cepp->ce_fileptr->cf_filename,
8213 cepp->ce_varlinenum, "set::dns",
8214 cepp->ce_varname);
8215 errors++;
8216 }
8217 }
8218 }
8219 #ifdef THROTTLING
8220 else if (!strcmp(cep->ce_varname, "throttle")) {
8221 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
8222 CheckNull(cepp);
8223 if (!strcmp(cepp->ce_varname, "period")) {
8224 int x = config_checkval(cepp->ce_vardata,CFG_TIME);
8225 CheckDuplicate(cepp, throttle_period, "throttle::period");
8226 if (x > 86400*7)
8227 {
8228 config_error("%s:%i: insane set::throttle::period value",
8229 cepp->ce_fileptr->cf_filename,
8230 cepp->ce_varlinenum);
8231 errors++;
8232 continue;
8233 }
8234 }
8235 else if (!strcmp(cepp->ce_varname, "connections")) {
8236 int x = atoi(cepp->ce_vardata);
8237 CheckDuplicate(cepp, throttle_connections, "throttle::connections");
8238 if ((x < 1) || (x > 127))
8239 {
8240 config_error("%s:%i: set::throttle::connections out of range, should be 1-127",
8241 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
8242 errors++;
8243 continue;
8244 }
8245 }
8246 else
8247 {
8248 config_error_unknownopt(cepp->ce_fileptr->cf_filename,
8249 cepp->ce_varlinenum, "set::throttle",
8250 cepp->ce_varname);
8251 errors++;
8252 continue;
8253 }
8254 }
8255 }
8256 #endif
8257 else if (!strcmp(cep->ce_varname, "anti-flood")) {
8258 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
8259 CheckNull(cepp);
8260 if (!strcmp(cepp->ce_varname, "unknown-flood-bantime"))
8261 {
8262 CheckDuplicate(cepp, anti_flood_unknown_flood_bantime, "anti-flood::unknown-flood-bantime");
8263 }
8264 else if (!strcmp(cepp->ce_varname, "unknown-flood-amount")) {
8265 CheckDuplicate(cepp, anti_flood_unknown_flood_amount, "anti-flood::unknown-flood-amount");
8266 }
8267 #ifdef NO_FLOOD_AWAY
8268 else if (!strcmp(cepp->ce_varname, "away-count")) {
8269 int temp = atol(cepp->ce_vardata);
8270 CheckDuplicate(cepp, anti_flood_away_count, "anti-flood::away-count");
8271 if (temp < 1 || temp > 255)
8272 {
8273 config_error("%s:%i: set::anti-flood::away-count must be between 1 and 255",
8274 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
8275 errors++;
8276 }
8277 }
8278 else if (!strcmp(cepp->ce_varname, "away-period")) {
8279 int temp = config_checkval(cepp->ce_vardata, CFG_TIME);
8280 CheckDuplicate(cepp, anti_flood_away_period, "anti-flood::away-period");
8281 if (temp < 10)
8282 {
8283 config_error("%s:%i: set::anti-flood::away-period must be greater than 9",
8284 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
8285 errors++;
8286 }
8287 }
8288 else if (!strcmp(cepp->ce_varname, "away-flood"))
8289 {
8290 int cnt, period;
8291 if (settings.has_anti_flood_away_period)
8292 {
8293 config_warn("%s:%d: set::anti-flood::away-flood overrides set::anti-flood::away-period",
8294 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
8295 continue;
8296 }
8297 if (settings.has_anti_flood_away_count)
8298 {
8299 config_warn("%s:%d: set::anti-flood::away-flood overrides set::anti-flood::away-count",
8300 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
8301 continue;
8302 }
8303 settings.has_anti_flood_away_period = 1;
8304 settings.has_anti_flood_away_count = 1;
8305 if (!config_parse_flood(cepp->ce_vardata, &cnt, &period) ||
8306 (cnt < 1) || (cnt > 255) || (period < 10))
8307 {
8308 config_error("%s:%i: set::anti-flood::away-flood error. Syntax is '<count>:<period>' (eg 5:60), "
8309 "count should be 1-255, period should be greater than 9",
8310 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
8311 errors++;
8312 }
8313 }
8314 #endif
8315 else if (!strcmp(cepp->ce_varname, "nick-flood"))
8316 {
8317 int cnt, period;
8318 CheckDuplicate(cepp, anti_flood_nick_flood, "anti-flood::nick-flood");
8319 if (!config_parse_flood(cepp->ce_vardata, &cnt, &period) ||
8320 (cnt < 1) || (cnt > 255) || (period < 5))
8321 {
8322 config_error("%s:%i: set::anti-flood::away-flood error. Syntax is '<count>:<period>' (eg 5:60), "
8323 "count should be 1-255, period should be greater than 4",
8324 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
8325 errors++;
8326 }
8327 }
8328 else
8329 {
8330 config_error_unknownopt(cepp->ce_fileptr->cf_filename,
8331 cepp->ce_varlinenum, "set::anti-flood",
8332 cepp->ce_varname);
8333 errors++;
8334 continue;
8335 }
8336 }
8337 }
8338 else if (!strcmp(cep->ce_varname, "options")) {
8339 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
8340 if (!strcmp(cepp->ce_varname, "webtv-support"))
8341 {
8342 CheckDuplicate(cepp, options_webtv_support, "options::webtv-support");
8343 }
8344 else if (!strcmp(cepp->ce_varname, "hide-ulines"))
8345 {
8346 CheckDuplicate(cepp, options_hide_ulines, "options::hide-ulines");
8347 }
8348 else if (!strcmp(cepp->ce_varname, "flat-map")) {
8349 CheckDuplicate(cepp, options_flat_map, "options::flat-map");
8350 }
8351 else if (!strcmp(cepp->ce_varname, "show-opermotd")) {
8352 CheckDuplicate(cepp, options_show_opermotd, "options::show-opermotd");
8353 }
8354 else if (!strcmp(cepp->ce_varname, "identd-check")) {
8355 CheckDuplicate(cepp, options_identd_check, "options::identd-check");
8356 }
8357 else if (!strcmp(cepp->ce_varname, "fail-oper-warn")) {
8358 CheckDuplicate(cepp, options_fail_oper_warn, "options::fail-oper-warn");
8359 }
8360 else if (!strcmp(cepp->ce_varname, "show-connect-info")) {
8361 CheckDuplicate(cepp, options_show_connect_info, "options::show-connect-info");
8362 }
8363 else if (!strcmp(cepp->ce_varname, "dont-resolve")) {
8364 CheckDuplicate(cepp, options_dont_resolve, "options::dont-resolve");
8365 }
8366 else if (!strcmp(cepp->ce_varname, "mkpasswd-for-everyone")) {
8367 CheckDuplicate(cepp, options_mkpasswd_for_everyone, "options::mkpasswd-for-everyone");
8368 }
8369 else if (!strcmp(cepp->ce_varname, "allow-insane-bans")) {
8370 CheckDuplicate(cepp, options_allow_insane_bans, "options::allow-insane-bans");
8371 }
8372 else if (!strcmp(cepp->ce_varname, "allow-part-if-shunned")) {
8373 CheckDuplicate(cepp, options_allow_part_if_shunned, "options::allow-part-if-shunned");
8374 }
8375 else if (!strcmp(cepp->ce_varname, "disable-cap")) {
8376 CheckDuplicate(cepp, options_disable_cap, "options::disable-cap");
8377 }
8378 else
8379 {
8380 config_error_unknownopt(cepp->ce_fileptr->cf_filename,
8381 cepp->ce_varlinenum, "set::options",
8382 cepp->ce_varname);
8383 errors++;
8384 continue;
8385 }
8386 }
8387 }
8388 else if (!strcmp(cep->ce_varname, "hosts")) {
8389 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
8390 {
8391 char *c, *host;
8392 if (!cepp->ce_vardata)
8393 {
8394 config_error_empty(cepp->ce_fileptr->cf_filename,
8395 cepp->ce_varlinenum, "set::hosts",
8396 cepp->ce_varname);
8397 errors++;
8398 continue;
8399 }
8400 if (!strcmp(cepp->ce_varname, "local")) {
8401 CheckDuplicate(cepp, hosts_local, "hosts::local");
8402 }
8403 else if (!strcmp(cepp->ce_varname, "global")) {
8404 CheckDuplicate(cepp, hosts_global, "hosts::global");
8405 }
8406 else if (!strcmp(cepp->ce_varname, "coadmin")) {
8407 CheckDuplicate(cepp, hosts_coadmin, "hosts::coadmin");
8408 }
8409 else if (!strcmp(cepp->ce_varname, "admin")) {
8410 CheckDuplicate(cepp, hosts_admin, "hosts::admin");
8411 }
8412 else if (!strcmp(cepp->ce_varname, "servicesadmin")) {
8413 CheckDuplicate(cepp, hosts_servicesadmin, "hosts::servicesadmin");
8414 }
8415 else if (!strcmp(cepp->ce_varname, "netadmin")) {
8416 CheckDuplicate(cepp, hosts_netadmin, "hosts::netadmin");
8417 }
8418 else if (!strcmp(cepp->ce_varname, "host-on-oper-up")) {
8419 CheckDuplicate(cepp, hosts_host_on_oper_up, "hosts::host-on-oper-up");
8420 }
8421 else
8422 {
8423 config_error_unknown(cepp->ce_fileptr->cf_filename,
8424 cepp->ce_varlinenum, "set::hosts", cepp->ce_varname);
8425 errors++;
8426 continue;
8427
8428 }
8429 if ((c = strchr(cepp->ce_vardata, '@')))
8430 {
8431 char *tmp;
8432 if (!(*(c+1)) || (c-cepp->ce_vardata) > USERLEN ||
8433 c == cepp->ce_vardata)
8434 {
8435 config_error("%s:%i: illegal value for set::hosts::%s",
8436 cepp->ce_fileptr->cf_filename,
8437 cepp->ce_varlinenum,
8438 cepp->ce_varname);
8439 errors++;
8440 continue;
8441 }
8442 for (tmp = cepp->ce_vardata; tmp != c; tmp++)
8443 {
8444 if (*tmp == '~' && tmp == cepp->ce_vardata)
8445 continue;
8446 if (!isallowed(*tmp))
8447 break;
8448 }
8449 if (tmp != c)
8450 {
8451 config_error("%s:%i: illegal value for set::hosts::%s",
8452 cepp->ce_fileptr->cf_filename,
8453 cepp->ce_varlinenum,
8454 cepp->ce_varname);
8455 errors++;
8456 continue;
8457 }
8458 host = c+1;
8459 }
8460 else
8461 host = cepp->ce_vardata;
8462 if (strlen(host) > HOSTLEN)
8463 {
8464 config_error("%s:%i: illegal value for set::hosts::%s",
8465 cepp->ce_fileptr->cf_filename,
8466 cepp->ce_varlinenum,
8467 cepp->ce_varname);
8468 errors++;
8469 continue;
8470 }
8471 for (; *host; host++)
8472 {
8473 if (!isallowed(*host) && *host != ':')
8474 {
8475 config_error("%s:%i: illegal value for set::hosts::%s",
8476 cepp->ce_fileptr->cf_filename,
8477 cepp->ce_varlinenum,
8478 cepp->ce_varname);
8479 errors++;
8480 continue;
8481 }
8482 }
8483 }
8484 }
8485 else if (!strcmp(cep->ce_varname, "cloak-keys"))
8486 {
8487 CheckDuplicate(cep, cloak_keys, "cloak-keys");
8488 for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
8489 {
8490 int value, errs = 0;
8491 if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
8492 && !(h->owner->options & MOD_OPT_PERM))
8493 continue;
8494 value = (*(h->func.intfunc))(conf, cep, CONFIG_CLOAKKEYS, &errs);
8495
8496 if (value == 1)
8497 break;
8498 if (value == -1)
8499 {
8500 errors += errs;
8501 break;
8502 }
8503 if (value == -2)
8504 errors += errs;
8505 }
8506 }
8507 else if (!strcmp(cep->ce_varname, "scan")) {
8508 config_status("%s:%i: set::scan: WARNING: scanner support has been removed, "
8509 "use BOPM instead: http://www.blitzed.org/bopm/ (*NIX) / http://vulnscan.org/winbopm/ (Windows)",
8510 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
8511 }
8512 else if (!strcmp(cep->ce_varname, "ident")) {
8513 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
8514 {
8515 int is_ok = 0;
8516 CheckNull(cepp);
8517 if (!strcmp(cepp->ce_varname, "connect-timeout"))
8518 {
8519 is_ok = 1;
8520 CheckDuplicate(cepp, ident_connect_timeout, "ident::connect-timeout");
8521 }
8522 else if (!strcmp(cepp->ce_varname, "read-timeout"))
8523 {
8524 is_ok = 1;
8525 CheckDuplicate(cepp, ident_read_timeout, "ident::read-timeout");
8526 }
8527 if (is_ok)
8528 {
8529 int v = config_checkval(cepp->ce_vardata,CFG_TIME);
8530 if ((v > 60) || (v < 1))
8531 {
8532 config_error("%s:%i: set::ident::%s value out of range (%d), should be between 1 and 60.",
8533 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum, cepp->ce_varname, v);
8534 errors++;
8535 continue;
8536 }
8537 } else {
8538 config_error_unknown(cepp->ce_fileptr->cf_filename,
8539 cepp->ce_varlinenum, "set::ident",
8540 cepp->ce_varname);
8541 errors++;
8542 continue;
8543 }
8544 }
8545 }
8546 else if (!strcmp(cep->ce_varname, "timesync") || !strcmp(cep->ce_varname, "timesynch")) {
8547 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
8548 {
8549 CheckNull(cepp);
8550 if (!strcmp(cepp->ce_varname, "enabled"))
8551 {
8552 }
8553 else if (!strcmp(cepp->ce_varname, "timeout"))
8554 {
8555 int v = config_checkval(cepp->ce_vardata,CFG_TIME);
8556 if ((v > 5) || (v < 1))
8557 {
8558 config_error("%s:%i: set::timesync::%s value out of range (%d), should be between 1 and 5 (higher=unreliable).",
8559 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum, cepp->ce_varname, v);
8560 errors++;
8561 continue;
8562 }
8563 } else if (!strcmp(cepp->ce_varname, "server"))
8564 {
8565 } else {
8566 config_error_unknown(cepp->ce_fileptr->cf_filename,
8567 cepp->ce_varlinenum, "set::timesync",
8568 cepp->ce_varname);
8569 errors++;
8570 continue;
8571 }
8572 }
8573 }
8574 else if (!strcmp(cep->ce_varname, "spamfilter")) {
8575 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
8576 {
8577 CheckNull(cepp);
8578 if (!strcmp(cepp->ce_varname, "ban-time"))
8579 {
8580 long x;
8581 CheckDuplicate(cepp, spamfilter_ban_time, "spamfilter::ban-time");
8582 x = config_checkval(cepp->ce_vardata,CFG_TIME);
8583 if ((x < 0) > (x > 2000000000))
8584 {
8585 config_error("%s:%i: set::spamfilter:ban-time: value '%ld' out of range",
8586 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, x);
8587 errors++;
8588 continue;
8589 }
8590 } else
8591 if (!strcmp(cepp->ce_varname, "ban-reason"))
8592 {
8593 CheckDuplicate(cepp, spamfilter_ban_reason, "spamfilter::ban-reason");
8594
8595 }
8596 else if (!strcmp(cepp->ce_varname, "virus-help-channel"))
8597 {
8598 CheckDuplicate(cepp, spamfilter_virus_help_channel, "spamfilter::virus-help-channel");
8599 if ((cepp->ce_vardata[0] != '#') || (strlen(cepp->ce_vardata) > CHANNELLEN))
8600 {
8601 config_error("%s:%i: set::spamfilter:virus-help-channel: "
8602 "specified channelname is too long or contains invalid characters (%s)",
8603 cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
8604 cepp->ce_vardata);
8605 errors++;
8606 continue;
8607 }
8608 } else
8609 if (!strcmp(cepp->ce_varname, "virus-help-channel-deny"))
8610 {
8611 CheckDuplicate(cepp, spamfilter_virus_help_channel_deny, "spamfilter::virus-help-channel-deny");
8612 } else
8613 if (!strcmp(cepp->ce_varname, "except"))
8614 {
8615 CheckDuplicate(cepp, spamfilter_except, "spamfilter::except");
8616 } else
8617 #ifdef SPAMFILTER_DETECTSLOW
8618 if (!strcmp(cepp->ce_varname, "detect-slow-warn"))
8619 {
8620 } else
8621 if (!strcmp(cepp->ce_varname, "detect-slow-fatal"))
8622 {
8623 } else
8624 #endif
8625 if (!strcmp(cepp->ce_varname, "stop-on-first-match"))
8626 {
8627 } else
8628 {
8629 config_error_unknown(cepp->ce_fileptr->cf_filename,
8630 cepp->ce_varlinenum, "set::spamfilter",
8631 cepp->ce_varname);
8632 errors++;
8633 continue;
8634 }
8635 }
8636 }
8637 /* TODO: FIX THIS */
8638 else if (!strcmp(cep->ce_varname, "default-bantime"))
8639 {
8640 long x;
8641 CheckDuplicate(cep, default_bantime, "default-bantime");
8642 CheckNull(cep);
8643 x = config_checkval(cep->ce_vardata,CFG_TIME);
8644 if ((x < 0) > (x > 2000000000))
8645 {
8646 config_error("%s:%i: set::default-bantime: value '%ld' out of range",
8647 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, x);
8648 errors++;
8649 }
8650 }
8651 else if (!strcmp(cep->ce_varname, "ban-version-tkl-time")) {
8652 long x;
8653 CheckDuplicate(cep, ban_version_tkl_time, "ban-version-tkl-time");
8654 CheckNull(cep);
8655 x = config_checkval(cep->ce_vardata,CFG_TIME);
8656 if ((x < 0) > (x > 2000000000))
8657 {
8658 config_error("%s:%i: set::ban-version-tkl-time: value '%ld' out of range",
8659 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, x);
8660 errors++;
8661 }
8662 }
8663 #ifdef NEWCHFLOODPROT
8664 else if (!strcmp(cep->ce_varname, "modef-default-unsettime")) {
8665 int v;
8666 CheckDuplicate(cep, modef_default_unsettime, "modef-default-unsettime");
8667 CheckNull(cep);
8668 v = atoi(cep->ce_vardata);
8669 if ((v <= 0) || (v > 255))
8670 {
8671 config_error("%s:%i: set::modef-default-unsettime: value '%d' out of range (should be 1-255)",
8672 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, v);
8673 errors++;
8674 }
8675 }
8676 else if (!strcmp(cep->ce_varname, "modef-max-unsettime")) {
8677 int v;
8678 CheckDuplicate(cep, modef_max_unsettime, "modef-max-unsettime");
8679 CheckNull(cep);
8680 v = atoi(cep->ce_vardata);
8681 if ((v <= 0) || (v > 255))
8682 {
8683 config_error("%s:%i: set::modef-max-unsettime: value '%d' out of range (should be 1-255)",
8684 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, v);
8685 errors++;
8686 }
8687 }
8688 #endif
8689 else if (!strcmp(cep->ce_varname, "ssl")) {
8690 #ifdef USE_SSL
8691 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
8692 if (!strcmp(cepp->ce_varname, "egd")) {
8693 CheckDuplicate(cep, ssl_egd, "ssl::egd");
8694 }
8695 else if (!strcmp(cepp->ce_varname, "renegotiate-timeout"))
8696 {
8697 CheckDuplicate(cep, renegotiate_timeout, "ssl::renegotiate-timeout");
8698 }
8699 else if (!strcmp(cepp->ce_varname, "renegotiate-bytes"))
8700 {
8701 CheckDuplicate(cep, renegotiate_bytes, "ssl::renegotiate-bytes");
8702 }
8703 else if (!strcmp(cepp->ce_varname, "server-cipher-list"))
8704 {
8705 CheckNull(cepp);
8706 CheckDuplicate(cep, ssl_server_cipher_list, "ssl::server-cipher-list");
8707 }
8708 else if (!strcmp(cepp->ce_varname, "certificate"))
8709 {
8710 CheckNull(cepp);
8711 CheckDuplicate(cep, ssl_certificate, "ssl::certificate");
8712 }
8713 else if (!strcmp(cepp->ce_varname, "key"))
8714 {
8715 CheckNull(cepp);
8716 CheckDuplicate(cep, ssl_key, "ssl::key");
8717 }
8718 else if (!strcmp(cepp->ce_varname, "trusted-ca-file"))
8719 {
8720 CheckNull(cepp);
8721 CheckDuplicate(cep, ssl_trusted_ca_file, "ssl::trusted-ca-file");
8722 }
8723 else if (!strcmp(cepp->ce_varname, "options"))
8724 {
8725 CheckDuplicate(cep, ssl_options, "ssl::options");
8726 for (ceppp = cepp->ce_entries; ceppp; ceppp = ceppp->ce_next)
8727 if (!config_binary_flags_search(_SSLFlags, ceppp->ce_varname, ARRAY_SIZEOF(_SSLFlags)))
8728 {
8729 config_error("%s:%i: unknown SSL flag '%s'",
8730 ceppp->ce_fileptr->cf_filename,
8731 ceppp->ce_varlinenum, ceppp->ce_varname);
8732 errors ++;
8733 }
8734 }
8735 else
8736 {
8737 config_error("%s:%i: unknown directive set::ssl::%s",
8738 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum,
8739 cepp->ce_varname);
8740 errors++;
8741 }
8742 }
8743 #endif /* USE_SSL */
8744 }
8745 else if (!strcmp(cep->ce_varname, "default-ipv6-clone-mask"))
8746 {
8747 /* keep this in sync with _test_allow() */
8748 int ipv6mask;
8749 ipv6mask = atoi(cep->ce_vardata);
8750 if (ipv6mask == 0)
8751 {
8752 config_error("%s:%d: set::default-ipv6-clone-mask given a value of zero. This cannnot be correct, as it would treat all IPv6 hosts as one host.",
8753 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
8754 errors++;
8755 }
8756 if (ipv6mask > 128)
8757 {
8758 config_error("%s:%d: set::default-ipv6-clone-mask was set to %d. The maximum value is 128.",
8759 cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
8760 ipv6mask);
8761 errors++;
8762 }
8763 if (ipv6mask <= 32)
8764 {
8765 config_warn("%s:%d: set::default-ipv6-clone-mask was given a very small value.",
8766 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
8767 }
8768 }
8769 else
8770 {
8771 int used = 0;
8772 for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
8773 {
8774 int value, errs = 0;
8775 if (h->owner && !(h->owner->flags & MODFLAG_TESTING) &&
8776 !(h->owner->options & MOD_OPT_PERM))
8777 continue;
8778 value = (*(h->func.intfunc))(conf,cep,CONFIG_SET, &errs);
8779 if (value == 2)
8780 used = 1;
8781 if (value == 1)
8782 {
8783 used = 1;
8784 break;
8785 }
8786 if (value == -1)
8787 {
8788 used = 1;
8789 errors += errs;
8790 break;
8791 }
8792 if (value == -2)
8793 {
8794 used = 1;
8795 errors += errs;
8796 }
8797 }
8798 if (!used) {
8799 config_error("%s:%i: unknown directive set::%s",
8800 cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
8801 cep->ce_varname);
8802 errors++;
8803 }
8804 }
8805 }
8806 return errors;
8807 }
8808
_conf_loadmodule(ConfigFile * conf,ConfigEntry * ce)8809 int _conf_loadmodule(ConfigFile *conf, ConfigEntry *ce)
8810 {
8811 #ifdef GLOBH
8812 glob_t files;
8813 int i;
8814 #elif defined(_WIN32)
8815 HANDLE hFind;
8816 WIN32_FIND_DATA FindData;
8817 char cPath[MAX_PATH], *cSlash = NULL, *path;
8818 #endif
8819 char *ret;
8820 if (!ce->ce_vardata)
8821 {
8822 config_status("%s:%i: loadmodule without filename",
8823 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
8824 return -1;
8825 }
8826 #ifdef GLOBH
8827 #if defined(__OpenBSD__) && defined(GLOB_LIMIT)
8828 glob(ce->ce_vardata, GLOB_NOSORT|GLOB_NOCHECK|GLOB_LIMIT, NULL, &files);
8829 #else
8830 glob(ce->ce_vardata, GLOB_NOSORT|GLOB_NOCHECK, NULL, &files);
8831 #endif
8832 if (!files.gl_pathc) {
8833 globfree(&files);
8834 config_status("%s:%i: loadmodule %s: failed to load",
8835 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
8836 ce->ce_vardata);
8837 return -1;
8838 }
8839 for (i = 0; i < files.gl_pathc; i++) {
8840 if ((ret = Module_Create(files.gl_pathv[i]))) {
8841 config_status("%s:%i: loadmodule %s: failed to load: %s",
8842 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
8843 files.gl_pathv[i], ret);
8844 return -1;
8845 }
8846 }
8847 globfree(&files);
8848 #elif defined(_WIN32)
8849 bzero(cPath,MAX_PATH);
8850 if (strchr(ce->ce_vardata, '/') || strchr(ce->ce_vardata, '\\')) {
8851 strncpyzt(cPath,ce->ce_vardata,MAX_PATH);
8852 cSlash=cPath+strlen(cPath);
8853 while(*cSlash != '\\' && *cSlash != '/' && cSlash > cPath)
8854 cSlash--;
8855 *(cSlash+1)=0;
8856 }
8857 hFind = FindFirstFile(ce->ce_vardata, &FindData);
8858 if (!FindData.cFileName || hFind == INVALID_HANDLE_VALUE) {
8859 config_status("%s:%i: loadmodule %s: failed to load",
8860 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
8861 ce->ce_vardata);
8862 FindClose(hFind);
8863 return -1;
8864 }
8865
8866 if (cPath) {
8867 path = MyMalloc(strlen(cPath) + strlen(FindData.cFileName)+1);
8868 strcpy(path,cPath);
8869 strcat(path,FindData.cFileName);
8870 if ((ret = Module_Create(path))) {
8871 config_status("%s:%i: loadmodule %s: failed to load: %s",
8872 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
8873 path, ret);
8874 free(path);
8875 return -1;
8876 }
8877 free(path);
8878 }
8879 else
8880 {
8881 if ((ret = Module_Create(FindData.cFileName))) {
8882 config_status("%s:%i: loadmodule %s: failed to load: %s",
8883 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
8884 FindData.cFileName, ret);
8885 return -1;
8886 }
8887 }
8888 while (FindNextFile(hFind, &FindData) != 0) {
8889 if (cPath) {
8890 path = MyMalloc(strlen(cPath) + strlen(FindData.cFileName)+1);
8891 strcpy(path,cPath);
8892 strcat(path,FindData.cFileName);
8893 if ((ret = Module_Create(path)))
8894 {
8895 config_status("%s:%i: loadmodule %s: failed to load: %s",
8896 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
8897 FindData.cFileName, ret);
8898 free(path);
8899 return -1;
8900 }
8901 free(path);
8902 }
8903 else
8904 {
8905 if ((ret = Module_Create(FindData.cFileName)))
8906 {
8907 config_status("%s:%i: loadmodule %s: failed to load: %s",
8908 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
8909 FindData.cFileName, ret);
8910 return -1;
8911 }
8912 }
8913 }
8914 FindClose(hFind);
8915 #else
8916 if ((ret = Module_Create(ce->ce_vardata))) {
8917 config_status("%s:%i: loadmodule %s: failed to load: %s",
8918 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
8919 ce->ce_vardata, ret);
8920 return -1;
8921 }
8922 #endif
8923 return 1;
8924 }
8925
_test_loadmodule(ConfigFile * conf,ConfigEntry * ce)8926 int _test_loadmodule(ConfigFile *conf, ConfigEntry *ce)
8927 {
8928 return 0;
8929 }
8930
8931 /*
8932 * Actually use configuration
8933 */
8934
run_configuration(void)8935 void run_configuration(void)
8936 {
8937 ConfigItem_listen *listenptr;
8938
8939 for (listenptr = conf_listen; listenptr; listenptr = (ConfigItem_listen *) listenptr->next)
8940 {
8941 if (!(listenptr->options & LISTENER_BOUND))
8942 {
8943 if (add_listener2(listenptr) == -1)
8944 {
8945 ircd_log(LOG_ERROR, "Failed to bind to %s:%i", listenptr->ip, listenptr->port);
8946 }
8947 else
8948 {
8949 }
8950 }
8951 else
8952 {
8953 if (listenptr->listener)
8954 {
8955 listenptr->listener->umodes =
8956 (listenptr->options & ~LISTENER_BOUND) ? listenptr->options : LISTENER_NORMAL;
8957 listenptr->listener->umodes |= LISTENER_BOUND;
8958 }
8959 }
8960 }
8961 }
8962
_conf_offchans(ConfigFile * conf,ConfigEntry * ce)8963 int _conf_offchans(ConfigFile *conf, ConfigEntry *ce)
8964 {
8965 ConfigEntry *cep, *cepp;
8966
8967 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
8968 {
8969 ConfigItem_offchans *of = MyMallocEx(sizeof(ConfigItem_offchans));
8970 strlcpy(of->chname, cep->ce_varname, CHANNELLEN+1);
8971 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next)
8972 {
8973 if (!strcmp(cepp->ce_varname, "topic"))
8974 of->topic = strdup(cepp->ce_vardata);
8975 }
8976 AddListItem(of, conf_offchans);
8977 }
8978 return 0;
8979 }
8980
_test_offchans(ConfigFile * conf,ConfigEntry * ce)8981 int _test_offchans(ConfigFile *conf, ConfigEntry *ce)
8982 {
8983 int errors = 0;
8984 ConfigEntry *cep, *cep2;
8985 char checkchan[CHANNELLEN + 1];
8986
8987 if (!ce->ce_entries)
8988 {
8989 config_error("%s:%i: empty official-channels block",
8990 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
8991 return 1;
8992 }
8993 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
8994 {
8995 if (strlen(cep->ce_varname) > CHANNELLEN)
8996 {
8997 config_error("%s:%i: official-channels: '%s' name too long (max %d characters).",
8998 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname, CHANNELLEN);
8999 errors++;
9000 continue;
9001 }
9002 strcpy(checkchan, cep->ce_varname); /* safe */
9003 clean_channelname(checkchan);
9004 if (strcmp(checkchan, cep->ce_varname) || (*cep->ce_varname != '#'))
9005 {
9006 config_error("%s:%i: official-channels: '%s' is not a valid channel name.",
9007 cep->ce_fileptr->cf_filename, cep->ce_varlinenum, cep->ce_varname);
9008 errors++;
9009 continue;
9010 }
9011 for (cep2 = cep->ce_entries; cep2; cep2 = cep2->ce_next)
9012 {
9013 if (!cep2->ce_vardata)
9014 {
9015 config_error_empty(cep2->ce_fileptr->cf_filename,
9016 cep2->ce_varlinenum, "official-channels",
9017 cep2->ce_varname);
9018 errors++;
9019 continue;
9020 }
9021 if (!strcmp(cep2->ce_varname, "topic"))
9022 {
9023 if (strlen(cep2->ce_vardata) > TOPICLEN)
9024 {
9025 config_error("%s:%i: official-channels::%s: topic too long (max %d characters).",
9026 cep2->ce_fileptr->cf_filename, cep2->ce_varlinenum, cep->ce_varname, TOPICLEN);
9027 errors++;
9028 continue;
9029 }
9030 } else {
9031 config_error_unknown(cep2->ce_fileptr->cf_filename,
9032 cep2->ce_varlinenum, "official-channels",
9033 cep2->ce_varname);
9034 errors++;
9035 continue;
9036 }
9037 }
9038 }
9039 return errors;
9040 }
9041
_conf_alias(ConfigFile * conf,ConfigEntry * ce)9042 int _conf_alias(ConfigFile *conf, ConfigEntry *ce)
9043 {
9044 ConfigItem_alias *alias = NULL;
9045 ConfigItem_alias_format *format;
9046 ConfigEntry *cep, *cepp;
9047 aCommand *cmptr;
9048
9049 if ((cmptr = find_Command(ce->ce_vardata, 0, M_ALIAS)))
9050 del_Command(ce->ce_vardata, NULL, cmptr->func);
9051 if (find_Command_simple(ce->ce_vardata))
9052 {
9053 config_warn("%s:%i: Alias '%s' would conflict with command (or server token) '%s', alias not added.",
9054 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
9055 ce->ce_vardata, ce->ce_vardata);
9056 return 0;
9057 }
9058 if ((alias = Find_alias(ce->ce_vardata)))
9059 DelListItem(alias, conf_alias);
9060 alias = MyMallocEx(sizeof(ConfigItem_alias));
9061 ircstrdup(alias->alias, ce->ce_vardata);
9062 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
9063 {
9064 if (!strcmp(cep->ce_varname, "format")) {
9065 format = MyMallocEx(sizeof(ConfigItem_alias_format));
9066 ircstrdup(format->format, cep->ce_vardata);
9067 regcomp(&format->expr, cep->ce_vardata, REG_ICASE|REG_EXTENDED);
9068 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
9069 if (!strcmp(cepp->ce_varname, "nick") ||
9070 !strcmp(cepp->ce_varname, "target") ||
9071 !strcmp(cepp->ce_varname, "command")) {
9072 ircstrdup(format->nick, cepp->ce_vardata);
9073 }
9074 else if (!strcmp(cepp->ce_varname, "parameters")) {
9075 ircstrdup(format->parameters, cepp->ce_vardata);
9076 }
9077 else if (!strcmp(cepp->ce_varname, "type")) {
9078 if (!strcmp(cepp->ce_vardata, "services"))
9079 format->type = ALIAS_SERVICES;
9080 else if (!strcmp(cepp->ce_vardata, "stats"))
9081 format->type = ALIAS_STATS;
9082 else if (!strcmp(cepp->ce_vardata, "normal"))
9083 format->type = ALIAS_NORMAL;
9084 else if (!strcmp(cepp->ce_vardata, "channel"))
9085 format->type = ALIAS_CHANNEL;
9086 else if (!strcmp(cepp->ce_vardata, "real"))
9087 format->type = ALIAS_REAL;
9088 }
9089 }
9090 AddListItem(format, alias->format);
9091 }
9092
9093 else if (!strcmp(cep->ce_varname, "nick") || !strcmp(cep->ce_varname, "target"))
9094 {
9095 ircstrdup(alias->nick, cep->ce_vardata);
9096 }
9097 else if (!strcmp(cep->ce_varname, "type")) {
9098 if (!strcmp(cep->ce_vardata, "services"))
9099 alias->type = ALIAS_SERVICES;
9100 else if (!strcmp(cep->ce_vardata, "stats"))
9101 alias->type = ALIAS_STATS;
9102 else if (!strcmp(cep->ce_vardata, "normal"))
9103 alias->type = ALIAS_NORMAL;
9104 else if (!strcmp(cep->ce_vardata, "channel"))
9105 alias->type = ALIAS_CHANNEL;
9106 else if (!strcmp(cep->ce_vardata, "command"))
9107 alias->type = ALIAS_COMMAND;
9108 }
9109 else if (!strcmp(cep->ce_varname, "spamfilter"))
9110 alias->spamfilter = config_checkval(cep->ce_vardata, CFG_YESNO);
9111 }
9112 if (BadPtr(alias->nick) && alias->type != ALIAS_COMMAND) {
9113 ircstrdup(alias->nick, alias->alias);
9114 }
9115 add_CommandX(alias->alias, NULL, m_alias, 1, M_USER|M_ALIAS);
9116 AddListItem(alias, conf_alias);
9117 return 0;
9118 }
9119
9120
_test_alias(ConfigFile * conf,ConfigEntry * ce)9121 int _test_alias(ConfigFile *conf, ConfigEntry *ce) {
9122 int errors = 0;
9123 ConfigEntry *cep, *cepp;
9124 char has_type = 0, has_target = 0, has_format = 0;
9125 char type = 0;
9126
9127 if (!ce->ce_entries)
9128 {
9129 config_error("%s:%i: empty alias block",
9130 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
9131 return 1;
9132 }
9133 if (!ce->ce_vardata)
9134 {
9135 config_error("%s:%i: alias without name",
9136 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
9137 errors++;
9138 }
9139 else if (!find_Command(ce->ce_vardata, 0, M_ALIAS) && find_Command(ce->ce_vardata, 0, 0)) {
9140 config_status("%s:%i: %s is an existing command, can not add alias",
9141 ce->ce_fileptr->cf_filename, ce->ce_varlinenum, ce->ce_vardata);
9142 errors++;
9143 }
9144 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
9145 {
9146 if (config_is_blankorempty(cep, "alias"))
9147 {
9148 errors++;
9149 continue;
9150 }
9151 if (!strcmp(cep->ce_varname, "format")) {
9152 int errorcode, errorbufsize;
9153 char *errorbuf;
9154 regex_t expr;
9155 char has_type = 0, has_target = 0, has_parameters = 0;
9156
9157 has_format = 1;
9158 errorcode = regcomp(&expr, cep->ce_vardata, REG_ICASE|REG_EXTENDED);
9159 if (errorcode > 0)
9160 {
9161 errorbufsize = regerror(errorcode, &expr, NULL, 0)+1;
9162 errorbuf = MyMalloc(errorbufsize);
9163 regerror(errorcode, &expr, errorbuf, errorbufsize);
9164 config_error("%s:%i: alias::format contains an invalid regex: %s",
9165 cep->ce_fileptr->cf_filename,
9166 cep->ce_varlinenum,
9167 errorbuf);
9168 errors++;
9169 free(errorbuf);
9170 }
9171 regfree(&expr);
9172 for (cepp = cep->ce_entries; cepp; cepp = cepp->ce_next) {
9173 if (config_is_blankorempty(cepp, "alias::format"))
9174 {
9175 errors++;
9176 continue;
9177 }
9178 if (!strcmp(cepp->ce_varname, "nick") ||
9179 !strcmp(cepp->ce_varname, "command") ||
9180 !strcmp(cepp->ce_varname, "target"))
9181 {
9182 if (has_target)
9183 {
9184 config_warn_duplicate(cepp->ce_fileptr->cf_filename,
9185 cepp->ce_varlinenum,
9186 "alias::format::target");
9187 continue;
9188 }
9189 has_target = 1;
9190 }
9191 else if (!strcmp(cepp->ce_varname, "type"))
9192 {
9193 if (has_type)
9194 {
9195 config_warn_duplicate(cepp->ce_fileptr->cf_filename,
9196 cepp->ce_varlinenum,
9197 "alias::format::type");
9198 continue;
9199 }
9200 has_type = 1;
9201 if (!strcmp(cepp->ce_vardata, "services"))
9202 ;
9203 else if (!strcmp(cepp->ce_vardata, "stats"))
9204 ;
9205 else if (!strcmp(cepp->ce_vardata, "normal"))
9206 ;
9207 else if (!strcmp(cepp->ce_vardata, "channel"))
9208 ;
9209 else if (!strcmp(cepp->ce_vardata, "real"))
9210 ;
9211 else
9212 {
9213 config_error("%s:%i: unknown alias type",
9214 cepp->ce_fileptr->cf_filename, cepp->ce_varlinenum);
9215 errors++;
9216 }
9217 }
9218 else if (!strcmp(cepp->ce_varname, "parameters"))
9219 {
9220 if (has_parameters)
9221 {
9222 config_warn_duplicate(cepp->ce_fileptr->cf_filename,
9223 cepp->ce_varlinenum,
9224 "alias::format::parameters");
9225 continue;
9226 }
9227 has_parameters = 1;
9228 }
9229 else
9230 {
9231 config_error_unknown(cepp->ce_fileptr->cf_filename,
9232 cepp->ce_varlinenum, "alias::format",
9233 cepp->ce_varname);
9234 errors++;
9235 }
9236 }
9237 if (!has_target)
9238 {
9239 config_error_missing(cep->ce_fileptr->cf_filename,
9240 cep->ce_varlinenum, "alias::format::target");
9241 errors++;
9242 }
9243 if (!has_type)
9244 {
9245 config_error_missing(cep->ce_fileptr->cf_filename,
9246 cep->ce_varlinenum, "alias::format::type");
9247 errors++;
9248 }
9249 if (!has_parameters)
9250 {
9251 config_error_missing(cep->ce_fileptr->cf_filename,
9252 cep->ce_varlinenum, "alias::format::parameters");
9253 errors++;
9254 }
9255 }
9256 else if (!strcmp(cep->ce_varname, "nick") || !strcmp(cep->ce_varname, "target"))
9257 {
9258 if (has_target)
9259 {
9260 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9261 cep->ce_varlinenum, "alias::target");
9262 continue;
9263 }
9264 has_target = 1;
9265 }
9266 else if (!strcmp(cep->ce_varname, "type")) {
9267 if (has_type)
9268 {
9269 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9270 cep->ce_varlinenum, "alias::type");
9271 continue;
9272 }
9273 has_type = 1;
9274 if (!strcmp(cep->ce_vardata, "services"))
9275 ;
9276 else if (!strcmp(cep->ce_vardata, "stats"))
9277 ;
9278 else if (!strcmp(cep->ce_vardata, "normal"))
9279 ;
9280 else if (!strcmp(cep->ce_vardata, "channel"))
9281 ;
9282 else if (!strcmp(cep->ce_vardata, "command"))
9283 type = 'c';
9284 else {
9285 config_error("%s:%i: unknown alias type",
9286 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
9287 errors++;
9288 }
9289 }
9290 else if (!strcmp(cep->ce_varname, "spamfilter"))
9291 ;
9292 else {
9293 config_error_unknown(cep->ce_fileptr->cf_filename, cep->ce_varlinenum,
9294 "alias", cep->ce_varname);
9295 errors++;
9296 }
9297 }
9298 if (!has_type)
9299 {
9300 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
9301 "alias::type");
9302 errors++;
9303 }
9304 if (!has_format && type == 'c')
9305 {
9306 config_error("%s:%d: alias::type is 'command' but no alias::format was specified",
9307 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
9308 errors++;
9309 }
9310 else if (has_format && type != 'c')
9311 {
9312 config_error("%s:%d: alias::format specified when type is not 'command'",
9313 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
9314 errors++;
9315 }
9316 return errors;
9317 }
9318
_conf_deny(ConfigFile * conf,ConfigEntry * ce)9319 int _conf_deny(ConfigFile *conf, ConfigEntry *ce)
9320 {
9321 Hook *h;
9322
9323 if (!strcmp(ce->ce_vardata, "dcc"))
9324 _conf_deny_dcc(conf, ce);
9325 else if (!strcmp(ce->ce_vardata, "channel"))
9326 _conf_deny_channel(conf, ce);
9327 else if (!strcmp(ce->ce_vardata, "link"))
9328 _conf_deny_link(conf, ce);
9329 else if (!strcmp(ce->ce_vardata, "version"))
9330 _conf_deny_version(conf, ce);
9331 else
9332 {
9333 int value;
9334 for (h = Hooks[HOOKTYPE_CONFIGRUN]; h; h = h->next)
9335 {
9336 value = (*(h->func.intfunc))(conf,ce,CONFIG_DENY);
9337 if (value == 1)
9338 break;
9339 }
9340 return 0;
9341 }
9342 return 0;
9343 }
9344
_conf_deny_dcc(ConfigFile * conf,ConfigEntry * ce)9345 int _conf_deny_dcc(ConfigFile *conf, ConfigEntry *ce)
9346 {
9347 ConfigItem_deny_dcc *deny = NULL;
9348 ConfigEntry *cep;
9349
9350 deny = MyMallocEx(sizeof(ConfigItem_deny_dcc));
9351 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
9352 {
9353 if (!strcmp(cep->ce_varname, "filename"))
9354 {
9355 ircstrdup(deny->filename, cep->ce_vardata);
9356 }
9357 else if (!strcmp(cep->ce_varname, "reason"))
9358 {
9359 ircstrdup(deny->reason, cep->ce_vardata);
9360 }
9361 else if (!strcmp(cep->ce_varname, "soft"))
9362 {
9363 int x = config_checkval(cep->ce_vardata,CFG_YESNO);
9364 if (x == 1)
9365 deny->flag.type = DCCDENY_SOFT;
9366 }
9367 }
9368 if (!deny->reason)
9369 {
9370 if (deny->flag.type == DCCDENY_HARD)
9371 ircstrdup(deny->reason, "Possible infected virus file");
9372 else
9373 ircstrdup(deny->reason, "Possible executable content");
9374 }
9375 AddListItem(deny, conf_deny_dcc);
9376 return 0;
9377 }
9378
_conf_deny_channel(ConfigFile * conf,ConfigEntry * ce)9379 int _conf_deny_channel(ConfigFile *conf, ConfigEntry *ce)
9380 {
9381 ConfigItem_deny_channel *deny = NULL;
9382 ConfigEntry *cep;
9383
9384 deny = MyMallocEx(sizeof(ConfigItem_deny_channel));
9385 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
9386 {
9387 if (!strcmp(cep->ce_varname, "channel"))
9388 {
9389 ircstrdup(deny->channel, cep->ce_vardata);
9390 }
9391 else if (!strcmp(cep->ce_varname, "redirect"))
9392 {
9393 ircstrdup(deny->redirect, cep->ce_vardata);
9394 }
9395 else if (!strcmp(cep->ce_varname, "reason"))
9396 {
9397 ircstrdup(deny->reason, cep->ce_vardata);
9398 }
9399 else if (!strcmp(cep->ce_varname, "warn"))
9400 {
9401 deny->warn = config_checkval(cep->ce_vardata,CFG_YESNO);
9402 }
9403 else if (!strcmp(cep->ce_varname, "class"))
9404 {
9405 ircstrdup(deny->class, cep->ce_vardata);
9406 }
9407 }
9408 AddListItem(deny, conf_deny_channel);
9409 return 0;
9410 }
_conf_deny_link(ConfigFile * conf,ConfigEntry * ce)9411 int _conf_deny_link(ConfigFile *conf, ConfigEntry *ce)
9412 {
9413 ConfigItem_deny_link *deny = NULL;
9414 ConfigEntry *cep;
9415
9416 deny = MyMallocEx(sizeof(ConfigItem_deny_link));
9417 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
9418 {
9419 if (!strcmp(cep->ce_varname, "mask"))
9420 {
9421 ircstrdup(deny->mask, cep->ce_vardata);
9422 }
9423 else if (!strcmp(cep->ce_varname, "rule"))
9424 {
9425 deny->rule = (char *)crule_parse(cep->ce_vardata);
9426 ircstrdup(deny->prettyrule, cep->ce_vardata);
9427 }
9428 else if (!strcmp(cep->ce_varname, "type")) {
9429 if (!strcmp(cep->ce_vardata, "all"))
9430 deny->flag.type = CRULE_ALL;
9431 else if (!strcmp(cep->ce_vardata, "auto"))
9432 deny->flag.type = CRULE_AUTO;
9433 }
9434 }
9435 AddListItem(deny, conf_deny_link);
9436 return 0;
9437 }
9438
_conf_deny_version(ConfigFile * conf,ConfigEntry * ce)9439 int _conf_deny_version(ConfigFile *conf, ConfigEntry *ce)
9440 {
9441 ConfigItem_deny_version *deny = NULL;
9442 ConfigEntry *cep;
9443
9444 deny = MyMallocEx(sizeof(ConfigItem_deny_version));
9445 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
9446 {
9447 if (!strcmp(cep->ce_varname, "mask"))
9448 {
9449 ircstrdup(deny->mask, cep->ce_vardata);
9450 }
9451 else if (!strcmp(cep->ce_varname, "version"))
9452 {
9453 ircstrdup(deny->version, cep->ce_vardata);
9454 }
9455 else if (!strcmp(cep->ce_varname, "flags"))
9456 {
9457 ircstrdup(deny->flags, cep->ce_vardata);
9458 }
9459 }
9460 AddListItem(deny, conf_deny_version);
9461 return 0;
9462 }
9463
_test_deny(ConfigFile * conf,ConfigEntry * ce)9464 int _test_deny(ConfigFile *conf, ConfigEntry *ce)
9465 {
9466 ConfigEntry *cep;
9467 int errors = 0;
9468 Hook *h;
9469
9470 if (!ce->ce_vardata)
9471 {
9472 config_error("%s:%i: deny without type",
9473 ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
9474 return 1;
9475 }
9476 if (!strcmp(ce->ce_vardata, "dcc"))
9477 {
9478 char has_filename = 0, has_reason = 0, has_soft = 0;
9479 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
9480 {
9481 if (config_is_blankorempty(cep, "deny dcc"))
9482 {
9483 errors++;
9484 continue;
9485 }
9486 if (!strcmp(cep->ce_varname, "filename"))
9487 {
9488 if (has_filename)
9489 {
9490 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9491 cep->ce_varlinenum, "deny dcc::filename");
9492 continue;
9493 }
9494 has_filename = 1;
9495 }
9496 else if (!strcmp(cep->ce_varname, "reason"))
9497 {
9498 if (has_reason)
9499 {
9500 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9501 cep->ce_varlinenum, "deny dcc::reason");
9502 continue;
9503 }
9504 has_reason = 1;
9505 }
9506 else if (!strcmp(cep->ce_varname, "soft"))
9507 {
9508 if (has_soft)
9509 {
9510 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9511 cep->ce_varlinenum, "deny dcc::soft");
9512 continue;
9513 }
9514 has_soft = 1;
9515 }
9516 else
9517 {
9518 config_error_unknown(cep->ce_fileptr->cf_filename,
9519 cep->ce_varlinenum, "deny dcc", cep->ce_varname);
9520 errors++;
9521 }
9522 }
9523 if (!has_filename)
9524 {
9525 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
9526 "deny dcc::filename");
9527 errors++;
9528 }
9529 if (!has_reason)
9530 {
9531 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
9532 "deny dcc::reason");
9533 errors++;
9534 }
9535 }
9536 else if (!strcmp(ce->ce_vardata, "channel"))
9537 {
9538 char has_channel = 0, has_warn = 0, has_reason = 0, has_redirect = 0, has_class = 0;
9539 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
9540 {
9541 if (config_is_blankorempty(cep, "deny channel"))
9542 {
9543 errors++;
9544 continue;
9545 }
9546 if (!strcmp(cep->ce_varname, "channel"))
9547 {
9548 if (has_channel)
9549 {
9550 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9551 cep->ce_varlinenum, "deny channel::channel");
9552 continue;
9553 }
9554 has_channel = 1;
9555 }
9556 else if (!strcmp(cep->ce_varname, "redirect"))
9557 {
9558 if (has_redirect)
9559 {
9560 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9561 cep->ce_varlinenum, "deny channel::redirect");
9562 continue;
9563 }
9564 has_redirect = 1;
9565 }
9566 else if (!strcmp(cep->ce_varname, "reason"))
9567 {
9568 if (has_reason)
9569 {
9570 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9571 cep->ce_varlinenum, "deny channel::reason");
9572 continue;
9573 }
9574 has_reason = 1;
9575 }
9576 else if (!strcmp(cep->ce_varname, "warn"))
9577 {
9578 if (has_warn)
9579 {
9580 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9581 cep->ce_varlinenum, "deny channel::warn");
9582 continue;
9583 }
9584 has_warn = 1;
9585 }
9586 else if (!strcmp(cep->ce_varname, "class"))
9587 {
9588 if (has_class)
9589 {
9590 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9591 cep->ce_varlinenum, "deny channel::class");
9592 continue;
9593 }
9594 has_class = 1;
9595 }
9596 else
9597 {
9598 config_error_unknown(cep->ce_fileptr->cf_filename,
9599 cep->ce_varlinenum, "deny channel", cep->ce_varname);
9600 errors++;
9601 }
9602 }
9603 if (!has_channel)
9604 {
9605 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
9606 "deny channel::channel");
9607 errors++;
9608 }
9609 if (!has_reason)
9610 {
9611 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
9612 "deny channel::reason");
9613 errors++;
9614 }
9615 }
9616 else if (!strcmp(ce->ce_vardata, "link"))
9617 {
9618 char has_mask = 0, has_rule = 0, has_type = 0;
9619 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
9620 {
9621 if (config_is_blankorempty(cep, "deny link"))
9622 {
9623 errors++;
9624 continue;
9625 }
9626 if (!strcmp(cep->ce_varname, "mask"))
9627 {
9628 if (has_mask)
9629 {
9630 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9631 cep->ce_varlinenum, "deny link::mask");
9632 continue;
9633 }
9634 has_mask = 1;
9635 }
9636 else if (!strcmp(cep->ce_varname, "rule"))
9637 {
9638 int val = 0;
9639 if (has_rule)
9640 {
9641 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9642 cep->ce_varlinenum, "deny link::rule");
9643 continue;
9644 }
9645 has_rule = 1;
9646 if ((val = crule_test(cep->ce_vardata)))
9647 {
9648 config_error("%s:%i: deny link::rule contains an invalid expression: %s",
9649 cep->ce_fileptr->cf_filename,
9650 cep->ce_varlinenum,
9651 crule_errstring(val));
9652 errors++;
9653 }
9654 }
9655 else if (!strcmp(cep->ce_varname, "type"))
9656 {
9657 if (has_type)
9658 {
9659 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9660 cep->ce_varlinenum, "deny link::type");
9661 continue;
9662 }
9663 has_type = 1;
9664 if (!strcmp(cep->ce_vardata, "auto"))
9665 ;
9666 else if (!strcmp(cep->ce_vardata, "all"))
9667 ;
9668 else {
9669 config_status("%s:%i: unknown deny link type",
9670 cep->ce_fileptr->cf_filename, cep->ce_varlinenum);
9671 errors++;
9672 }
9673 }
9674 else
9675 {
9676 config_error_unknown(cep->ce_fileptr->cf_filename,
9677 cep->ce_varlinenum, "deny link", cep->ce_varname);
9678 errors++;
9679 }
9680 }
9681 if (!has_mask)
9682 {
9683 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
9684 "deny link::mask");
9685 errors++;
9686 }
9687 if (!has_rule)
9688 {
9689 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
9690 "deny link::rule");
9691 errors++;
9692 }
9693 if (!has_type)
9694 {
9695 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
9696 "deny link::type");
9697 errors++;
9698 }
9699 }
9700 else if (!strcmp(ce->ce_vardata, "version"))
9701 {
9702 char has_mask = 0, has_version = 0, has_flags = 0;
9703 for (cep = ce->ce_entries; cep; cep = cep->ce_next)
9704 {
9705 if (config_is_blankorempty(cep, "deny version"))
9706 {
9707 errors++;
9708 continue;
9709 }
9710 if (!strcmp(cep->ce_varname, "mask"))
9711 {
9712 if (has_mask)
9713 {
9714 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9715 cep->ce_varlinenum, "deny version::mask");
9716 continue;
9717 }
9718 has_mask = 1;
9719 }
9720 else if (!strcmp(cep->ce_varname, "version"))
9721 {
9722 if (has_version)
9723 {
9724 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9725 cep->ce_varlinenum, "deny version::version");
9726 continue;
9727 }
9728 has_version = 1;
9729 }
9730 else if (!strcmp(cep->ce_varname, "flags"))
9731 {
9732 if (has_flags)
9733 {
9734 config_warn_duplicate(cep->ce_fileptr->cf_filename,
9735 cep->ce_varlinenum, "deny version::flags");
9736 continue;
9737 }
9738 has_flags = 1;
9739 }
9740 else
9741 {
9742 config_error_unknown(cep->ce_fileptr->cf_filename,
9743 cep->ce_varlinenum, "deny version", cep->ce_varname);
9744 errors++;
9745 }
9746 }
9747 if (!has_mask)
9748 {
9749 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
9750 "deny version::mask");
9751 errors++;
9752 }
9753 if (!has_version)
9754 {
9755 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
9756 "deny version::version");
9757 errors++;
9758 }
9759 if (!has_flags)
9760 {
9761 config_error_missing(ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
9762 "deny version::flags");
9763 errors++;
9764 }
9765 }
9766 else
9767 {
9768 int used = 0;
9769 for (h = Hooks[HOOKTYPE_CONFIGTEST]; h; h = h->next)
9770 {
9771 int value, errs = 0;
9772 if (h->owner && !(h->owner->flags & MODFLAG_TESTING)
9773 && !(h->owner->options & MOD_OPT_PERM))
9774 continue;
9775 value = (*(h->func.intfunc))(conf,ce,CONFIG_DENY, &errs);
9776 if (value == 2)
9777 used = 1;
9778 if (value == 1)
9779 {
9780 used = 1;
9781 break;
9782 }
9783 if (value == -1)
9784 {
9785 used = 1;
9786 errors += errs;
9787 break;
9788 }
9789 if (value == -2)
9790 {
9791 used = 1;
9792 errors += errs;
9793 }
9794 }
9795 if (!used) {
9796 config_error("%s:%i: unknown deny type %s",
9797 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
9798 ce->ce_vardata);
9799 return 1;
9800 }
9801 return errors;
9802 }
9803
9804 return errors;
9805 }
9806
9807 #ifdef USE_LIBCURL
conf_download_complete(const char * url,const char * file,const char * errorbuf,int cached,void * inc_key)9808 static void conf_download_complete(const char *url, const char *file, const char *errorbuf, int cached, void *inc_key)
9809 {
9810 ConfigItem_include *inc;
9811 if (!loop.ircd_rehashing)
9812 return;
9813
9814 /*
9815 use inc_key to find the correct include block. This
9816 should be cheaper than using the full URL.
9817 */
9818 for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
9819 {
9820 if ( inc_key != (void *)inc )
9821 continue;
9822 if (!(inc->flag.type & INCLUDE_REMOTE))
9823 continue;
9824 if (inc->flag.type & INCLUDE_NOTLOADED)
9825 continue;
9826 if (stricmp(url, inc->url))
9827 continue;
9828
9829 inc->flag.type &= ~INCLUDE_DLQUEUED;
9830 break;
9831 }
9832 if (!inc)
9833 {
9834 ircd_log(LOG_ERROR, "Downloaded remote include which matches no include statement.");
9835 return;
9836 }
9837
9838 if (!file && !cached)
9839 update_remote_include(inc, file, 0, errorbuf); /* DOWNLOAD FAILED */
9840 else
9841 {
9842 char *urlfile = url_getfilename(url);
9843 char *file_basename = unreal_getfilename(urlfile);
9844 char *tmp = unreal_mktemp("/var/run/ircd/tmp", file);
9845 free(urlfile);
9846
9847 if (cached)
9848 {
9849 unreal_copyfileex(inc->file, tmp, 1);
9850 #ifdef REMOTEINC_SPECIALCACHE
9851 unreal_copyfileex(inc->file, unreal_mkcache(url), 0);
9852 #endif
9853 update_remote_include(inc, tmp, 0, NULL);
9854 }
9855 else
9856 {
9857 /*
9858 copy/hardlink file to another file because our caller will
9859 remove(file).
9860 */
9861 unreal_copyfileex(file, tmp, 1);
9862 update_remote_include(inc, tmp, 0, NULL);
9863 #ifdef REMOTEINC_SPECIALCACHE
9864 unreal_copyfileex(file, unreal_mkcache(url), 0);
9865 #endif
9866 }
9867 }
9868 for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
9869 {
9870 if (inc->flag.type & INCLUDE_DLQUEUED)
9871 return;
9872 }
9873 rehash_internal(loop.rehash_save_cptr, loop.rehash_save_sptr, loop.rehash_save_sig);
9874 }
9875 #endif
9876
rehash(aClient * cptr,aClient * sptr,int sig)9877 int rehash(aClient *cptr, aClient *sptr, int sig)
9878 {
9879 #ifdef USE_LIBCURL
9880 ConfigItem_include *inc;
9881 char found_remote = 0;
9882 if (loop.ircd_rehashing)
9883 {
9884 if (!sig)
9885 sendto_one(sptr, ":%s NOTICE %s :A rehash is already in progress",
9886 me.name, sptr->name);
9887 return 0;
9888 }
9889
9890 loop.ircd_rehashing = 1;
9891 loop.rehash_save_cptr = cptr;
9892 loop.rehash_save_sptr = sptr;
9893 loop.rehash_save_sig = sig;
9894 for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
9895 {
9896 time_t modtime;
9897 if (!(inc->flag.type & INCLUDE_REMOTE))
9898 continue;
9899
9900 if (inc->flag.type & INCLUDE_NOTLOADED)
9901 continue;
9902 found_remote = 1;
9903 modtime = unreal_getfilemodtime(inc->file);
9904 inc->flag.type |= INCLUDE_DLQUEUED;
9905
9906 /*
9907 use (void *)inc as the key for finding which
9908 include block conf_download_complete() should use.
9909 */
9910 download_file_async(inc->url, modtime, conf_download_complete, (void *)inc);
9911 }
9912 if (!found_remote)
9913 return rehash_internal(cptr, sptr, sig);
9914 return 0;
9915 #else
9916 loop.ircd_rehashing = 1;
9917 return rehash_internal(cptr, sptr, sig);
9918 #endif
9919 }
9920
rehash_internal(aClient * cptr,aClient * sptr,int sig)9921 int rehash_internal(aClient *cptr, aClient *sptr, int sig)
9922 {
9923 flush_connections(&me);
9924 if (sig == 1)
9925 {
9926 sendto_ops("Got signal SIGHUP, reloading %s file", configfile);
9927 #ifdef ULTRIX
9928 if (fork() > 0)
9929 exit(0);
9930 write_pidfile();
9931 #endif
9932 }
9933 loop.ircd_rehashing = 1; /* double checking.. */
9934 if (init_conf(configfile, 1) == 0)
9935 run_configuration();
9936 if (sig == 1)
9937 reread_motdsandrules();
9938 unload_all_unused_snomasks();
9939 unload_all_unused_umodes();
9940 unload_all_unused_extcmodes();
9941 loop.ircd_rehashing = 0;
9942 return 1;
9943 }
9944
link_cleanup(ConfigItem_link * link_ptr)9945 void link_cleanup(ConfigItem_link *link_ptr)
9946 {
9947 ircfree(link_ptr->servername);
9948 ircfree(link_ptr->username);
9949 ircfree(link_ptr->bindip);
9950 ircfree(link_ptr->hostname);
9951 ircfree(link_ptr->hubmask);
9952 ircfree(link_ptr->leafmask);
9953 ircfree(link_ptr->connpwd);
9954 #ifdef USE_SSL
9955 ircfree(link_ptr->ciphers);
9956 #endif
9957 Auth_DeleteAuthStruct(link_ptr->recvauth);
9958 link_ptr->recvauth = NULL;
9959 }
9960
delete_linkblock(ConfigItem_link * link_ptr)9961 void delete_linkblock(ConfigItem_link *link_ptr)
9962 {
9963 Debug((DEBUG_ERROR, "delete_linkblock: deleting %s, refcount=%d",
9964 link_ptr->servername, link_ptr->refcount));
9965 if (link_ptr->class)
9966 {
9967 link_ptr->class->xrefcount--;
9968 /* Perhaps the class is temporary too and we need to free it... */
9969 if (link_ptr->class->flag.temporary &&
9970 !link_ptr->class->clients && !link_ptr->class->xrefcount)
9971 {
9972 delete_classblock(link_ptr->class);
9973 link_ptr->class = NULL;
9974 }
9975 }
9976 link_cleanup(link_ptr);
9977 DelListItem(link_ptr, conf_link);
9978 MyFree(link_ptr);
9979 }
9980
delete_cgiircblock(ConfigItem_cgiirc * e)9981 void delete_cgiircblock(ConfigItem_cgiirc *e)
9982 {
9983 Debug((DEBUG_ERROR, "delete_cgiircblock: deleting %s", e->hostname));
9984 if (e->auth)
9985 Auth_DeleteAuthStruct(e->auth);
9986 ircfree(e->hostname);
9987 ircfree(e->username);
9988 DelListItem(e, conf_cgiirc);
9989 MyFree(e);
9990 }
9991
delete_classblock(ConfigItem_class * class_ptr)9992 void delete_classblock(ConfigItem_class *class_ptr)
9993 {
9994 Debug((DEBUG_ERROR, "delete_classblock: deleting %s, clients=%d, xrefcount=%d",
9995 class_ptr->name, class_ptr->clients, class_ptr->xrefcount));
9996 ircfree(class_ptr->name);
9997 DelListItem(class_ptr, conf_class);
9998 MyFree(class_ptr);
9999 }
10000
listen_cleanup()10001 void listen_cleanup()
10002 {
10003 int i = 0;
10004 ConfigItem_listen *listen_ptr;
10005 ListStruct *next;
10006 for (listen_ptr = conf_listen; listen_ptr; listen_ptr = (ConfigItem_listen *)next)
10007 {
10008 next = (ListStruct *)listen_ptr->next;
10009 if (listen_ptr->flag.temporary && !listen_ptr->clients)
10010 {
10011 ircfree(listen_ptr->ip);
10012 DelListItem(listen_ptr, conf_listen);
10013 MyFree(listen_ptr);
10014 i++;
10015 }
10016 }
10017 if (i)
10018 close_listeners();
10019 }
10020
10021 #ifdef USE_LIBCURL
find_remote_include(char * url,char ** errorbuf)10022 char *find_remote_include(char *url, char **errorbuf)
10023 {
10024 ConfigItem_include *inc;
10025 for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
10026 {
10027 if (!(inc->flag.type & INCLUDE_NOTLOADED))
10028 continue;
10029 if (!(inc->flag.type & INCLUDE_REMOTE))
10030 continue;
10031 if (!stricmp(url, inc->url))
10032 {
10033 *errorbuf = inc->errorbuf;
10034 return inc->file;
10035 }
10036 }
10037 return NULL;
10038 }
10039
find_loaded_remote_include(char * url)10040 char *find_loaded_remote_include(char *url)
10041 {
10042 ConfigItem_include *inc;
10043 for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
10044 {
10045 if ((inc->flag.type & INCLUDE_NOTLOADED))
10046 continue;
10047 if (!(inc->flag.type & INCLUDE_REMOTE))
10048 continue;
10049 if (!stricmp(url, inc->url))
10050 return inc->file;
10051 }
10052 return NULL;
10053 }
10054
10055 /**
10056 * Non-asynchronous remote inclusion to give a user better feedback
10057 * when first starting his IRCd.
10058 *
10059 * The asynchronous friend is rehash() which merely queues remote
10060 * includes for download using download_file_async().
10061 */
remote_include(ConfigEntry * ce)10062 int remote_include(ConfigEntry *ce)
10063 {
10064 char *errorbuf = NULL;
10065 char *file = find_remote_include(ce->ce_vardata, &errorbuf);
10066 int ret;
10067 if (!loop.ircd_rehashing || (loop.ircd_rehashing && !file && !errorbuf))
10068 {
10069 char *error;
10070 if (config_verbose > 0)
10071 config_status("Downloading %s", ce->ce_vardata);
10072 file = download_file(ce->ce_vardata, &error);
10073 if (!file)
10074 {
10075 #ifdef REMOTEINC_SPECIALCACHE
10076 if (has_cached_version(ce->ce_vardata))
10077 {
10078 config_warn("%s:%i: include: error downloading '%s': %s -- using cached version instead.",
10079 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
10080 ce->ce_vardata, error);
10081 file = strdup(unreal_mkcache(ce->ce_vardata));
10082 /* Let it pass to load_conf()... */
10083 } else {
10084 #endif
10085 config_error("%s:%i: include: error downloading '%s': %s",
10086 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
10087 ce->ce_vardata, error);
10088 return -1;
10089 #ifdef REMOTEINC_SPECIALCACHE
10090 }
10091 #endif
10092 }
10093 add_remote_include(file, ce->ce_vardata, 0, NULL, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
10094 ret = load_conf(file, ce->ce_vardata);
10095 free(file);
10096 return ret;
10097 }
10098 else
10099 {
10100 if (errorbuf)
10101 {
10102 #ifdef REMOTEINC_SPECIALCACHE
10103 if (has_cached_version(ce->ce_vardata))
10104 {
10105 config_warn("%s:%i: include: error downloading '%s': %s -- using cached version instead.",
10106 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
10107 ce->ce_vardata, errorbuf);
10108 /* Let it pass to load_conf()... */
10109 file = strdup(unreal_mkcache(ce->ce_vardata));
10110 } else {
10111 #endif
10112 config_error("%s:%i: include: error downloading '%s': %s",
10113 ce->ce_fileptr->cf_filename, ce->ce_varlinenum,
10114 ce->ce_vardata, errorbuf);
10115 return -1;
10116 #ifdef REMOTEINC_SPECIALCACHE
10117 }
10118 #endif
10119 }
10120 if (config_verbose > 0)
10121 config_status("Loading %s from download", ce->ce_vardata);
10122 add_remote_include(file, ce->ce_vardata, 0, NULL, ce->ce_fileptr->cf_filename, ce->ce_varlinenum);
10123 ret = load_conf(file, ce->ce_vardata);
10124 return ret;
10125 }
10126 return 0;
10127 }
10128 #endif
10129
10130 /**
10131 * Add an item to the conf_include list for the specified file.
10132 *
10133 * Checks for whether or not we're performing recursive includes
10134 * belong in conf_load() because that function is able to return an
10135 * error code. Any checks in here will end up being ignored by callers
10136 * and thus will gain us nothing.
10137 *
10138 * @param file path to the include file.
10139 */
add_include(const char * file,const char * included_from,int included_from_line)10140 void add_include(const char *file, const char *included_from, int included_from_line)
10141 {
10142 ConfigItem_include *inc;
10143
10144 inc = MyMallocEx(sizeof(ConfigItem_include));
10145 inc->file = strdup(file);
10146 inc->flag.type = INCLUDE_NOTLOADED;
10147 inc->included_from = strdup(included_from);
10148 inc->included_from_line = included_from_line;
10149 AddListItem(inc, conf_include);
10150 }
10151
10152 #ifdef USE_LIBCURL
10153 /**
10154 * Adds a remote include entry to the config_include list.
10155 *
10156 * This is to be called whenever the included_from and
10157 * included_from_line parameters are known. This means that during a
10158 * rehash when downloads are done asynchronously, you call this with
10159 * the inclued_from and included_from_line information. After the
10160 * download is complete and you know there it is stored in the FS,
10161 * call update_remote_include().
10162 */
add_remote_include(const char * file,const char * url,int flags,const char * errorbuf,const char * included_from,int included_from_line)10163 void add_remote_include(const char *file, const char *url, int flags, const char *errorbuf, const char *included_from, int included_from_line)
10164 {
10165 ConfigItem_include *inc;
10166
10167 /* we rely on MyMallocEx() zeroing the ConfigItem_include */
10168 inc = MyMallocEx(sizeof(ConfigItem_include));
10169 if (included_from)
10170 {
10171 inc->included_from = strdup(included_from);
10172 inc->included_from_line = included_from_line;
10173 }
10174 inc->url = strdup(url);
10175
10176 update_remote_include(inc, file, INCLUDE_NOTLOADED|INCLUDE_REMOTE|flags, errorbuf);
10177 AddListItem(inc, conf_include);
10178 }
10179
10180 /**
10181 * Update certain information in a remote include's config_include list entry.
10182 *
10183 * @param file the place on disk where the downloaded remote include
10184 * may be found
10185 * @param flags additional flags to set on the config_include entry
10186 * @param errorbuf non-NULL if there were errors encountered in
10187 * downloading. The error will be stored into the config_include
10188 * entry.
10189 */
update_remote_include(ConfigItem_include * inc,const char * file,int flags,const char * errorbuf)10190 void update_remote_include(ConfigItem_include *inc, const char *file, int flags, const char *errorbuf)
10191 {
10192 /*
10193 * file may be NULL when errorbuf is non-NULL and vice-versa.
10194 */
10195 if (file)
10196 inc->file = strdup(file);
10197 inc->flag.type |= flags;
10198
10199 if (errorbuf)
10200 inc->errorbuf = strdup(errorbuf);
10201 }
10202 #endif
10203
10204 /**
10205 * Clean up conf_include after a rehash fails because of a
10206 * configuration file error.
10207 *
10208 * Duplicates some in unload_loaded_include().
10209 */
unload_notloaded_includes(void)10210 void unload_notloaded_includes(void)
10211 {
10212 ConfigItem_include *inc, *next;
10213
10214 for (inc = conf_include; inc; inc = next)
10215 {
10216 next = (ConfigItem_include *)inc->next;
10217 if ((inc->flag.type & INCLUDE_NOTLOADED) || !(inc->flag.type & INCLUDE_USED))
10218 {
10219 #ifdef USE_LIBCURL
10220 if (inc->flag.type & INCLUDE_REMOTE)
10221 {
10222 remove(inc->file);
10223 free(inc->url);
10224 if (inc->errorbuf)
10225 free(inc->errorbuf);
10226 }
10227 #endif
10228 free(inc->file);
10229 free(inc->included_from);
10230 DelListItem(inc, conf_include);
10231 free(inc);
10232 }
10233 }
10234 }
10235
10236 /**
10237 * Clean up conf_include after a successful rehash to make way for
10238 * load_includes().
10239 */
unload_loaded_includes(void)10240 void unload_loaded_includes(void)
10241 {
10242 ConfigItem_include *inc, *next;
10243
10244 for (inc = conf_include; inc; inc = next)
10245 {
10246 next = (ConfigItem_include *)inc->next;
10247 if (!(inc->flag.type & INCLUDE_NOTLOADED) || !(inc->flag.type & INCLUDE_USED))
10248 {
10249 #ifdef USE_LIBCURL
10250 if (inc->flag.type & INCLUDE_REMOTE)
10251 {
10252 remove(inc->file);
10253 free(inc->url);
10254 if (inc->errorbuf)
10255 free(inc->errorbuf);
10256 }
10257 #endif
10258 free(inc->file);
10259 free(inc->included_from);
10260 DelListItem(inc, conf_include);
10261 free(inc);
10262 }
10263 }
10264 }
10265
10266 /**
10267 * Mark loaded includes as loaded by removing the INCLUDE_NOTLOADED
10268 * flag. Meant to be called only after calling
10269 * unload_loaded_includes().
10270 */
load_includes(void)10271 void load_includes(void)
10272 {
10273 ConfigItem_include *inc;
10274
10275 /* Doing this for all the includes should actually be faster
10276 * than only doing it for includes that are not-loaded
10277 */
10278 for (inc = conf_include; inc; inc = (ConfigItem_include *)inc->next)
10279 inc->flag.type &= ~INCLUDE_NOTLOADED;
10280 }
10281