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.
28 #include "ircd_alloc.h"
29 #include "ircd_chattr.h"
30 #include "ircd_string.h"
45 * stuff that isn't used by s_conf.c anymore
47 #define CONF_ME 0x0040
48 #define CONF_KILL 0x0080
49 #define CONF_ADMIN 0x0100
50 #define CONF_CLASS 0x0400
51 #define CONF_LISTEN_PORT 0x2000
52 #define CONF_IPKILL 0x00010000
53 #define CONF_CRULEALL 0x00200000
54 #define CONF_CRULEAUTO 0x00400000
55 #define CONF_TLINES 0x00800000
57 #define CONF_KLINE (CONF_KILL | CONF_IPKILL)
58 #define CONF_CRULE (CONF_CRULEALL | CONF_CRULEAUTO)
60 /* DEFAULTMAXSENDQLENGTH went into the features subsystem... */
61 #define DEFAULTMAXSENDQLENGTH 40000
64 * For the connect rule patch.. these really should be in a header,
65 * but i see h.h isn't included for some reason.. so they're here.
69 struct CRuleNode* crule_parse(const char* rule);
70 void crule_free(struct CRuleNode** elem);
72 static void new_class(int cn);
73 static char confchar(unsigned int status);
74 static char *getfield(char *newline);
75 static int validate(struct ConfItem *top);
76 static struct ConfItem *chk_initconf(void);
77 static struct ConnectionClass *get_class(int cn, int ism);
79 static int numclasses = 0, *classarr = (int *)NULL, debugflag = 0;
80 static char *chk_configfile = "";
81 static char nullfield[] = "";
82 static char maxsendq[12];
84 /* A few dummy variables and functions needed to link with runmalloc.o */
87 void debug(int level, const char *form, ...)
93 vfprintf(stderr, form, vl);
94 fprintf(stderr, "\n");
98 void sendto_one(struct Client *to, char *pattern, ...)
101 char *rpl_str(int numeric)
106 int main(int argc, char *argv[])
108 const char *dpath = "./";
109 chk_configfile = "ircd.conf";
126 fprintf(stderr, "-d: Missing path\n");
132 if (isdigit(argv[1][2]))
133 debugflag = atoi(&argv[1][2]);
136 fprintf(stderr, "Ignoring unknown option -%c\n", argv[1][1]);
140 chk_configfile = argv[1];
147 fprintf(stderr, "chdir(\"%s\") : %s\n", dpath,
148 (strerror(errno)) ? strerror(errno) : "Unknown error");
151 else if (debugflag > 1)
152 fprintf(stderr, "chdir(\"%s\") : Success", dpath);
156 return validate(chk_initconf());
162 * Read configuration file.
164 * Returns -1, if file cannot be opened
167 static struct ConfItem *chk_initconf(void)
172 struct CRuleNode* crule;
173 int ccount = 0, flags = 0;
174 struct ConfItem *aconf = NULL, *ctop = NULL;
176 fprintf(stderr, "chk_initconf(): ircd.conf = %s\n", chk_configfile);
177 if (NULL == (file = fbopen(chk_configfile, "r")))
183 while (fbgets(line, sizeof(line) - 1, file))
189 MyFree(aconf->passwd);
194 aconf = (struct ConfItem*) MyMalloc(sizeof(struct ConfItem));
198 aconf->passwd = NULL;
200 aconf->conn_class = NULL;
201 aconf->dns_pending = 0;
203 if ((tmp = strchr(line, '\n')))
206 * Do quoting of characters and # detection.
208 for (tmp = line; *tmp; ++tmp) {
210 switch (*(tmp + 1)) {
227 if ('\0' == *(tmp + 1))
230 strcpy(tmp + 1, tmp + 2);
232 else if (*tmp == '#')
235 if (!*line || *line == '#' || *line == '\n' ||
236 *line == ' ' || *line == '\t')
241 fprintf(stderr, "ERROR: Bad config line (%s)\n", line);
246 printf("\n%s\n", line);
249 tmp = getfield(line);
252 fprintf(stderr, "\tERROR: no fields found\n");
256 aconf->status = CONF_ILLEGAL;
260 case 'A': /* Name, e-mail address of administrator */
261 case 'a': /* of this server. */
262 aconf->status = CONF_ADMIN;
264 case 'C': /* Server where I should try to connect */
265 case 'c': /* in case of lp failures */
267 aconf->status = CONF_SERVER;
271 aconf->status = CONF_CRULEALL;
273 /* Connect rule - autos only */
275 aconf->status = CONF_CRULEAUTO;
277 case 'H': /* Hub server line */
279 aconf->status = CONF_HUB;
281 case 'I': /* Just plain normal irc client trying */
282 case 'i': /* to connect me */
283 aconf->status = CONF_CLIENT;
285 case 'K': /* Kill user line on irc.conf */
286 aconf->status = CONF_KILL;
288 case 'k': /* Kill user line based on IP in ircd.conf */
289 aconf->status = CONF_IPKILL;
291 /* Operator. Line should contain at least */
292 /* password and host where connection is */
293 case 'L': /* guaranteed leaf server */
295 aconf->status = CONF_LEAF;
297 /* Me. Host field is name used for this host */
298 /* and port number is the number of the port */
301 aconf->status = CONF_ME;
304 aconf->status = CONF_OPERATOR;
306 /* Local Operator, (limited privs --SRB) */
308 aconf->status = CONF_LOCOP;
310 case 'P': /* listen port line */
312 aconf->status = CONF_LISTEN_PORT;
316 aconf->status = CONF_TLINES;
320 aconf->status = CONF_UWORLD;
324 aconf->status = CONF_CLASS;
327 fprintf(stderr, "\tERROR: unknown conf line letter (%c)\n", *tmp);
331 if (IsIllegal(aconf))
334 for (;;) /* Fake loop, that I can use break here --msa */
336 if ((tmp = getfield(NULL)) == NULL)
338 DupString(aconf->host, tmp);
339 if ((tmp = getfield(NULL)) == NULL)
341 DupString(aconf->passwd, tmp);
342 if ((tmp = getfield(NULL)) == NULL)
344 DupString(aconf->name, tmp);
345 if ((tmp = getfield(NULL)) == NULL)
347 aconf->port = atoi(tmp);
348 if ((tmp = getfield(NULL)) == NULL)
350 if (!(aconf->status & (CONF_CLASS | CONF_ME)))
352 aconf->conn_class = get_class(atoi(tmp), 0);
355 if (aconf->status & CONF_ME)
356 aconf->conn_class = get_class(atoi(tmp), 1);
359 if (!aconf->conn_class && (aconf->status & (CONF_SERVER |
360 CONF_ME | CONF_OPS | CONF_CLIENT)))
362 fprintf(stderr, "\tWARNING: No class. Default 0\n");
363 aconf->conn_class = get_class(0, 0);
366 * If conf line is a class definition, create a class entry
367 * for it and make the conf_line illegal and delete it.
369 if (aconf->status & CONF_CLASS)
373 fprintf(stderr, "\tERROR: no class #\n");
378 fprintf(stderr, "\tWARNING: missing sendq field\n");
379 fprintf(stderr, "\t\t default: %d\n", DEFAULTMAXSENDQLENGTH);
380 sprintf(maxsendq, "%d", DEFAULTMAXSENDQLENGTH);
383 sprintf(maxsendq, "%d", atoi(tmp));
384 new_class(atoi(aconf->host));
385 aconf->conn_class = get_class(atoi(aconf->host), 0);
389 if (aconf->status & CONF_LISTEN_PORT)
392 fprintf(stderr, "\tERROR: %s\n", "null host field in P-line");
393 else if (strchr(aconf->host, '/'))
394 fprintf(stderr, "\t%s\n", "WARNING: / present in P-line "
395 "for non-UNIXPORT configuration");
396 aconf->conn_class = get_class(0, 0);
400 if (aconf->status & CONF_SERVER &&
401 (!aconf->host || strchr(aconf->host, '*') || strchr(aconf->host, '?')))
403 fprintf(stderr, "\tERROR: bad host field\n");
407 if (aconf->status & CONF_SERVER && BadPtr(aconf->passwd))
409 fprintf(stderr, "\tERROR: empty/no password field\n");
413 if (aconf->status & CONF_SERVER && !aconf->name)
415 fprintf(stderr, "\tERROR: bad name field\n");
419 if (aconf->status & (CONF_OPS))
420 if (!strchr(aconf->host, '@'))
423 int len = 3; /* *@\0 = 3 */
425 len += strlen(aconf->host);
426 newhost = (char *)MyMalloc(len);
427 sprintf(newhost, "*@%s", aconf->host);
429 aconf->host = newhost;
432 /* parse the connect rules to detect errors, but free
433 * any allocated storage immediately -- we're just looking
435 if (aconf->status & CONF_CRULE)
436 if ((crule = crule_parse(aconf->name)) != NULL)
439 if (!aconf->conn_class)
440 aconf->conn_class = get_class(0, 0);
441 sprintf(maxsendq, "%d", ConfClass(aconf));
443 if ((aconf->status & CONF_ADMIN) && (!aconf->name ||
444 !aconf->passwd || !aconf->host))
445 fprintf(stderr, "ERROR: Your A: line must have 4 fields!\n");
448 DupString(aconf->name, nullfield);
450 DupString(aconf->passwd, nullfield);
452 DupString(aconf->host, nullfield);
453 if (aconf->status & (CONF_ME | CONF_ADMIN))
455 if (flags & aconf->status)
456 fprintf(stderr, "ERROR: multiple %c-lines\n",
457 ToUpper(confchar(aconf->status)));
459 flags |= aconf->status;
463 printf("(%d) (%s) (%s) (%s) (%u) (%s)\n",
464 aconf->status, aconf->host, aconf->passwd,
465 aconf->name, aconf->port, maxsendq);
467 if (aconf->status & (CONF_SERVER | CONF_HUB | CONF_LEAF))
478 static struct ConnectionClass *get_class(int cn, int ism)
480 static struct ConnectionClass cls;
483 cls.cc_class = (unsigned int)-1;
484 if ((cn >= 1) && (cn <= 64))
487 fprintf(stderr, "\tWARNING: server numeric %d is not 1-64\n", cn);
491 int i = numclasses - 1;
492 cls.cc_class = (unsigned int)-1;
494 if (classarr[i] == cn)
500 fprintf(stderr, "\tWARNING: class %d not found\n", cn);
505 static void new_class(int cn)
509 classarr = (int *)MyRealloc(classarr, sizeof(int) * numclasses);
511 classarr = (int *)MyMalloc(sizeof(int));
512 classarr[numclasses - 1] = cn;
516 * field breakup for ircd.conf file.
518 static char *getfield(char *newline)
520 static char *line = NULL;
529 if ((end = strchr(line, ':')) == NULL)
532 if ((end = strchr(field, '\n')) == NULL)
533 end = field + strlen(field);
541 static int validate(struct ConfItem *top)
543 struct ConfItem *aconf, *bconf;
544 unsigned int otype, valid = 0;
549 for (aconf = top; aconf; aconf = aconf->next)
551 if (aconf->status & CONF_MATCH)
554 if (aconf->status & CONF_SERVER)
558 for (bconf = top; bconf; bconf = bconf->next)
560 if (bconf == aconf || !(bconf->status & otype))
562 if (bconf->conn_class == aconf->conn_class &&
563 0 == ircd_strcmp(bconf->name, aconf->name) &&
564 0 == ircd_strcmp(bconf->host, aconf->host))
566 aconf->status |= CONF_MATCH;
567 bconf->status |= CONF_MATCH;
573 for (bconf = top; bconf; bconf = bconf->next)
575 if ((bconf == aconf) || !(bconf->status & CONF_SERVER))
577 if (0 == ircd_strcmp(bconf->name, aconf->name))
579 aconf->status |= CONF_MATCH;
585 fprintf(stderr, "\n");
586 for (aconf = top; aconf; aconf = aconf->next) {
587 if (aconf->status & CONF_MATCH)
589 else if ('N' != confchar(aconf->status))
590 fprintf(stderr, "Unmatched %c:%s:%s:%s\n",
591 confchar(aconf->status), aconf->host, aconf->passwd, aconf->name);
593 return valid ? 0 : -1;
596 static char confchar(unsigned int status)
598 static char letrs[] = "ICNoOMKARYLPH";
601 status &= ~(CONF_MATCH | CONF_ILLEGAL);
603 for (; *s; s++, status >>= 1)