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