/* * config.cpp * * (C) 1998-2002 Murat Deligonul * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * ---- * does: * Parsing configuration file, loading options to various data structures * rulesets, etc. */ #include "autoconf.h" #include #include #include #include #include #include #include #include #include #ifdef HAVE_FCNTL_H #include #endif #include "config.h" #include "ruleset.h" #include "general.h" #include "dynbuff.h" #include "ezbounce.h" #include "debug.h" #include "hash.h" struct config_symbol { const char * symbol; int id; int flags; }; class cfghash : public __htbl { public: cfghash(int buckets) : __htbl(buckets) { } int insert(const struct config_symbol * ); const struct config_symbol * lookup(const char *); }; /* store the config hash stats */ struct __htbl::hash_stat_t cfght; /* temp lists: */ static list * __users; static list * __rulesets; static list * __vhosts; static proxy_options * __popt; static cfghash * chash; /* Additional Constants -- flags for symbol table */ enum { MATCH_GLOBAL = 0x8, MATCH_USER = 0x10, NEED_ARG = 0x20, NEED_2ARG = 0x40, PROXY_OPTION = 0x80, USER_OPTION = 0x100 }; /* Additional IDs for symbols */ enum { CFG_CMD_SET = 0x100000, CFG_CMD_LISTEN, CFG_CMD_ALLOW, CFG_CMD_DENY, CFG_CMD_USER, CFG_CMD_VHOSTS, CFG_CMD_SSL_LISTEN, LOGFILE, PIDFILE, MOTD_FILE, DCC_LISTEN_PORT_RANGE, LOG_DIR, MAX_DNS_WAIT_TIME, USERFILE, MAX_REGISTER_TIME, MAX_FAILED_PASSWORDS, MAX_FAILED_ADMINS, LISTEN_VHOST, MAX_SOCKETS, MAX_BUFFER_SIZE, MIN_BUFFER_SIZE, CERTFILE, ID_SILENT_REJECTION, ID_NO_REVERSE_LOOKUPS, ID_PREVENT_SELF_CONNECTS, ID_KILL_WHEN_FULL }; static const struct config_symbol symtab[] = { {"SET", CFG_CMD_SET, MATCH_GLOBAL | MATCH_USER | NEED_2ARG}, {"LISTEN", CFG_CMD_LISTEN, MATCH_GLOBAL | NEED_ARG}, {"SSL-LISTEN", CFG_CMD_SSL_LISTEN, MATCH_GLOBAL | NEED_ARG}, {"ALLOW", CFG_CMD_ALLOW, MATCH_USER}, {"DENY", CFG_CMD_DENY, MATCH_GLOBAL | MATCH_USER}, {"USER", CFG_CMD_USER, MATCH_GLOBAL | NEED_ARG}, {"VHOSTS", CFG_CMD_VHOSTS, MATCH_GLOBAL | MATCH_USER}, /* variables - proxy-only settings: */ { "LOGFILE", LOGFILE, PROXY_OPTION}, { "MOTDFILE", MOTD_FILE, PROXY_OPTION}, { "PIDFILE", PIDFILE, PROXY_OPTION}, { "CERTFILE", CERTFILE, PROXY_OPTION}, { "USERFILE", USERFILE, PROXY_OPTION}, { "LOG-FILE", LOGFILE, PROXY_OPTION}, { "MOTD-FILE", MOTD_FILE, PROXY_OPTION}, { "PID-FILE", PIDFILE, PROXY_OPTION}, { "CERT-FILE", CERTFILE, PROXY_OPTION}, { "USER-FILE", USERFILE, PROXY_OPTION}, { "LOG-DIR", LOG_DIR, PROXY_OPTION}, { "NO-REVERSE-LOOKUPS", ID_NO_REVERSE_LOOKUPS, PROXY_OPTION}, { "DCC-LISTEN-PORT-RANGE", DCC_LISTEN_PORT_RANGE, PROXY_OPTION}, { "MIN-BUFFER-SIZE", MIN_BUFFER_SIZE, PROXY_OPTION}, { "MAX-BUFFER-SIZE", MAX_BUFFER_SIZE, PROXY_OPTION}, { "PREVENT-SELF-CONNECTS", ID_PREVENT_SELF_CONNECTS, PROXY_OPTION}, { "MAX-DNS-WAIT-TIME", MAX_DNS_WAIT_TIME, PROXY_OPTION}, { "KILL-ON-FULL-QUEUE", ID_KILL_WHEN_FULL, PROXY_OPTION}, { "MAX-REGISTRATION-TIME", MAX_REGISTER_TIME, PROXY_OPTION}, { "MAX-FAILED-PASSWORDS", MAX_FAILED_PASSWORDS, PROXY_OPTION}, { "SILENT-REJECTION", ID_SILENT_REJECTION, PROXY_OPTION}, { "LISTEN-VHOST", LISTEN_VHOST, PROXY_OPTION}, { "MAX-SOCKETS", MAX_SOCKETS, PROXY_OPTION}, /* User configurable */ { "PASSWORD", OPT_PASSWORD, USER_OPTION}, { "MAX-IDLE-TIME", OPT_MAX_IDLE_TIME, USER_OPTION}, { "DROP-ON-DISCONNECT", OPT_DROP_ON_DISCONNECT, USER_OPTION}, { "ENABLE-DETACH-COMMAND", OPT_ENABLE_DETACH_COMMAND, USER_OPTION}, { "ENABLE-AUTO-DETACH", OPT_ENABLE_AUTO_DETACH, USER_OPTION}, { "ENABLE-VHOST-COMMAND", OPT_ENABLE_VHOST_COMMAND, USER_OPTION}, { "ENABLE-FAKE-IDENTS", OPT_ENABLE_FAKE_IDENTS, USER_OPTION}, { "AUTO-FAKE-IDENTS", OPT_AUTO_FAKE_IDENT, USER_OPTION}, { "AUTO-SERVER", OPT_AUTOSERVER, USER_OPTION}, { "ENABLE-OUTGOING-DCC-PROXYING", OPT_ENABLE_OUTGOING_DCC_PROXYING, USER_OPTION}, { "ENABLE-INCOMING-DCC-PROXYING", OPT_ENABLE_INCOMING_DCC_PROXYING, USER_OPTION}, { "IS-ADMIN", OPT_USER_IS_ADMIN, USER_OPTION}, { "DEFAULT-VHOST", OPT_DEFAULT_VHOST, USER_OPTION}, /* Logging options */ { "ENABLE-PRIVATE-LOGGING", OPT_ENABLE_PRIVATE_LOGGING, USER_OPTION}, { "ENABLE-PUBLIC-LOGGING", OPT_ENABLE_PUBLIC_LOGGING, USER_OPTION}, { "ENABLE-SEPERATE-LOGGING",OPT_ENABLE_SEPERATE_LOGGING, USER_OPTION}, { "DEFAULT-LOG-OPTIONS", OPT_DEFAULT_LOG_OPTIONS, USER_OPTION}, { "MAX-LOGFILE-SIZE", OPT_MAX_LOGFILE_SIZE, USER_OPTION}, }; /* * default options for a proxy_options structure */ const struct proxy_options default_proxy_options = { 0, /* ports */ 0, /* sslports */ 0, /* dcc_ports */ 0, /* logdir */ 0, /* configfile */ 0, /* logfile */ 0, /* pidfile */ 0, /* certfile */ 0, /* userfile */ 0, /* motdfile */ 30, /* max_register */ 3, /* max_failed_pass */ DEF_MIN_BUFFER_SIZE, /* min. buffer size */ DEF_MAX_BUFFER_SIZE, /* max. buffer size */ DEF_MAX_SOCKETS, /* socket table size */ 10, /* dns look up time out */ KILL_WHEN_FULL | PREVENT_SELF_CONNECTS, /* flags */ {0} /* default interface */ }; static int do_set_command(userdef *, int, char *, char *); static char * strip(char *); static char * remove_trailing(char *); static int grab_block(dynbuff *, dynbuff *, int); static int parse_block(dynbuff * , int , userdef * ); static ruleset * do_ruleset(dynbuff * db, int, char *, u_long); static bool check_config(void); static bool check_user_config(userdef * ); /* Return pointer past leading space and tab chars. * Remove all tabs from line. * If # encountered before anything else, return NULL */ static char * strip(char * c) { if (*c == '#') return 0; while (isspace(*c)) if (*++c == '#') return 0; if (!*c) return 0; char * b = c; while (*b) if (*b++ == '\t') *(b-1) = ' '; return c; } /* Remove whitespace characters from * end of string */ static char * remove_trailing(char * str) { if (!str) return 0; char * p = str + strlen(str); while (isspace(*p)) *p-- = 0; return str; } int load_config_file(const char *file, struct proxy_options * pc, list ** ulist, list ** rlist, list ** vlist) { int fd = open(file, O_RDONLY); struct stat st; dynbuff db(8048, 0); if (fd < 0) return 0; fstat(fd, &st); db.add(fd, st.st_size); close(fd); /* Got the config file in memory * * Init the symbol table */ chash = new cfghash(47); for (unsigned c = 0; c < (sizeof(symtab) / sizeof(struct config_symbol)); c++) chash->insert(&symtab[c]); /* init other globals */ __popt = new proxy_options; __users = new list; __rulesets = new list; __vhosts = new list; memcpy(__popt, &default_proxy_options, sizeof(proxy_options)); if (!parse_block(&db, MATCH_GLOBAL, (userdef *) 0)) { fprintf(stderr, "master parse_block() failed -- aborting\n"); goto error; return -1; } fflush(stderr); printf("Checking config...."); fflush(stdout); if (check_config()) printf("OK\n"); else { error: destroy_list(__users, 0); destroy_list(__rulesets, 0); destroy_list(__vhosts, 1); delete[] __popt->ports; delete[] __popt->sslports; delete[] __popt->dcc_ports; delete[] __popt->logdir; delete[] __popt->logfile; delete[] __popt->configfile; delete[] __popt->pidfile; delete[] __popt->certfile; delete[] __popt->motdfile; delete[] __popt->userfile; delete __users; delete __rulesets; delete __vhosts; delete __popt; delete chash; return -1; } /* copy stuff back */ *ulist = __users; *rlist = __rulesets; *vlist = __vhosts; memcpy(pc, __popt, sizeof(struct proxy_options)); pc->configfile = my_strdup(file); /* get hash table stats so we can look at them later */ memset(&cfght, 0, sizeof(cfght)); chash->stat(&cfght); delete chash; delete __popt; return 1; } /* NOTE: will not tell how many lines if returns an * error. We'll have to use a pointer argument, perhaps * for curline itself. However, since error conditions stop * the parsing altogether, this issue does not matter right * now ..... */ int grab_block(dynbuff * src, dynbuff * target, int curline) { char line[256]; int num_O = 0, num_C =0; int __curline = 0; while (src->copy_line(curline++, line, sizeof(line), 1, 0) != -1) { __curline++; char * p = strip(line); remove_trailing(p); bool add = 0; if (!p) continue; if (*p == '{') { if (++num_O > 1) add = 1; } else if (*p == '}') { if (!num_O) return 0; /* } before { -- invalid */ if (++num_C != num_O) add = 1; } else { /* couldn't find a {. It could be a "xxx {" type of construct. * Make sure it is such a thing and not a { character in a * set command for example. */ char * n = strchr(p, '{'); if (!n) { if (!num_O && __curline != 1) return 0; else if (num_O) add = 1; } else { if (!num_O) num_O++; else { /* { found, and it's not the first one we were looking * for.. make sure its not part of set command or whatever */ if (isspace(*(n-1)) && (isspace(*(n+1)) || *(n+1) == 0)) num_O++; add = 1; } } } if (add) { target->add(line); target->add("\n"); } if (num_O == num_C && num_O) return curline; } return -1; /* premature end */ } /* * Parse a block. A block is considered a section of commands * between { } braces (not including the braces). * * Return 0 or 1 (fail or success) */ int parse_block(dynbuff * db, int flags, userdef * user) { char buff[256], cmd[64]; int line = 0; while (db->copy_line(line++, buff, sizeof(buff), 1, 0) != -1) { char * p = strip(buff); char arg2[64] = "", arg3[64] = ""; const struct config_symbol * csym = 0; if ( !p /* comment .. */ || !gettok(p, cmd, sizeof(cmd), ' ', 1)) /* blank line.. */ continue; ToUpper(cmd); csym = chash->lookup(cmd); gettok(p, arg2, sizeof(arg2), ' ', 2); gettok(p, arg3, sizeof(arg3), ' ', 3); if (!csym) { fprintf(stderr, "*** error: %d: invalid command '%s'\n", line, cmd); return 0; } if ((csym->flags & NEED_ARG) && !*arg2) { fprintf(stderr, "*** error: %d: command '%s' needs a parameter\n", line, cmd); return 0; } if ((csym->flags & NEED_2ARG) && !*arg3) { fprintf(stderr, "*** error: %d: command '%s %s' needs an additional parameter\n", line, cmd, arg2); abort(); return 0; } if ((flags & MATCH_USER) && !(csym->flags & MATCH_USER)) { fprintf(stderr, "*** error: %d: command '%s' is not valid in a user definition block\n", line,cmd); return 0; } /* iff MATCH_GLOBAL is set */ if (!(flags & MATCH_USER) && !(csym->flags & MATCH_GLOBAL)) { fprintf(stderr, "*** error: %d: command '%s' is only valid in user block\n", line,cmd); return 0; } switch (csym->id) { case CFG_CMD_LISTEN: if (!__popt->ports) __popt->ports = my_strdup(arg2); else fprintf(stderr,"*** warning: %d: ignoring `listen' command: ports were already set!\n", line); break; case CFG_CMD_SSL_LISTEN: if (!__popt->sslports) __popt->sslports = my_strdup(arg2); else fprintf(stderr,"*** warning: %d: ignoring `ssl-listen' command: ports were already set!\n", line); break; case CFG_CMD_DENY: case CFG_CMD_ALLOW: { int r; dynbuff n(512, 0); r = grab_block(db, &n, line-1); switch (r) { case 0: case -1: fprintf(stderr, "*** error: %d: Parse Error in deny/allow block (ended prematurely?)\n", line); return 0; default: { ruleset * rs; char reason[100]; DEBUG("parse_block(): creating new allow/deny block\n"); rs = do_ruleset(&n, csym->id, reason, sizeof(reason)); if (!rs) { fprintf(stderr, "*** error: %d: Unable to create ruleset: %s\n", line, reason); return 0; } if (user) user->rulesets->add(rs); else __rulesets->add(rs); } } line = r; break; } case CFG_CMD_SET: DEBUG("Encountered set option %s %s\n", arg2, arg3); switch(do_set_command(user, flags, arg2, arg3)) { case 0: fprintf(stderr, "*** error: %d: Cannot set `%s': unknown variable\n", line, arg2); return 0; case -3: fprintf(stderr, "*** error: %d: Cannot set `%s': bad value '%s' (possible error: %s)\n", line, arg2, arg3, strerror(errno)); return 0; case -2: fprintf(stderr, "*** error: %d: Cannot set `%s': must be set *inside* `user xxx {...}' block\n", line, arg2); return 0; case -1: fprintf(stderr, "*** error: %d: Cannot set `%s': must be set *outside* `user xxx {...}' block\n", line, arg2); return 0; } break; case CFG_CMD_VHOSTS: { int r; dynbuff n(512, 0); r = grab_block(db, &n, line-1); switch (r) { case 0: case -1: fprintf(stderr, "*** error: %d: Parse Error in vhost block (ended prematurely?)\n", line); return 0; default: { DEBUG("parse_block(): create new vhost block\n"); char buff2[200]; int line2 = 0; while (n.copy_line(line2++, buff2, sizeof(buff2), 1, 0) != -1) { DEBUG("parse_block(): vhost: got %s\n", buff2); if (user) { if (!user->vhosts) user->vhosts = new list; user->vhosts->add(my_strdup(strip(buff2))); } else __vhosts->add(my_strdup(strip(buff2))); } } } line = r; break; } case CFG_CMD_USER: { dynbuff n(2048,0); int r; userdef * u; DEBUG("parse_block(): creating new user block\n"); if (arg2[0] == '{') { fprintf(stderr, "*** error: %d: user block must in the form: `user {'\n", line); return 0; } if (userdef::find(__users, arg2)) { fprintf(stderr, "*** error: %d: user `%s' already defined!\n", line, arg2); return 0; } r = grab_block(db, &n, line-1); if (!r) { fprintf(stderr, "*** error: %d: Unable to grab block after `user' statement\n", line); return 0; } u = new userdef(arg2); if (!parse_block(&n, flags | MATCH_USER, u)) { fprintf(stderr, "*** error: %d: Error parsing `user' command block at line %d\n", line, line); delete u; return 0; } __users->add(u); line = r; DEBUG("parse_block(): ...parsed successfully\n"); break; } } } /* Check that the user created is valid: */ if (user) { if (!check_user_config(user)) { fprintf(stderr, "*** error: %d: Error(s) creating user `%s'\n", line, user->name); /* delete user; -- we do this elsewhere */ return 0; } struct in_addr in = { user->cfg.get(PREF_VHOST) }; printf("---> Created user `%s'\n", user->name); printf(" |---> Password: %s\n", user->cfg.get(OPT_PASSWORD, 0)); printf(" |---> Default VHost: %s\n", inet_ntoa(in)); printf(" |---> Admin: %s\n", user->cfg.checkf(OPT_USER_IS_ADMIN) ? "yes" : "no"); printf(" \\---> Detachable: %s\n", user->cfg.checkf(OPT_ENABLE_DETACH_COMMAND) ? "yes" : "no"); } return 1; } /* * Return: * 1 - Success * -1 - Failed: not a user option * -2 - Failed: not a proxy option * -3 - Failed: illegal value * 0: other error (command not found) */ int do_set_command(userdef * user, int flags, char * var, char * arg) { const struct config_symbol * c; ToUpper(var); c = chash->lookup(var); /* Check that this is a valid command, and that we don't match any other * non-set crap in the symbol table */ if ((!c) || (!(c->flags & PROXY_OPTION) && !(c->flags & USER_OPTION))) return 0; /* there should not be a 'user' to set this option */ if ((c->flags & PROXY_OPTION) && user) return -1; if ((c->flags & USER_OPTION) && !user) return -2; int v = atoi(arg); switch (c->id) { /* proxy options: boolean */ case ID_NO_REVERSE_LOOKUPS: case ID_KILL_WHEN_FULL: case ID_PREVENT_SELF_CONNECTS: case ID_SILENT_REJECTION: if (v) __popt->flags |= c->id; else __popt->flags &= ~(c->id); return 1; /* user options: boolean */ case OPT_ENABLE_VHOST_COMMAND: case OPT_ENABLE_DETACH_COMMAND: case OPT_DROP_ON_DISCONNECT: case OPT_ENABLE_FAKE_IDENTS: case OPT_AUTO_FAKE_IDENT: case OPT_ENABLE_OUTGOING_DCC_PROXYING: case OPT_ENABLE_INCOMING_DCC_PROXYING: case OPT_ENABLE_AUTO_DETACH: case OPT_ENABLE_PRIVATE_LOGGING: case OPT_ENABLE_PUBLIC_LOGGING: case OPT_ENABLE_SEPERATE_LOGGING: case OPT_USER_IS_ADMIN: if (v) { user->cfg.setf(c->id); user->cfg.setp(c->id); } else { user->cfg.clearf(c->id); user->cfg.clearp(c->id); } return 1; case OPT_MAX_IDLE_TIME: case OPT_MAX_LOGFILE_SIZE: user->cfg.set(c->id, v); return 1; case OPT_DEFAULT_LOG_OPTIONS: user->cfg.set(c->id, logfile::charflags_to_int(arg)); return 1; /* user options: strings */ case OPT_AUTOSERVER: case OPT_PASSWORD: case OPT_DEFAULT_VHOST: if (!user->cfg.set(c->id, arg)) return -3; return 1; /* proxy options: numeric */ case MAX_SOCKETS: __popt->max_sockets = v; return 1; case MAX_DNS_WAIT_TIME: __popt->max_dns_wait_time = v; return 1; case MAX_BUFFER_SIZE: __popt->max_buffer_size = v; return 1; case MIN_BUFFER_SIZE: __popt->min_buffer_size = v; return 1; case MAX_REGISTER_TIME: __popt->max_register_time = (time_t) v; return 1; case MAX_FAILED_PASSWORDS: __popt->max_failed_passwords = v; return 1; /* Proxy options: string values */ case LOGFILE: __popt->logfile = my_strdup(arg); return 1; case PIDFILE: __popt->pidfile = my_strdup(arg); return 1; case CERTFILE: __popt->certfile = my_strdup(arg); return 1; case USERFILE: __popt->userfile = my_strdup(arg); return 1; case LOG_DIR: __popt->logdir = my_strdup(arg); return 1; case MOTD_FILE: __popt->motdfile = my_strdup(arg); return 1; case DCC_LISTEN_PORT_RANGE: __popt->dcc_ports = my_strdup(arg); return 1; case LISTEN_VHOST: if (fill_in_addr(arg, &__popt->iface_listen) < 1) return -3; return 1; default: break; } return 0; } /* * Return values: * 1 - Success and number of lines in the block * 0 - Minor syntax error or something, but object was still created. * -1 - Error in creating rule set. No rule set created. Reason given in 'reason'. * */ static ruleset * do_ruleset(dynbuff * db, int id, char * reason, u_long reason_max) { char line[256]; unsigned success_tos = 0, success_froms = 0, curline = 0; ruleset * rs = 0; if (id == CFG_CMD_ALLOW) rs = new allowed_ruleset; else if (id == CFG_CMD_DENY) rs = new denied_ruleset; while (db->copy_line(0, line, sizeof(line), 0) != -1) { int num = 0, type = 0, current = 1; char * address = 0, * ports = 0,* ban_reason = 0; char * p = strip(line); extern int mk_ppchar(char * string, char *(*buff)[MAX_PPCHAR_ARGS]); char *argv[MAX_PPCHAR_ARGS]; memset(&argv, 0, sizeof(argv)); curline++; if (!p) continue; mk_ppchar(p, &argv); /* * Get second word first, which can be * 'from' or 'to' or the address depending on if a number was entered * before them. */ if (strcasecmp(argv[2], "from") == 0) type = ruleset::FROM; else if (strcasecmp(argv[2], "to") == 0) type = ruleset::TO; /* Get first word, which will either be the number or the type. */ if (type) { if ((num = atoi(argv[1])) == 0) { fprintf(stderr, "In line: %s\n\t'0' or text entered for number field, using unlimited.\n", argv[0]); num = ruleset::UNLIMITED; } current = 3; } else { if (strcasecmp(argv[1], "from") == 0) type = ruleset::FROM; else if (strcasecmp(argv[1], "to") == 0) type = ruleset::TO; else { fprintf(stderr, "In line: %s\n\tFirst word must be 'from' or 'to'.\n", argv[0]); delete[] argv[0]; continue; } num = ruleset::UNLIMITED; current = 2; } /* Can now get address */ if (!(address = argv[current++])) { fprintf(stderr, "In line: %s\n\tThis line is too short. Minimum requirements are
\n", argv[0]); delete[] argv[0]; continue; } if (type == ruleset::FROM) success_froms++; else success_tos++; /* Optional argument: port. Defaults to 'all'/ Will also handle 'on' (quite messily?) */ if (!argv[current]) { ports = "all"; /* This means we are the last thing.. set a default reason too */ if (id == CFG_CMD_DENY) ban_reason = "No reason was given!"; } else { if (strcasecmp(argv[current], "on") == 0) { ports = argv[++current]; current++; } else /* not a valid port string */ ports = "all"; /* Remaining text is the ban reason. Only useful when id == DENY.*/ if (id == CFG_CMD_DENY) { if (argv[current]) ban_reason = gettok_ptr(argv[0], ' ', current); else ban_reason = "No reason was given!"; } } /* All done w/ this ruleset */ if (type == ruleset::FROM) rs->add_host_from(address, ports, ban_reason, num); else rs->add_host_to(address, ports, ban_reason, num); delete[] argv[0]; // DEBUG("CONFIG: Creating ruleset with address: %s | ports: %s | reason: %s | num %d\n", // address, ports, ban_reason, num); } /* Is it valid rule set? */ if ((id == CFG_CMD_ALLOW) && (success_tos == 0 || success_froms == 0)) { safe_strcpy(reason, "Rule set of type 'allow' must contain at least one 'from' field and one 'to' field.\n", reason_max); delete rs; return 0; } else if (success_tos == 0 && success_froms == 0) { safe_strcpy(reason, "No valid 'from' or 'to' fields found in rule set. Rule set destroyed.\n", reason_max); delete rs; return 0; } /* yes it is valid */ return rs; } static bool check_user_config(userdef * user) { bool err = 0; if (!user->rulesets->size()) { fprintf(stderr, "*** error: user definition `%s' has no allow rulesets\n", user->name); err = 1; } if (user->cfg.checkf(OPT_AUTO_FAKE_IDENT) && !user->cfg.checkf(OPT_ENABLE_FAKE_IDENTS)) { fprintf(stderr,"*** error: user %s: auto-fake-idents set to 1, but enable-fake-idents not set to 1\n", user->name); err = 1; } if (user->cfg.checkf(OPT_ENABLE_AUTO_DETACH) && !user->cfg.checkf(OPT_ENABLE_DETACH_COMMAND)) { fprintf(stderr,"*** error: user %s: enable-auto-detach enabled but detach/reattach commands are not.\n", user->name); err = 1; } if (!user->cfg.get(OPT_PASSWORD, 0)) { fprintf(stderr, "*** error: user %s: must supply a password\n", user->name); err = 1; } if (user->cfg.checkf(OPT_ENABLE_PUBLIC_LOGGING) || user->cfg.checkf(OPT_ENABLE_PRIVATE_LOGGING)) { if (!user->cfg.get(OPT_LOG_OPTIONS)) { fprintf(stderr, "*** warning: user %s: No log options were set: defaulting to log all\n", user->name); user->cfg.set(OPT_LOG_OPTIONS, logfile::LOG_ALL); } } return !err; } static bool check_config(void) { bool err = 0; if (!__users->size()) { fprintf(stderr,"\n*** error: No users defined"); err = 1; } if (!__popt->logfile) { fprintf(stderr, "\n*** error: \"logfile\" variable wasn't set"); err = 1; } if (!__popt->ports && !__popt->sslports) { fprintf(stderr, "\n*** error: No listen ports defined"); err = 1; } #ifdef _USE_SSL if (!__popt->certfile && __popt->sslports) { fprintf(stderr," \n*** error: SSL listen ports set, but no \"certfile\" defined"); err = 1; } #endif if (__popt->max_sockets < 10) { fprintf(stderr,"\n*** error: \"max-sockets\" variable set too low. Must be >= 10"); err = 1; } if (__popt->logdir && access(__popt->logdir, R_OK | W_OK | X_OK)) { fprintf(stderr, "\n*** error: Cannot access log file base dir `%s': %s", __popt->logdir, strerror(errno)); err = 1; } if (__popt->max_buffer_size <= __popt->min_buffer_size) { fprintf(stderr, "\n*** error: \"max-buffer-size\" must be greater than \"min_buffer_size\""); err = 1; } if (err) { fputc('\n', stderr); return 0; } return 1; } int cfghash::insert(const struct config_symbol * c) { int idx = hash(c->symbol) % buckets; list_add(&table[idx], (void *) c); return 1; } const struct config_symbol * cfghash::lookup(const char * str) { int idx = hash(str) % (buckets); struct hashlist * l = &table[idx]; struct node * n; const struct config_symbol * c; lookups++; for (n = l->head; n; n = n->next) { c = (const struct config_symbol *) n->data; if (!strcmp(c->symbol, str)) return hits++, c; } return 0; }