1 /************************************************************************
2  *   IRC - Internet Relay Chat, iauth/a_conf.c
3  *   Copyright (C) 1998 Christophe Kalt
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 1, or (at your option)
8  *   any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 #ifndef lint
21 static const volatile char rcsid[] = "@(#)$Id: a_conf.c,v 1.39 2004/11/13 16:46:18 chopin Exp $";
22 #endif
23 
24 #include "os.h"
25 #include "a_defines.h"
26 #define A_CONF_C
27 #include "a_externs.h"
28 #undef A_CONF_C
29 
30 static aModule *Mlist[16];
31 
32 #define DEFAULT_TIMEOUT 30
33 
34 u_int	debuglevel = 0;
35 
36 AnInstance *instances = NULL;
37 
conf_err(u_int nb,char * msg,char * chk)38 static	void	conf_err(u_int nb, char *msg, char *chk)
39 {
40 	if (chk)
41 		fprintf(stderr, "configuration error line %d: %s\n", nb, msg);
42 	else
43 		sendto_log(ALOG_IRCD|ALOG_DCONF, LOG_ERR,
44 			   "Configuration error line %d: %s", nb, msg);
45 	exit(1);
46 }
47 
48 /*
49  * Match address by #IP bitmask (10.11.12.128/27)
50  */
match_ipmask(aTarget * mask,char * ipaddr)51 static	int	match_ipmask(aTarget *mask, char *ipaddr)
52 {
53 #ifdef INET6
54 	return 1;
55 #else
56         int i1, i2, i3, i4;
57 	u_long iptested;
58 
59         if (sscanf(ipaddr, "%d.%d.%d.%d", &i1, &i2, &i3, &i4) != 4)
60 		return -1;
61 	iptested = htonl(i1 * 0x1000000 + i2 * 0x10000 + i3 * 0x100 + i4);
62         return ((iptested & mask->lmask) == mask->baseip) ? 0 : 1;
63 #endif
64 }
65 
66 /* conf_read: read the configuration file, instanciate modules */
conf_read(char * cfile)67 char	*conf_read(char *cfile)
68 {
69 	AnInstance *ident = NULL; /* make sure this module is used */
70 	u_char needh = 0; /* do we need hostname information for any host? */
71 	u_char o_req = 0, o_dto = 0, o_wup = 0, o_del = 0;
72 	static char o_all[5];
73 	u_int timeout = DEFAULT_TIMEOUT, totto = 0;
74 	u_int lnnb = 0, i;
75 	u_char icount = 0, Mcnt = 0;
76 	char buffer[160], *ch;
77 	AnInstance **last = &instances, *itmp;
78 	FILE *cfh;
79 
80 	Mlist[Mcnt++] = &Module_rfc931;
81 	Mlist[Mcnt++] = &Module_socks;
82 	Mlist[Mcnt++] = &Module_pipe;
83 	Mlist[Mcnt++] = &Module_lhex;
84 	Mlist[Mcnt++] = &Module_webproxy;
85 	Mlist[Mcnt] = NULL;
86 
87 	cfh = fopen((cfile) ? cfile : IAUTHCONF_PATH, "r");
88 	if (!cfh)
89 	    {
90 		if (cfile)
91 		    {
92 			perror("Couldn't open config file");
93 			exit(0);
94 		    }
95 	    }
96 	else
97 	    {
98 		while (fgets(buffer, 160, cfh))
99 		    {
100 			if ((ch = index(buffer, '\n')))
101 			{
102 				lnnb += 1;
103 			}
104 			else
105 			{
106 				conf_err(lnnb, "line too long, ignoring.",
107 					 cfile);
108 				/* now skip what's left */
109 				while (fgets(buffer, 160, cfh))
110 				{
111 					if (index(buffer, '\n'))
112 					{
113 						break;
114 					}
115 				}
116 				continue;
117 			}
118 			if (buffer[0] == '#' || buffer[0] == '\n')
119 				continue;
120 			*ch = '\0';
121 			if ((ch = index(buffer, '#')))
122 			{
123 				*ch = '\0';
124 			}
125 			if (!strncmp("required", buffer, 8))
126 			  {
127 				o_req = 1;
128 				continue;
129 			  }
130 			if (!strncmp("notimeout", buffer, 9))
131 			  {
132 				o_dto = 1;
133 				continue;
134 			  }
135 			if (!strncmp("extinfo", buffer, 7))
136 			  {
137 				o_wup = 1;
138 				continue;
139 			  }
140 			if (!strncmp("delayed", buffer, 7))
141 			  {
142 				o_del = 1;
143 				continue;
144 			  }
145 			if (!strncmp("timeout = ", buffer, 10))
146 			    {
147 				if (sscanf(buffer, "timeout = %u",
148 					   &timeout) != 1)
149 					conf_err(lnnb, "Invalid setting.",
150 						 cfile);
151 				continue;
152 			    }
153 			/* debugmode setting */
154 			if (!strncmp("debuglvl = 0x", buffer, 13))
155 			    {
156 				if (sscanf(buffer, "debuglvl = %x",
157 					   &debuglevel) != 1)
158 					conf_err(lnnb, "Invalid setting.",
159 						 cfile);
160 				else if (!cfile)
161 					sendto_log(ALOG_DCONF, LOG_DEBUG,
162 						   "debuglevel = %X",
163 						   debuglevel);
164 				continue;
165 			    }
166 #if defined(USE_DSM)
167 			if (!strncmp("shared ", buffer, 7))
168 			    {
169 				char lfname[80];
170 				void *mod_handle;
171 				aModule *(*load_func)();
172 
173 				ch = index(buffer+7, ' ');
174 				if (ch == NULL)
175 				    {
176 					conf_err(lnnb, "Syntax error.", cfile);
177 					continue;
178 				    }
179 				*ch++ = '\0';
180 # if defined(RTLD_NOW)
181 				mod_handle = dlopen(ch, RTLD_NOW);
182 # else
183 				mod_handle = dlopen(ch, RTLD_LAZY);
184 # endif
185 				if (mod_handle == NULL)
186 				    {
187 					conf_err(lnnb, dlerror(), cfile);
188 					continue;
189 				    }
190 # if defined(DLSYM_NEEDS_UNDERSCORE)
191 				sprintf(lfname, "_%s_load", buffer+7);
192 # else
193 				sprintf(lfname, "%s_load", buffer+7);
194 # endif
195 				load_func = (aModule *(*)())dlsym(mod_handle,
196 								  lfname);
197 				if (load_func == NULL)
198 				    {
199 					conf_err(lnnb,"Invalid shared object.",
200 						 cfile);
201 					dlclose(mod_handle);
202 					continue;
203 				    }
204 				Mlist[Mcnt] = load_func();
205 				if (Mlist[Mcnt])
206 				    {
207 					Mcnt += 1;
208 					Mlist[Mcnt] = NULL;
209 				    }
210 				else
211 				    {
212 					conf_err(lnnb, "Failed.", cfile);
213 					dlclose(mod_handle);
214 				    }
215 				continue;
216 			    }
217 #endif
218 			if (!strncmp("exit", buffer, 4))
219 			{
220 				break;
221 			}
222 			if (buffer[0] == '\t')
223 			    {
224 				conf_err(lnnb, "Ignoring unexpected property.",
225 					 cfile);
226 				continue;
227 			    }
228 			/* at this point, it has to be the following */
229 			if (strncasecmp("module ", buffer, 7))
230 			    {
231 				conf_err(lnnb,
232 					 "Unexpected line: not a module.",
233 					 cfile);
234 				continue;
235 			    }
236 			for (i = 0; Mlist[i] != NULL; i++)
237 				if (!strcasecmp(buffer+7, Mlist[i]->name))
238 					break;
239 			if (Mlist[i] == NULL)
240 			    {
241 				conf_err(lnnb, "Unknown module name.", cfile);
242 				continue;
243 			    }
244 			if (Mlist[i] == &Module_rfc931 && ident)
245 			    {
246 				conf_err(lnnb,
247 				 "This module can only be loaded once.",
248 					 cfile);
249 				continue;
250 			    }
251 			*last = (AnInstance *) malloc(sizeof(AnInstance));
252 			(*last)->nexti = NULL;
253 			(*last)->in = icount++;
254 			(*last)->mod = Mlist[i];
255 			(*last)->opt = NULL;
256 			(*last)->popt = NULL;
257 			(*last)->data = NULL;
258 			(*last)->hostname = NULL;
259 			(*last)->address = NULL;
260 			(*last)->timeout = timeout;
261 			(*last)->reason	= NULL;
262 			(*last)->delayed = o_del;
263 			(*last)->port = 0;
264 			if (Mlist[i] == &Module_rfc931)
265 				ident = *last;
266 
267 			while (fgets(buffer, 160, cfh))
268 			    {
269 				aTarget **ttmp;
270 				u_long baseip = 0, lmask = 0;
271 				int inverse = 0;
272 
273 				if ((ch = index(buffer, '\n')))
274 				{
275 					lnnb += 1;
276 				}
277 				else
278 				{
279 					conf_err(lnnb,
280 						 "line too long, ignoring.",
281 						 cfile);
282 					/* now skip what's left */
283 					while (fgets(buffer, 160, cfh))
284 						if (index(buffer,'\n'))
285 							break;
286 					continue;
287 				}
288 				if (buffer[0] == '#')
289 					continue;
290 				if (buffer[0] == '\n')
291 					break;
292 				if (buffer[0] != '\t')
293 				    {
294 					conf_err(lnnb, "Invalid syntax.",
295 						 cfile);
296 					continue;
297 				    }
298 				*ch = '\0';
299 				if (!strncasecmp(buffer+1, "option = ", 9))
300 				    {
301 					if ((*last)->opt)
302 						conf_err(lnnb,
303 					 "Duplicate option keyword: ignored.",
304 							 cfile);
305 					else
306 						(*last)->opt =
307 							mystrdup(buffer + 10);
308 					continue;
309 				    }
310 				if (!strncasecmp(buffer+1, "reason = ", 9))
311 				{
312 					if ((*last)->reason)
313 						conf_err(lnnb,
314 					"Duplicate reason keyword: ignored.",
315 						cfile);
316 					else
317 						(*last)->reason =
318 							mystrdup(buffer + 10);
319 					continue;
320 				}
321 				if (!strncasecmp(buffer+1, "host = ", 7))
322 				    {
323 					needh = 1;
324 					ttmp = &((*last)->hostname);
325 					ch = buffer + 8;
326 					if (*ch == '!')
327 					{
328 						inverse = 1;
329 						ch++;
330 					}
331 				    }
332 				else if (!strncasecmp(buffer+1, "ip = ", 5))
333 				    {
334 					ttmp = &((*last)->address);
335 					ch = buffer + 6;
336 					if (*ch == '!')
337 					{
338 						inverse = 1;
339 						ch++;
340 					}
341 					if (strchr(ch, '/'))
342 					    {
343 						int i1, i2, i3, i4, m;
344 
345 						if (sscanf(ch,"%d.%d.%d.%d/%d",
346 							   &i1, &i2, &i3, &i4,
347 							   &m) != 5 ||
348 						    m < 1 || m > 31)
349 						    {
350 							conf_err(lnnb,
351 								 "Bad mask.",
352 								 cfile);
353 							continue;
354 						    }
355 						lmask = htonl((u_long)0xffffffffL << (32 - m));
356 						baseip = htonl(i1 * 0x1000000 +
357 							       i2 * 0x10000 +
358 							       i3 * 0x100 +
359 							       i4);
360 					    }
361 					else
362 					    {
363 						lmask = 0;
364 						baseip = 0;
365 					    }
366 				    }
367 				else if (!strncmp(buffer+1, "timeout = ", 10))
368 				    {
369 					u_int local_timeout;
370 					if (sscanf(buffer+1, "timeout = %u",
371 						   &local_timeout) != 1)
372 						conf_err(lnnb,
373 							 "Invalid setting.",
374 							 cfile);
375 					(*last)->timeout = local_timeout;
376 					continue;
377 				    }
378 				else if (!strncmp(buffer+1, "port = ", 7))
379 				    {
380 					u_int local_port;
381 					if (sscanf(buffer+1, "port = %u",
382 						   &local_port) != 1)
383 						conf_err(lnnb,
384 							 "Invalid setting.",
385 							 cfile);
386 					(*last)->port = local_port;
387 					continue;
388 				    }
389 				else
390 				    {
391 					conf_err(lnnb, "Invalid keyword.",
392 						 cfile);
393 					continue;
394 				    }
395 				if (Mlist[i] == &Module_rfc931)
396 					continue;
397 				while (*ttmp)
398 					ttmp = &((*ttmp)->nextt);
399 				*ttmp = (aTarget *) malloc(sizeof(aTarget));
400 				(*ttmp)->yes = inverse ? -1 : 0;
401 				(*ttmp)->value = mystrdup(ch);
402 				if ((*ttmp)->baseip)
403 				    {
404 					(*ttmp)->lmask = lmask;
405 					(*ttmp)->baseip = baseip;
406 				    }
407 				(*ttmp)->nextt = NULL;
408 			    }
409 			if ((*last)->port == 0 &&
410 				(Mlist[i] == &Module_webproxy ||
411 				Mlist[i] == &Module_socks))
412 			{
413 				conf_err(lnnb, "port here is mandatory.", cfile);
414 			}
415 
416 			last = &((*last)->nexti);
417 		    }
418 		fclose(cfh);
419 	    }
420 
421 	if (ident == NULL)
422 	    {
423 		ident = *last = (AnInstance *) malloc(sizeof(AnInstance));
424 		(*last)->nexti = NULL;
425 		(*last)->opt = NULL;
426 		(*last)->mod = &Module_rfc931;
427 		(*last)->hostname = NULL;
428 		(*last)->address = NULL;
429 		(*last)->timeout = DEFAULT_TIMEOUT;
430 		(*last)->in = icount;
431 		(*last)->popt = NULL;
432 		(*last)->address = NULL;
433 		(*last)->delayed = o_del;
434 		(*last)->port = 0;
435 	    }
436 	if (ident->timeout < DEFAULT_TIMEOUT)
437 	{
438 		if (cfile)
439 		{
440 			printf("Warning: rfc913 is less than %d.\n",
441 				DEFAULT_TIMEOUT);
442 		}
443 		else
444 		{
445 			sendto_log(ALOG_IRCD|ALOG_DCONF, LOG_ERR,
446 				"Warning: rfc913 is less than %d.",
447 				DEFAULT_TIMEOUT);
448 		}
449 	}
450 	if (ident->delayed)
451 	{
452 		if (cfile)
453 		{
454 			printf("Warning: rfc913 should not be delayed.\n");
455 		}
456 		else
457 		{
458 			sendto_log(ALOG_IRCD|ALOG_DCONF, LOG_ERR,
459 				"Warning: rfc913 should not be delayed.");
460 		}
461 	}
462 
463 	itmp = instances;
464 	while (itmp)
465 	    {
466 		if (!itmp->delayed)
467 		totto += itmp->timeout;
468 		itmp = itmp->nexti;
469 	    }
470 	if (totto > ACCEPTTIMEOUT)
471 	    {
472 		if (cfile)
473 		{
474 			printf("Warning: sum of timeouts exceeds "
475 				"ACCEPTTIMEOUT!\n");
476 		}
477 		else
478 		{
479 			sendto_log(ALOG_IRCD|ALOG_DCONF, LOG_ERR,
480 				"Warning: sum of timeouts exceeds "
481 				"ACCEPTTIMEOUT!");
482 		}
483 		if (o_dto)
484 		{
485 			if (cfile)
486 			{
487 				printf("Error: \"notimeout\" is set!\n");
488 			}
489 			else
490 			{
491 				sendto_log(ALOG_IRCD|ALOG_DCONF, LOG_ERR,
492 					   "Error: \"notimeout\" is set!");
493 			}
494 		}
495 	    }
496 
497 	itmp = instances;
498 	if (cfile)
499 	    {
500 		aTarget *ttmp;
501 		char *err;
502 
503 		printf("\nModule(s) loaded:\n");
504 		while (itmp)
505 		    {
506 			printf("\t%s\t%s\n", itmp->mod->name,
507 			       (itmp->opt) ? itmp->opt : "");
508 			if ((ttmp = itmp->hostname))
509 			    {
510 				printf("\t\tHost = %s%s",
511 				       (ttmp->yes == 0) ? "" : "!",
512 				       ttmp->value);
513 				while ((ttmp = ttmp->nextt))
514 					printf(",%s%s",
515 					       (ttmp->yes == 0) ? "" : "!",
516 					       ttmp->value);
517 				printf("\n");
518 			    }
519 			if ((ttmp = itmp->address))
520 			    {
521 				printf("\t\tIP   = %s%s",
522 				       ((ttmp->yes == 0) ? "" : "!"),
523 				       ttmp->value);
524 				while ((ttmp = ttmp->nextt))
525 				{
526 					printf(",%s%s",
527 					       ((ttmp->yes == 0) ? "" : "!"),
528 					       ttmp->value);
529 				}
530 				printf("\n");
531 			    }
532 			if (itmp->timeout != DEFAULT_TIMEOUT)
533 				printf("\t\ttimeout: %u seconds\n",
534 				       itmp->timeout);
535 			if (itmp->port != 0)
536 				printf("\t\tport: %u\n",
537 				       itmp->port);
538 			if (itmp->mod->init)
539 			    {
540 				err = itmp->mod->init(itmp);
541 				printf("\t\tInitialization: %s\n",
542 				       (err) ? err : "Successful");
543 			    }
544 			itmp = itmp->nexti;
545 		    }
546 	    }
547 	else
548 	{
549 		while (itmp)
550 		{
551 			if (itmp->mod->init)
552 			{
553 				itmp->mod->init(itmp);
554 			}
555 			itmp = itmp->nexti;
556 		}
557 	}
558 
559 	ch = o_all;
560 	if (o_req) *ch++ = 'R';
561 	if (o_dto) *ch++ = 'T';
562 	if (o_wup) *ch++ = 'A';
563 	if (needh) *ch++ = 'W';
564 	*ch++ = '\0';
565 	return o_all;
566 }
567 
568 /* conf_match: check if an instance is to be applied to a connection
569    Returns -1: no match, and never will
570             0: got a match, doIt[tm]
571 	    1: no match, but might be later so ask again */
conf_match(u_int cl,AnInstance * inst)572 int	conf_match(u_int cl, AnInstance *inst)
573 {
574 	aTarget *ttmp;
575 
576 	/* general case, always matches */
577 	if (inst->address == NULL && inst->hostname == NULL)
578 		return 0;
579 	/* feature case, "host = *" to force to wait for DNS info */
580 	if ((cldata[cl].state & A_NOH) && inst->hostname &&
581 	    !strcmp(inst->hostname->value, "*"))
582 		return 0;
583 	/* check matches on IP addresses */
584 	if ((ttmp = inst->address))
585 	{
586 		while (ttmp)
587 		{
588 			if (ttmp->baseip)
589 			{
590 				if (match_ipmask(ttmp, cldata[cl].itsip) == 0)
591 				{
592 					return ttmp->yes;
593 				}
594 			}
595 			else
596 			{
597 				if (match(ttmp->value, cldata[cl].itsip) == 0)
598 				{
599 					return ttmp->yes;
600 				}
601 			}
602 			ttmp = ttmp->nextt;
603 		}
604 	}
605 	/* check matches on hostnames */
606 	if ((ttmp = inst->hostname))
607 	    {
608 		if (cldata[cl].state & A_GOTH)
609 		    {
610 			while (ttmp)
611 			    {
612 				if (match(ttmp->value, cldata[cl].host) == 0)
613 					return ttmp->yes;
614 				ttmp = ttmp->nextt;
615 			    }
616 			/* no match, will never match */
617 			return -1;
618 		    }
619 		else if (cldata[cl].state & A_NOH)
620 			return -1;
621 		else
622 			/* may be later, once we have DNS information */
623 			return 1;
624 	    }
625 	/* fall through, no match, will never match */
626 	return -1;
627 }
628 
629 /* conf_ircd: send the configuration to the ircd daemon */
conf_ircd(void)630 void	conf_ircd(void)
631 {
632 	AnInstance *itmp = instances;
633 	aTarget *ttmp;
634 
635 	sendto_ircd("a");
636 	while (itmp)
637 	    {
638 		if (itmp->address == NULL && itmp->hostname == NULL)
639 			sendto_ircd("A * %s %s", itmp->mod->name,
640 				    (itmp->popt) ? itmp->popt : "");
641 		else
642 		    {
643 			ttmp = itmp->address;
644 			while (ttmp)
645 			    {
646 				sendto_ircd("A %s %s %s", ttmp->value,
647 					    itmp->mod->name,
648 					    (itmp->popt) ? itmp->popt : "");
649 				ttmp = ttmp->nextt;
650 			    }
651 			ttmp = itmp->hostname;
652 			while (ttmp)
653 			    {
654 				sendto_ircd("A %s %s %s", ttmp->value,
655 					    itmp->mod->name,
656 					    (itmp->popt) ? itmp->popt : "");
657 				ttmp = ttmp->nextt;
658 			    }
659 		    }
660 		itmp = itmp->nexti;
661 	    }
662 }
663 
664