2 * IRC - Internet Relay Chat, ircd/chkconf.c
3 * Copyright (C) 1993 Darren Reed
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)
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.
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.
26 #include "ircd_alloc.h"
27 #include "ircd_chattr.h"
28 #include "ircd_string.h"
44 * For the connect rule patch.. these really should be in a header,
45 * but i see h.h isn't included for some reason.. so they're here.
47 char *crule_parse(char *rule);
48 void crule_free(char **elem);
50 static void new_class(int cn);
51 static char confchar(unsigned int status);
52 static char *getfield(char *newline);
53 static int validate(struct ConfItem *top);
54 static struct ConfItem *chk_initconf(void);
55 static struct ConfClass *get_class(int cn, int ism);
57 static int numclasses = 0, *classarr = (int *)NULL, debugflag = 0;
58 static char *chk_configfile = CPATH;
59 static char nullfield[] = "";
60 static char maxsendq[12];
62 /* A few dummy variables and functions needed to link with runmalloc.o */
65 void debug(int level, const char *form, ...)
71 vfprintf(stderr, form, vl);
72 fprintf(stderr, "\n");
76 void sendto_one(struct Client *to, char *pattern, ...)
79 char *rpl_str(int numeric)
84 int main(int argc, char *argv[])
86 const char *dpath = DPATH;
87 chk_configfile = "ircd.conf";
104 fprintf(stderr, "-d: Missing path\n");
110 if (isdigit(argv[1][2]))
111 debugflag = atoi(&argv[1][2]);
114 fprintf(stderr, "Ignoring unknown option -%c\n", argv[1][1]);
118 chk_configfile = argv[1];
125 fprintf(stderr, "chdir(\"%s\") : %s\n", dpath, strerror(errno));
128 else if (debugflag > 1)
129 fprintf(stderr, "chdir(\"%s\") : Success", dpath);
133 return validate(chk_initconf());
139 * Read configuration file.
141 * Returns -1, if file cannot be opened
144 static struct ConfItem *chk_initconf(void)
147 char line[512], *tmp, *s, *crule;
148 int ccount = 0, flags = 0;
149 struct ConfItem *aconf = NULL, *ctop = NULL;
151 fprintf(stderr, "chk_initconf(): ircd.conf = %s\n", chk_configfile);
152 if (NULL == (file = fbopen(chk_configfile, "r")))
158 while (fbgets(line, sizeof(line) - 1, file))
164 MyFree(aconf->passwd);
169 aconf = (struct ConfItem*) MyMalloc(sizeof(struct ConfItem));
173 aconf->passwd = NULL;
175 aconf->confClass = NULL;
176 aconf->dns_pending = 0;
178 if ((tmp = strchr(line, '\n')))
181 * Do quoting of characters and # detection.
183 for (tmp = line; *tmp; tmp++)
208 for (s = tmp; (*s = *++s);)
212 else if (*tmp == '#')
215 if (!*line || *line == '#' || *line == '\n' ||
216 *line == ' ' || *line == '\t')
221 fprintf(stderr, "ERROR: Bad config line (%s)\n", line);
226 printf("\n%s\n", line);
229 tmp = getfield(line);
232 fprintf(stderr, "\tERROR: no fields found\n");
236 aconf->status = CONF_ILLEGAL;
240 case 'A': /* Name, e-mail address of administrator */
241 case 'a': /* of this server. */
242 aconf->status = CONF_ADMIN;
244 case 'C': /* Server where I should try to connect */
245 case 'c': /* in case of lp failures */
247 aconf->status = CONF_SERVER;
251 aconf->status = CONF_CRULEALL;
253 /* Connect rule - autos only */
255 aconf->status = CONF_CRULEAUTO;
257 case 'H': /* Hub server line */
259 aconf->status = CONF_HUB;
261 case 'I': /* Just plain normal irc client trying */
262 case 'i': /* to connect me */
263 aconf->status = CONF_CLIENT;
265 case 'K': /* Kill user line on irc.conf */
266 aconf->status = CONF_KILL;
268 case 'k': /* Kill user line based on IP in ircd.conf */
269 aconf->status = CONF_IPKILL;
271 /* Operator. Line should contain at least */
272 /* password and host where connection is */
273 case 'L': /* guaranteed leaf server */
275 aconf->status = CONF_LEAF;
277 /* Me. Host field is name used for this host */
278 /* and port number is the number of the port */
281 aconf->status = CONF_ME;
284 aconf->status = CONF_OPERATOR;
286 /* Local Operator, (limited privs --SRB) */
288 aconf->status = CONF_LOCOP;
290 case 'P': /* listen port line */
292 aconf->status = CONF_LISTEN_PORT;
296 aconf->status = CONF_TLINES;
300 aconf->status = CONF_UWORLD;
304 aconf->status = CONF_CLASS;
307 fprintf(stderr, "\tERROR: unknown conf line letter (%c)\n", *tmp);
311 if (IsIllegal(aconf))
314 for (;;) /* Fake loop, that I can use break here --msa */
316 if ((tmp = getfield(NULL)) == NULL)
318 DupString(aconf->host, tmp);
319 if ((tmp = getfield(NULL)) == NULL)
321 DupString(aconf->passwd, tmp);
322 if ((tmp = getfield(NULL)) == NULL)
324 DupString(aconf->name, tmp);
325 if ((tmp = getfield(NULL)) == NULL)
327 aconf->port = atoi(tmp);
328 if ((tmp = getfield(NULL)) == NULL)
330 if (!(aconf->status & (CONF_CLASS | CONF_ME)))
332 aconf->confClass = get_class(atoi(tmp), 0);
335 if (aconf->status & CONF_ME)
336 aconf->confClass = get_class(atoi(tmp), 1);
339 if (!aconf->confClass && (aconf->status & (CONF_SERVER |
340 CONF_ME | CONF_OPS | CONF_CLIENT)))
342 fprintf(stderr, "\tWARNING: No class. Default 0\n");
343 aconf->confClass = get_class(0, 0);
346 * If conf line is a class definition, create a class entry
347 * for it and make the conf_line illegal and delete it.
349 if (aconf->status & CONF_CLASS)
353 fprintf(stderr, "\tERROR: no class #\n");
358 fprintf(stderr, "\tWARNING: missing sendq field\n");
359 fprintf(stderr, "\t\t default: %d\n", DEFAULTMAXSENDQLENGTH);
360 sprintf(maxsendq, "%d", DEFAULTMAXSENDQLENGTH);
363 sprintf(maxsendq, "%d", atoi(tmp));
364 new_class(atoi(aconf->host));
365 aconf->confClass = get_class(atoi(aconf->host), 0);
369 if (aconf->status & CONF_LISTEN_PORT)
372 fprintf(stderr, "\tERROR: %s\n", "null host field in P-line");
373 else if (strchr(aconf->host, '/'))
374 fprintf(stderr, "\t%s\n", "WARNING: / present in P-line "
375 "for non-UNIXPORT configuration");
376 aconf->confClass = get_class(0, 0);
380 if (aconf->status & CONF_SERVER &&
381 (!aconf->host || strchr(aconf->host, '*') || strchr(aconf->host, '?')))
383 fprintf(stderr, "\tERROR: bad host field\n");
387 if (aconf->status & CONF_SERVER && BadPtr(aconf->passwd))
389 fprintf(stderr, "\tERROR: empty/no password field\n");
393 if (aconf->status & CONF_SERVER && !aconf->name)
395 fprintf(stderr, "\tERROR: bad name field\n");
399 if (aconf->status & (CONF_OPS))
400 if (!strchr(aconf->host, '@'))
403 int len = 3; /* *@\0 = 3 */
405 len += strlen(aconf->host);
406 newhost = (char *)MyMalloc(len);
407 sprintf(newhost, "*@%s", aconf->host);
409 aconf->host = newhost;
412 /* parse the connect rules to detect errors, but free
413 * any allocated storage immediately -- we're just looking
415 if (aconf->status & CONF_CRULE)
416 if ((crule = (char *)crule_parse(aconf->name)) != NULL)
419 if (!aconf->confClass)
420 aconf->confClass = get_class(0, 0);
421 sprintf(maxsendq, "%d", ConfClass(aconf));
423 if ((aconf->status & CONF_ADMIN) && (!aconf->name ||
424 !aconf->passwd || !aconf->host))
425 fprintf(stderr, "ERROR: Your A: line must have 4 fields!\n");
428 DupString(aconf->name, nullfield);
430 DupString(aconf->passwd, nullfield);
432 DupString(aconf->host, nullfield);
433 if (aconf->status & (CONF_ME | CONF_ADMIN))
435 if (flags & aconf->status)
436 fprintf(stderr, "ERROR: multiple %c-lines\n",
437 ToUpper(confchar(aconf->status)));
439 flags |= aconf->status;
443 printf("(%d) (%s) (%s) (%s) (%u) (%s)\n",
444 aconf->status, aconf->host, aconf->passwd,
445 aconf->name, aconf->port, maxsendq);
447 if (aconf->status & (CONF_SERVER | CONF_HUB | CONF_LEAF))
458 static struct ConfClass *get_class(int cn, int ism)
460 static struct ConfClass cls;
463 cls.conClass = (unsigned int)-1;
464 if ((cn >= 1) && (cn <= 64))
467 fprintf(stderr, "\tWARNING: server numeric %d is not 1-64\n", cn);
471 int i = numclasses - 1;
472 cls.conClass = (unsigned int)-1;
474 if (classarr[i] == cn)
480 fprintf(stderr, "\tWARNING: class %d not found\n", cn);
485 static void new_class(int cn)
489 classarr = (int *)MyRealloc(classarr, sizeof(int) * numclasses);
491 classarr = (int *)MyMalloc(sizeof(int));
492 classarr[numclasses - 1] = cn;
496 * field breakup for ircd.conf file.
498 static char *getfield(char *newline)
500 static char *line = NULL;
509 if ((end = strchr(line, ':')) == NULL)
512 if ((end = strchr(field, '\n')) == NULL)
513 end = field + strlen(field);
521 static int validate(struct ConfItem *top)
523 struct ConfItem *aconf, *bconf;
524 unsigned int otype, valid = 0;
529 for (aconf = top; aconf; aconf = aconf->next)
531 if (aconf->status & CONF_MATCH)
534 if (aconf->status & CONF_SERVER)
538 for (bconf = top; bconf; bconf = bconf->next)
540 if (bconf == aconf || !(bconf->status & otype))
542 if (bconf->confClass == aconf->confClass &&
543 0 == ircd_strcmp(bconf->name, aconf->name) &&
544 0 == ircd_strcmp(bconf->host, aconf->host))
546 aconf->status |= CONF_MATCH;
547 bconf->status |= CONF_MATCH;
553 for (bconf = top; bconf; bconf = bconf->next)
555 if ((bconf == aconf) || !(bconf->status & CONF_SERVER))
557 if (0 == ircd_strcmp(bconf->name, aconf->name))
559 aconf->status |= CONF_MATCH;
565 fprintf(stderr, "\n");
566 for (aconf = top; aconf; aconf = aconf->next) {
567 if (aconf->status & CONF_MATCH)
569 else if ('N' != confchar(aconf->status))
570 fprintf(stderr, "Unmatched %c:%s:%s:%s\n",
571 confchar(aconf->status), aconf->host, aconf->passwd, aconf->name);
573 return valid ? 0 : -1;
576 static char confchar(unsigned int status)
578 static char letrs[] = "ICNoOMKARYLPH";
581 status &= ~(CONF_MATCH | CONF_ILLEGAL);
583 for (; *s; s++, status >>= 1)