/*
* 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 <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#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<userdef> * __users;
static list<ruleset> * __rulesets;
static list<char> * __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<userdef> ** ulist, list<ruleset> ** rlist, list<char> ** 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<userdef>;
__rulesets = new list<ruleset>;
__vhosts = new list<char>;
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<char>;
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 <username> {'\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 <from/to> <address>\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;
}
syntax highlighted by Code2HTML, v. 0.9.1