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