/* * ffproxy (c) 2002-2004 Niklas Olmes * http://faith.eu.org * * $Id: db.c,v 2.1 2004/12/31 08:59:15 niklas Exp $ * * 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. */ #include "configure.h" #ifdef HAVE_SYS_TYPES_H # include #endif #include #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #include #include #include #include #include "cfg.h" #include "print.h" #include "msg.h" #include "alloc.h" #include "file.h" #include "db.h" static void clear_databases(void); static void clear_db(char *[]); static void clear_rdb(regex_t *[]); static void read_db(const char *, char *[]); static void read_rdb(const char *, regex_t *[]); static void read_file(const char *, struct msg *); static void read_config_file(void); static void verify_config(void); #define MAX_E 256 regex_t *a_ip[MAX_E]; regex_t *a_host[MAX_E]; char *a_dyndns[MAX_E]; regex_t *f_host[MAX_E]; regex_t *f_url[MAX_E]; regex_t *f_hdr_drop[MAX_E]; regex_t *f_hdr_match[MAX_E]; char *f_hdr_entry[MAX_E]; char *f_hdr_add[MAX_E]; regex_t *f_rhdr_drop[MAX_E]; regex_t *f_rhdr_match[MAX_E]; char *f_rhdr_entry[MAX_E]; struct msg e_inv; struct msg e_res; struct msg e_con; struct msg e_post; struct msg e_fil; void reload_databases(void) { clear_databases(); load_databases(); } void load_databases(void) { extern struct cfg config; read_config_file(); verify_config(); if (*config.dbdir != '\0' && chdir(config.dbdir) != 0) fatal("could not chdir() to dbdir (%s)", config.dbdir); read_rdb("db/access.ip", a_ip); read_rdb("db/access.host", a_host); read_db("db/access.dyndns", a_dyndns); read_rdb("db/filter.host.match", f_host); read_rdb("db/filter.url.match", f_url); read_rdb("db/filter.header.drop", f_hdr_drop); read_rdb("db/filter.header.match", f_hdr_match); read_db("db/filter.header.entry", f_hdr_entry); read_db("db/filter.header.add", f_hdr_add); read_rdb("db/filter.rheader.drop", f_rhdr_drop); read_rdb("db/filter.rheader.match", f_rhdr_match); read_db("db/filter.rheader.entry", f_rhdr_entry); read_file("html/invalid", &e_inv); read_file("html/resolve", &e_res); read_file("html/connect", &e_con); read_file("html/post", &e_post); read_file("html/filtered", &e_fil); } static void clear_databases(void) { clear_rdb(a_ip); clear_rdb(a_host); clear_db(a_dyndns); clear_rdb(f_host); clear_rdb(f_url); clear_rdb(f_hdr_drop); clear_rdb(f_hdr_match); clear_db(f_hdr_entry); clear_db(f_hdr_add); clear_rdb(f_rhdr_drop); clear_rdb(f_rhdr_match); clear_db(f_rhdr_entry); free(e_inv.c); free(e_res.c); free(e_con.c); free(e_post.c); free(e_fil.c); e_inv.len = e_res.len = e_con.len = e_post.len = e_fil.len = 0; } static void clear_db(char *db[]) { int i; i = 0; while (db[i] != NULL) { free(db[i]); db[i++] = NULL; } } static void clear_rdb(regex_t * r[]) { int i; i = 0; while (r[i] != NULL) { regfree(r[i]); free(r[i]); r[i++] = NULL; } } static void read_db(const char *f, char *db[]) { FILE *fp; char buf[512], *p; size_t i; fp = my_fopen(f); i = 0; while (fgets(buf, sizeof(buf), fp) != NULL && i < MAX_E - 1) { if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n') continue; if ((p = strchr(buf, '\n')) == NULL) { (void) fclose(fp); fatal_n("line too long in file %s", f); } *p = '\0'; p = (char *) my_alloc(strlen(buf) + 1); strcpy(p, buf); db[i++] = p; } (void) fclose(fp); db[i] = NULL; } static void read_rdb(const char *f, regex_t * r[]) { FILE *fp; regex_t *regex; char buf[512], *p; char errbuf[512]; size_t i; int err; fp = my_fopen(f); i = 0; while (fgets(buf, sizeof(buf), fp) != NULL && i < MAX_E - 1) { if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r') continue; if ((p = strchr(buf, '\n')) == NULL) { (void) fclose(fp); fatal_n("line too long in file %s", f); } *p = '\0'; regex = (regex_t *) my_alloc(sizeof(regex_t)); if ((err = regcomp(regex, buf, REG_EXTENDED)) != 0) { (void) regerror(err, regex, errbuf, sizeof(errbuf)); warn("invalid regular expression (%s) in file (%s): %s", buf, f, errbuf); free(regex); continue; } r[i++] = regex; } (void) fclose(fp); r[i] = NULL; } static void read_file(const char *fn, struct msg * m) { int f; char buf[8192]; ssize_t len; f = my_open(fn); len = read(f, &buf, sizeof(buf)); m->c = (char *) my_alloc(len + 1); (void) memcpy(m->c, buf, len); m->c[len] = '\0'; m->len = len; (void) close(f); } #include "dns.h" static void read_config_file(void) { extern struct cfg config; FILE *fp; char obuf[100]; char abuf[100]; char b[300]; if (*config.file == '\0') { ; } else if ((fp = fopen(config.file, "r")) != NULL) { while (fgets(b, sizeof(b), fp) != NULL) { (void) sscanf(b, "%99s %99s", obuf, abuf); if (config.first && strcmp("daemonize", obuf) == 0) { if (strcmp(abuf, "yes") == 0) config.daemon = 1; else config.daemon = 0; continue; } else if (strcmp("child_processes", obuf) == 0) { config.childs = atoi(abuf); continue; } else if (config.first && strcmp("bind_ipv4", obuf) == 0) { if (strcmp(abuf, "yes") == 0) config.bind_ipv4 = 1; else config.bind_ipv4 = 0; continue; } else if (config.first && strcmp("bind_ipv6", obuf) == 0) { if (strcmp(abuf, "yes") == 0) config.bind_ipv6 = 1; else config.bind_ipv6 = 0; continue; } else if (config.first && strcmp("bind_ipv4_host", obuf) == 0) { (void) strncpy(config.ipv4, abuf, sizeof(config.ipv4) - 1); config.ipv4[sizeof(config.ipv4) - 1] = '\0'; continue; } else if (config.first && strcmp("bind_ipv6_host", obuf) == 0) { (void) strncpy(config.ipv6, abuf, sizeof(config.ipv6) - 1); config.ipv6[sizeof(config.ipv6) - 1] = '\0'; continue; } else if (config.first && strcmp("port", obuf) == 0) { config.port = atoi(abuf); continue; } else if (strcmp("use_ipv6", obuf) == 0) { if (strcmp(abuf, "yes") == 0) config.use_ipv6 = 1; else config.use_ipv6 = 0; continue; } else if (config.first && strcmp("uid", obuf) == 0) { if (!(config.uid = atoi(abuf))) { struct passwd *pwd; if ((pwd = getpwnam(abuf))) config.uid = (unsigned long) pwd->pw_uid; else fatal_n("UID %s not found", abuf); } continue; } else if (config.first && strcmp("gid", obuf) == 0) { if (!(config.gid = atoi(abuf))) { struct group *grp; if ((grp = getgrnam(abuf))) config.gid = (unsigned long) grp->gr_gid; else fatal_n("GID %s not found", abuf); } continue; } else if (config.first && strcmp("chroot_dir", obuf) == 0) { (void) strncpy(config.chroot, abuf, sizeof(config.chroot) - 1); config.chroot[sizeof(config.chroot) - 1] = 0; continue; } else if (strcmp("forward_proxy", obuf) == 0) { (void) strncpy(config.proxyhost, abuf, sizeof(config.proxyhost) - 1); config.proxyhost[sizeof(config.proxyhost) - 1] = 0; continue; } else if (strcmp("forward_proxy_port", obuf) == 0) { config.proxyport = atoi(abuf); continue; } else if (strcmp("forward_proxy_ipv6", obuf) == 0) { if (strcmp(abuf, "yes") == 0) config.aux_proxy_ipv6 = 1; else config.aux_proxy_ipv6 = 0; continue; } else if (config.first && strcmp("db_files_path", obuf) == 0) { (void) strncpy(config.dbdir, abuf, sizeof(config.dbdir) - 1); config.dbdir[sizeof(config.dbdir) - 1] = 0; continue; } else if (strcmp("backlog_size", obuf) == 0) { config.backlog = atoi(abuf); continue; } else if (strcmp("use_syslog", obuf) == 0) { if (strcmp(abuf, "yes") == 0) config.syslog = 1; else config.syslog = 0; continue; } else if (strcmp("log_all_requests", obuf) == 0) { if (strcmp(abuf, "yes") == 0) config.logrequests = 1; else config.logrequests = 0; continue; } else if (strcmp("accel_host", obuf) == 0) { (void) strncpy(config.accelhost, abuf, sizeof(config.accelhost) - 1); config.accelhost[sizeof(config.accelhost) - 1] = '\0'; continue; } else if (strcmp("accel_port", obuf) == 0) { config.accelport = atoi(abuf); continue; } else if (strcmp("accel_user_host", obuf) == 0) { if (strcmp(abuf, "yes") == 0) config.accelusrhost = 1; else config.accelusrhost = 0; continue; } else if (strcmp("use_keep_alive", obuf) == 0) { if (strcmp(abuf, "yes") == 0) config.kalive = 1; else config.kalive = 0; continue; } else if (strcmp("unrestricted_connect", obuf) == 0) { if (strcmp(abuf, "yes") == 0) config.unr_con = 1; else config.unr_con = 0; continue; } else if (strcmp("timeout_connect", obuf) == 0) { config.to_con = atoi(abuf); continue; } else if (!config.first) { continue; } else if (*obuf != '#') { warn("unknown option in config file %s: %s", config.file, obuf); continue; } } (void) fclose(fp); } else { if (strcmp(config.file, CFGFILE) == 0) info("default config file (%s) not available, not using config file", CFGFILE); else fatal("unable to open config file %s", config.file); } config.first = 0; } #define ZHWRONG(a, o, v) if(a < 1 || a > v) fatal_n("%s is set < 1 or value is too high (maximum: %d, current: %d)", o, v, a); #define HWRONG(a, o, v) if(a < 0 || a > v) fatal_n("Value of %s is set too high or negative (maximum: %d, current: %d)", o, v, a); #define HUWRONG(a, o, v) if(a > v) fatal_n("Value of %s is set too high (maximum: %d, current: %d)", o, v, a); static void verify_config(void) { extern struct cfg config; HUWRONG(config.port, "port", MAX_PORTS); ZHWRONG(config.childs, "child_processes", MAX_CHILDS); HWRONG(config.backlog, "backlog_size", MAX_BACKLOG); HUWRONG(config.proxyport, "forward_proxy_port", MAX_PORTS); HUWRONG(config.uid, "uid", MAX_UID); HUWRONG(config.gid, "gid", MAX_GID); HUWRONG(config.accelport, "accel_port", MAX_PORTS); if ((config.uid && !config.gid) || (!config.uid && config.gid)) fatal_n("Only one of uid and gid is set to non-zero.\nYou have to use both or none of them"); if (*config.accelhost && config.accelport) config.accel = 1; else config.accel = 0; if (!config.bind_ipv4 && !config.bind_ipv6) fatal_n("Both IPv4 and IPv6 binding disabled. This makes no sense"); }