/***************************************
This is part of frox: A simple transparent FTP proxy
Copyright (C) 2000 James Hollingshead
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
config.c: configuration file parsing
***** This file was autogenerated by ./configen.pl from
***** configs.tpl and configs.c.in
***** CHANGES TO THIS FILE WILL BE LOST. Please
***** edit configs.tpl or configs.c.in instead
***************************************/
#include <sys/stat.h>
#include <fcntl.h>
#include <netdb.h>
#include <pwd.h>
#include <grp.h>
#include <syslog.h>
#include "common.h"
void usage(int option);
void set_defaults(void);
struct options config;
enum vartype { BOOL, FILENAME, DIRECTRY, STRING, ADDRESS, ADDRPRT, INT, PRTRNGE,
ACL, SUBSECT
};
struct option_array {
const char *name;
enum vartype type;
void *var;
char cmdline;
int reloadable;
int essential;
};
struct option_array opts[] = {
{"", FILENAME,&config.config_file, 'f', FALSE, FALSE},
{"Listen", ADDRESS, &config.listen, '\0', FALSE, FALSE},
{"Port", INT, &config.lport, 'p', FALSE, TRUE },
{"ResolvLoadHack", STRING, &config.resolvhack, '\0', FALSE, FALSE},
{"BindToDevice", STRING, &config.device, '\0', FALSE, FALSE},
{"FromInetd", BOOL, &config.inetd, 'i', FALSE, FALSE},
{"NoDetach", BOOL, &config.nodetach, 'N', FALSE, FALSE},
{"FTPProxy", ADDRPRT, &config.ftpproxy, '\0', TRUE, FALSE},
{"FTPProxyNoPort", BOOL, &config.ftpproxynp, '\0', TRUE, FALSE},
{"ControlPorts", PRTRNGE, &config.contports, '\0', TRUE, FALSE},
{"PassivePorts", PRTRNGE, &config.pasvports, '\0', TRUE, FALSE},
{"ActivePorts", PRTRNGE, &config.actvports, '\0', TRUE, FALSE},
{"Timeout", INT, &config.timeout, '\0', TRUE, FALSE},
{"MaxForks", INT, &config.maxforks, 'm', TRUE, FALSE},
{"MaxForksPerHost", INT, &config.maxforksph, '\0', TRUE, FALSE},
{"MaxTransferRate", INT, &config.maxdlrate, '\0', TRUE, FALSE},
{"CacheDlRate", INT, &config.cachedlrate, '\0', TRUE, FALSE},
{"MaxUploadRate", INT, &config.maxulrate, '\0', TRUE, FALSE},
{"User", STRING, &config.user, '\0', FALSE, TRUE },
{"Group", STRING, &config.group, '\0', FALSE, TRUE },
{"WorkingDir", STRING, &config.chroot, '\0', FALSE, TRUE },
{"DontChroot", BOOL, &config.dontchroot, '\0', FALSE, FALSE},
{"AllowNonAscii", BOOL, &config.nonasciiok, '\0', TRUE, FALSE},
{"BounceDefend", BOOL, &config.bdefend, '\0', TRUE, FALSE},
{"SameAddress", BOOL, &config.sameaddress, '\0', TRUE, FALSE},
{"LogFile", FILENAME,&config.logfile, '\0', FALSE, FALSE},
{"LogLevel", INT, &config.loglevel, 'l', TRUE, FALSE},
{"XferLogging", BOOL, &config.xferlogging, '\0', TRUE, FALSE},
{"PidFile", FILENAME,&config.pidfile, '\0', FALSE, FALSE},
{"APConv", BOOL, &config.apconv, '\0', TRUE, FALSE},
{"PAConv", BOOL, &config.paconv, '\0', TRUE, FALSE},
{"DoNTP", BOOL, &config.ntp, '\0', TRUE, FALSE},
{"NTPAddress", ADDRPRT, &config.ntpdest, '\0', TRUE, FALSE},
{"TcpOutgoingAddr", ADDRESS, &config.tcpoutaddr, '\0', TRUE, FALSE},
{"PASVAddress", ADDRESS, &config.pasvaddress, '\0', TRUE, FALSE},
{"ACL", ACL, &config.acls, '\0', TRUE, FALSE},
{"SubSection", SUBSECT, &config.subsecs, '\0', TRUE, FALSE},
#ifdef TRANS_DATA
{"TransparentData", BOOL, &config.transdata, '\0', FALSE, FALSE},
#endif
#ifdef USE_CACHE
{"CacheModule", STRING, &config.cachemod, '\0', FALSE, FALSE},
{"CacheSize", INT, &config.cachesize, '\0', FALSE, FALSE},
{"HTTPProxy", ADDRPRT, &config.httpproxy, '\0', TRUE, FALSE},
{"ForceHTTP", BOOL, &config.forcehttp, '\0', TRUE, FALSE},
{"MinCacheSize", INT, &config.mincachesize,'\0', TRUE, FALSE},
{"StrictCaching", BOOL, &config.strictcache, '\0', TRUE, FALSE},
{"CacheOnFQDN", BOOL, &config.usefqdn, '\0', TRUE, FALSE},
{"CacheAll", BOOL, &config.cacheall, '\0', TRUE, FALSE},
#endif
#ifdef USE_CCP
{"CCProgram", FILENAME,&config.ccpcmd, '\0', TRUE, FALSE},
{"UseOldCCP", BOOL, &config.oldccp, '\0', TRUE, FALSE},
#endif
#ifdef DO_VSCAN
{"VirusScanner", STRING, &config.vscanner, '\0', TRUE, FALSE},
{"VSOK", INT, &config.vscanok, '\0', TRUE, FALSE},
{"VSProgressMsgs", INT, &config.vscanpm, '\0', TRUE, FALSE},
#endif
#ifdef DO_SSL
{"UseSSL", BOOL, &config.usessl, '\0', TRUE, FALSE},
{"DataSSL", BOOL, &config.datassl, '\0', TRUE, FALSE},
{"AnonSSL", BOOL, &config.anonssl, '\0', TRUE, FALSE},
#endif
{0, 0, 0, 0, 0, 0}
};
void print_config(void);
int name2addr(sstr * str, struct in_addr *addr);
int store_acl(sstr * str, struct acl_list *acls);
int store_subsect(sstr * str, struct subsect_list *list);
int set_opt(struct option_array *opt, sstr * str);
u_int16_t *get_portlist(sstr * str);
int process_opts(void);
int parse_line(sstr * buf);
int match_acl(struct acl_item *acl, struct sockaddr_in *src,
struct sockaddr_in *dst, const char *user);
static char cmdline_set[100] = { 0 };
static int rereading = FALSE;
static int sublevel = 0;
static int line_no;
/* ------------------------------------------------------------- **
** Functions to read / parse the config file.
** ------------------------------------------------------------- */
int process_cmdline(int argc, char *argv[])
{
int i;
struct option_array *opt;
sstr *arg;
char *optp, *argp;
set_defaults();
if (argc <= 1)
return 0;
arg = sstr_init(0);
i = 1;
optp = argv[i] + 1;
while (i < argc) {
if (argv[i][0] != '-')
usage(-1);
opt = opts;
if (*optp == '-')
usage(-1); /*?TODO longopts */
else {
while (opt->name != NULL && opt->cmdline != *optp)
opt++;
if (opt->name == NULL)
usage(*optp);
if (strlen(cmdline_set) < 99)
cmdline_set[strlen(cmdline_set)] = *optp;
if (opt->type == BOOL) {
sstr_cpy2(arg, "yes");
set_opt(opt, arg);
if (*(++optp) == 0) {
i++;
optp = argv[i] + 1;
}
} else {
argp = optp + 1;
if (*argp == 0) {
if (i >= argc - 1 ||
*(argp = argv[++i]) == '-')
usage(*optp);
}
sstr_cpy2(arg, argp);
set_opt(opt, arg);
i++;
optp = argv[i] + 1;
}
}
}
sstr_free(arg);
return (0);
}
/*This is out here as a global so that if config is copied to a backup
location read_config can be called recursively to read a subsection.*/
FILE *fp = NULL;
int read_config()
{
struct option_array *opt;
sstr *buf;
if (!fp) {
if (config.config_file == NULL) fp = fopen(CONFIG_FILE, "r");
else fp = fopen(config.config_file, "r");
if (fp == NULL) return (-1);
line_no=0;
}
buf = sstr_init(0);
while (sstr_fgets(buf, fp) != NULL) {
line_no++;
switch (parse_line(buf)) {
case -1:
sstr_free(buf);
if (sublevel == 0) fclose(fp);
return (-1);
case 0:
break;
case 1: /* end subsection */
sstr_free(buf);
return (0);
}
};
sstr_free(buf);
fclose(fp);
fp = NULL;
opt = opts;
while (opt->name != NULL && !opt->essential)
opt++;
if (opt->name != NULL) {
fprintf(stderr, "Essential option \"%s\" not specified.\n",
opt->name);
return (-1);
}
process_opts();
#ifdef DEBUG
if(!config.inetd) print_config();
#endif
return (0);
}
int parse_line(sstr * buf)
{
struct option_array *opt;
sstr *tok;
tok = sstr_init(0);
if (sstr_getchar(buf, 0) == '#')
return (0);
if (sstr_token(buf, tok, " =\t\r\n", 0) == -1)
return (0);
if (!sstr_casecmp2(tok, "EndSection"))
return (sublevel > 0 ? 1 : -1);
opt = opts;
while (opt->name != NULL && sstr_casecmp2(tok, opt->name))
opt++;
if (opt->name == NULL) {
fprintf(stderr,"Unrecognised option \"%s\" at line %d of %s\n",
sstr_buf(tok), line_no, config.config_file);
return (-1);
}
if (opt->cmdline && strchr(cmdline_set, opt->cmdline)) {
fprintf(stderr,
"\"%s\" specified on the command line: ignored\n",
opt->name);
return (0);
}
if (set_opt(opt, buf) == -1) {
fprintf(stderr, "Invalid argument to %s at line %d of %s\n",
opt->name, line_no, config.config_file);
return (-1);
}
return (0);
}
void usage(int option)
{
if (option != 'h' && option != -1)
fprintf(stderr, "Unknown option %c\n", option);
fprintf(stderr, "Usage frox [-f config_file] [-h]\n");
exit(option == 'h' ? 0 : -1);
}
void set_defaults(void)
{
sstr *tmp;
tmp = sstr_init(0);
config.resolvhack = NULL;
config.device = NULL;
sstr_cpy2(tmp, "ControlPorts 40000-50000");
parse_line(tmp);
sstr_cpy2(tmp, "PassivePorts 40000-50000");
parse_line(tmp);
sstr_cpy2(tmp, "ActivePorts 40000-50000");
parse_line(tmp);
config.timeout = 300;
config.user = NULL;
config.group = NULL;
config.nonasciiok = FALSE;
config.bdefend = TRUE;
config.loglevel = 15;
config.xferlogging = TRUE;
#ifdef TRANS_DATA
#endif
#ifdef USE_CACHE
config.cachemod = NULL;
#endif
#ifdef USE_CCP
config.ccpcmd = NULL;
config.oldccp = TRUE;
#endif
#ifdef DO_VSCAN
config.vscanner = NULL;
config.vscanok = 0;
config.vscanpm = 0;
#endif
#ifdef DO_SSL
config.datassl = TRUE;
config.anonssl = TRUE;
#endif
sstr_free(tmp);
}
/*Any final processing that needs to be done*/
int process_opts(void)
{
if (config.chroot) { /*So that filename stripping works properly */
if (config.chroot[strlen(config.chroot) - 1] == '/')
config.chroot[strlen(config.chroot) - 1] = 0;
}
/* Get uid/gid before we chroot */
if (config.group) {
struct group *grp;
if ((grp = getgrnam(config.group)) == NULL) {
fprintf(stderr, "Unable to find group %s\n",
config.group);
return (-1);
}
config.gid = grp->gr_gid;
}
if (config.user) {
struct passwd *pw;
if ((pw = getpwnam(config.user)) == NULL) {
fprintf(stderr, "Unable to find user %s\n",
config.user);
return (-1);
}
config.uid = pw->pw_uid;
}
config.listen_address.sin_addr = config.listen;
config.listen_address.sin_port = htons(config.lport);
config.listen_address.sin_family = AF_INET;
return (0);
}
int reread_config(void)
{
int i;
struct acl_list acls;
acls = config.acls;
config.acls.num = 0;
config.acls.list = NULL;
rereading = TRUE;
sublevel = 0;
i = read_config();
if (i == -1)
config.acls = acls;
else
free(acls.list);
return (i);
}
int set_opt(struct option_array *opt, sstr * str)
{
sstr *tok;
int sep;
if (rereading && !opt->reloadable)
return (0);
tok = sstr_init(0);
sstr_ncat2(str, "\n", 1); /*For sstr_token */
opt->essential = FALSE;
switch (opt->type) {
case BOOL:
sstr_token(str, tok, " \t\r\n", 0);
if (!sstr_casecmp2(tok, "yes"))
*(int *) opt->var = TRUE;
else if (!sstr_casecmp2(tok, "no"))
*(int *) opt->var = FALSE;
else
return (-1);
break;
case FILENAME:
case STRING:
sstr_token(str, tok, " \t\r\n", SSTR_QTOK);
*(char **) opt->var = strdup(sstr_buf(tok));
break;
case DIRECTRY:
sstr_token(str, tok, " \t\r\n", SSTR_QTOK);
if (sstr_getchar(tok, sstr_len(tok) - 1) != '/')
sstr_ncat2(tok, "/", 1);
*(char **) opt->var = strdup(sstr_buf(tok));
break;
case ADDRESS:
sstr_token(str, tok, " \t\r\n", 0);
return name2addr(tok, (struct in_addr *) opt->var);
break;
case ADDRPRT:
sep = sstr_token(str, tok, " :\t\r\n", 0);
if( name2addr(tok, &((struct sockaddr_in *) opt->var)->sin_addr)==-1)
return(-1);
if (sep == ':')
((struct sockaddr_in *) opt->var)->sin_port
= ntohs(sstr_atoi(str));
((struct sockaddr_in *) opt->var)->sin_family = AF_INET;
break;
case INT:
sstr_token(str, tok, " \t\r\n", 0);
*(int *) opt->var = sstr_atoi(tok);
break;
case PRTRNGE:
sstr_token(str, tok, " \t-,\r\n", 0);
((int *) opt->var)[0] = sstr_atoi(tok);
((int *) opt->var)[1] = sstr_atoi(str);
if(!valid_uint16(((int *) opt->var)[0]) ||
!valid_uint16(((int *) opt->var)[1])) {
fprintf(stderr, "Port out of range\n");
return -1;
}
if(((int *) opt->var)[0] >= ((int *) opt->var)[1]) {
fprintf(stderr, "Port range is inverted\n");
return -1;
}
break;
case ACL:
return store_acl(str, (struct acl_list *) opt->var);
break;
case SUBSECT:
return store_subsect(str, (struct subsect_list *) opt->var);
}
sstr_free(tok);
return (0);
}
int name2addr(sstr * str, struct in_addr *addr)
{
int c;
c = sstr_getchar(str, 0);
if (sstr_len(str) == 1 && c == '*') {
addr->s_addr = INADDR_ANY;
return (0);
}
if (c < '0' || c > '9') {
struct hostent *hostinfo;
hostinfo = gethostbyname(sstr_buf(str));
if (hostinfo == NULL) {
fprintf(stderr, "Unable to resolve host %s\n",
sstr_buf(str));
return (-1);
}
*addr = *((struct in_addr *) *hostinfo->h_addr_list);
} else {
if (inet_aton(sstr_buf(str), addr) == 0)
return (-1);
}
return (0);
}
int addrange_match(struct in_addr addr, char *range)
{
char *s;
if(*range=='*') return TRUE;
else if((s=strchr(range, '/'))) {
struct in_addr a, m;
s = strchr(range, '/');
*s++='\0';
if(inet_aton(range, &a) == 0) {
write_log(ERROR, "Unable to parse ACL. Ignoring.");
return FALSE;
}
if(strchr(s, '.')) {
if (inet_aton(s, &m) == 0) {
write_log(ERROR,
"Unable to parse ACL. Ignoring.");
return FALSE;
}
} else {
int i = atoi(s);
m.s_addr = htonl(0xFFFFFFFF << (32-i));
}
if((addr.s_addr & m.s_addr) == (a.s_addr & m.s_addr))
return TRUE;
else return FALSE;
} else if(*range >= '0' && *range<='9') {
struct in_addr a;
if(inet_aton(range, &a) == 0) {
write_log(ERROR, "Unable to parse ACL. Ignoring.");
return FALSE;
}
if(a.s_addr == addr.s_addr) return TRUE;
else return FALSE;
} else {
struct hostent *hostinfo;
struct in_addr *ap;
int i;
hostinfo = gethostbyname(range);
if (hostinfo == NULL) {
write_log(ERROR, "Unable to resolve host %s in ACL.",
range);
return FALSE;
}
for(i=0;hostinfo->h_addr_list[i];i++){
ap = (struct in_addr *) hostinfo->h_addr_list[i];
if(ap->s_addr == addr.s_addr) return TRUE;
}
return FALSE;
}
}
int store_addressrange(sstr * str, struct in_addr *addr, struct in_addr *msk)
{
sstr *tok;
int sep, i;
tok = sstr_init(0);
sep = sstr_token(str, tok, " /->\r\n", 0);
if(name2addr(tok, addr)==-1) return(-1);
if (sep == '/') {
sep = sstr_token(str, tok, " /->\r\n", 0);
if (sstr_chr(tok, '.')==-1) { /* x.x.x.x/yy */
i = sstr_atoi(tok);
msk->s_addr = htonl(0xFFFFFFFF << (32 - i));
} else
if(name2addr(tok, msk)==-1) return(-1);
} else { /*No mask given */
if (addr->s_addr == INADDR_ANY)
msk->s_addr = INADDR_ANY;
else
msk->s_addr = INADDR_BROADCAST;
}
sstr_free(tok);
return (0);
}
u_int16_t *get_portlist(sstr * str)
{
sstr *tok;
int i = 0, sep;
u_int16_t *ports = NULL;
tok = sstr_init(0);
do {
ports = realloc(ports, (i + 2) * sizeof(u_int16_t));
if(!ports) die(ERROR, "Out of memory reading config file",
0, 0, -1);
sep = sstr_token(str, tok, " \t,-\r\n", 0);
if (sep == -1)
break;
if (!sstr_cmp2(tok, "*")) {
ports[i] = 1;
ports[i + 1] = 0xFFFF;
i += 2;
break;
}
ports[i] = ports[i + 1] = sstr_atoi(tok);
if (sep == '-') {
sep = sstr_token(str, tok, " \t,\n", 0);
if (sep == -1)
ports[i + 1] = 0xFFFF;
else
ports[i + 1] = sstr_atoi(tok);
}
i += 2;
} while (sep != -1);
ports[i] = ports[i + 1] = 0;
sstr_free(tok);
return (ports);
}
void parse_match(sstr *str, struct acl_item *item)
{
sstr *tok;
tok = sstr_init(0);
item->user = NULL;
sstr_token(str, tok, " \t\n", 0);
item->src = strdup(sstr_buf(tok));
sstr_token(str, NULL, " \t\n", 0); /*Removes the " - " from the ACL*/
if(sstr_chr(str, '@')!=-1) {
sstr_token(str, tok, "@", 0);
item->user = strdup(sstr_buf(tok));
config.fakentp = TRUE;
}
sstr_token(str, tok, " \t\n", 0);
item->dst = strdup(sstr_buf(tok));
item->ntp_ports = get_portlist(str);
sstr_free(tok);
}
int store_acl(sstr * str, struct acl_list *acls)
{
sstr *tok;
struct acl_item item;
tok = sstr_init(0);
sstr_token(str, tok, " \t\n", 0);
if (!sstr_casecmp2(tok, "Allow"))
item.action = ALLOW;
else if (!sstr_casecmp2(tok, "Deny"))
item.action = DENY;
else
return (-1);
sstr_free(tok);
parse_match(str, &item);
acls->list = realloc(acls->list,
(acls->num + 1) * sizeof(struct acl_item));
if(!acls->list) return(-1);
memcpy(acls->list + acls->num, &item, sizeof(struct acl_item));
acls->num++;
return (0);
}
/* This is quite horrible, but it does seem to work... We make a
shallow copy of config, and then recall read_config. config will
now be changed with any additional options in the subsection - we
copy it where we want it, and restore config. The copy is only a
shallow one, but we get away with it as other funcs overwrite
pointers not their contents. */
int store_subsect(sstr * str, struct subsect_list *subsecs)
{
struct options tmp;
struct subsect item;
parse_match(str, &item.match);
memcpy(&tmp, &config, sizeof(struct options));
sublevel++;
config.acls.list = NULL;
config.subsecs.list = NULL;
config.acls.num = config.subsecs.num = 0;
if (read_config() == -1)
return (-1);
sublevel--;
if(process_opts()==-1) return(-1);
memcpy(&item.config, &config, sizeof(struct options));
memcpy(&config, &tmp, sizeof(struct options));
subsecs->list = realloc(subsecs->list,
(subsecs->num + 1) * sizeof(struct subsect));
memcpy(subsecs->list + subsecs->num, &item, sizeof(struct subsect));
subsecs->num++;
return (0);
}
/* ------------------------------------------------------------- **
** Alter absolute pathnames to still work after chroot.
** ------------------------------------------------------------- */
void strip_filenames(void)
{
struct option_array *opt = opts;
char *filename;
if (config.chroot == NULL)
return;
do {
if (opt->type != DIRECTRY && opt->type != FILENAME)
continue;
filename = *(char **) opt->var;
if (filename == NULL)
continue;
debug2("stripping %s: ", opt->name);
debug2("%s-->", filename);
if (strncmp(config.chroot, filename, strlen(config.chroot)))
*filename = 0;
else {
memmove(filename, filename + strlen(config.chroot),
strlen(filename) - strlen(config.chroot) + 1);
if(opt->type == DIRECTRY &&
filename[strlen(filename)-1]!='/')
strcat(filename, "/");
}
debug2("%s\n", filename);
} while ((++opt)->name != NULL);
free(config.chroot);
config.chroot="/";
}
/* ------------------------------------------------------------- **
** Functions to return config file options.
** ------------------------------------------------------------- */
int match_acl(struct acl_item *acl, struct sockaddr_in *src,
struct sockaddr_in *dst, const char *user)
{
u_int16_t port;
int i;
char ftpstr[4];
const char *userp;
if(!strcasecmp(user, "anonymous")) {
strcpy(ftpstr, "ftp");
userp=ftpstr;
} else userp = user;
port = ntohs(dst->sin_port);
if (addrange_match(src->sin_addr, acl->src) &&
addrange_match(dst->sin_addr, acl->dst) &&
(!acl->user || !strcasecmp(userp, acl->user))) {
for (i = 0; acl->ntp_ports[i] != 0; i += 2)
if (port >= acl->ntp_ports[i] &&
port <= acl->ntp_ports[i + 1]) {
return (TRUE);
}
if (i == 0)
return (TRUE);
}
return (FALSE);
}
int config_connectionok(struct sockaddr_in *src, struct sockaddr_in *dst,
const char *user)
{
int i;
for (i = 0; i < config.acls.num; i++)
if (match_acl(config.acls.list + i, src, dst, user))
break;
if (i != config.acls.num) {
if (config.acls.list[i].action == ALLOW) {
config_change(src, dst, user);
return (TRUE);
} else
return (FALSE);
}
return (FALSE);
}
void config_change(struct sockaddr_in *src, struct sockaddr_in *dst,
const char *user)
{
int i;
for (i = 0; i < config.subsecs.num; i++)
if (match_acl(&config.subsecs.list[i].match, src, dst, user))
break;
if (i != config.subsecs.num) {
write_log(VERBOSE, "Changing to config file subsection %d", i+1);
memcpy(&config, &config.subsecs.list[i].config, sizeof(config));
}
}
int config_pasvok(struct sockaddr_in *addr)
{
if (addr->sin_addr.s_addr == 0)
return (FALSE);
if (config.sameaddress) {
if (addr->sin_addr.s_addr !=
info->server_control.address.sin_addr.s_addr) {
return (FALSE);
}
}
return (TRUE);
}
int config_portok(struct sockaddr_in *addr)
{
if (addr->sin_addr.s_addr == 0)
return (FALSE);
if (config.sameaddress)
if (addr->sin_addr.s_addr !=
info->client_control.address.sin_addr.s_addr)
return (FALSE);
if (config.bdefend)
if (ntohs(addr->sin_port) < 1024)
return (FALSE);
return (TRUE);
}
#ifdef DEBUG
void print_config(void)
{
struct option_array *opt;
struct subsect *p;
int i, j;
opt = opts;
while (opt->name != NULL) {
switch (opt->type) {
case BOOL:
fprintf(stderr, "%s = %s\n", opt->name,
*(int *) opt->var == TRUE ? "TRUE" : "FALSE");
break;
case FILENAME:
case DIRECTRY:
case STRING:
fprintf(stderr, "%s = %s\n", opt->name,
*(char **) opt->var);
break;
case ADDRESS:
fprintf(stderr, "%s = %s\n", opt->name,
inet_ntoa(*(struct in_addr *) opt->var));
break;
case ADDRPRT:
fprintf(stderr, "%s = %s:%d\n", opt->name,
inet_ntoa(((struct sockaddr_in *) opt->
var)->sin_addr),
htons(((struct sockaddr_in *) opt->var)->
sin_port));
break;
case INT:
fprintf(stderr, "%s = %d\n", opt->name,
*(int *) opt->var);
break;
case PRTRNGE:
fprintf(stderr, "%s = %d-%d\n", opt->name,
((int *) opt->var)[0], ((int *) opt->var)[1]);
break;
case ACL:
case SUBSECT:
break;
}
opt++;
}
for (i = 0; i < config.acls.num; i++) {
fprintf(stderr, "ACL: %s", config.acls.list[i].src);
fprintf(stderr, " --> %s @ %s",
config.acls.list[i].user ?
config.acls.list[i].user : "*",
config.acls.list[i].dst);
fprintf(stderr, ": %s ",
config.acls.list[i].action == DENY ? "DENY" : "ALLOW");
for (j = 0; config.acls.list[i].ntp_ports[j] != 0; j += 2) {
fprintf(stderr, "%d-%d,",
config.acls.list[i].ntp_ports[j],
config.acls.list[i].ntp_ports[j + 1]);
}
fprintf(stderr, "\n");
}
for (i = 0; i < config.subsecs.num; i++) {
struct options tmp;
p = config.subsecs.list + i;
fprintf(stderr, "Subsection: %s", p->match.src);
fprintf(stderr, " --> %s @ %s",
p->match.user ? p->match.user : "*",
p->match.dst);
for (j = 0; p->match.ntp_ports[j] != 0; j += 2) {
fprintf(stderr, "%d-%d,", p->match.ntp_ports[j],
p->match.ntp_ports[j + 1]);
}
fprintf(stderr, " {\n");
memcpy(&tmp, &config, sizeof(struct options));
memcpy(&config, &p->config, sizeof(struct options));
print_config();
memcpy(&config, &tmp, sizeof(struct options));
fprintf(stderr, "}\n");
}
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1