1 /*
2 * ffproxy (c) 2002-2004 Niklas Olmes <niklas@noxa.de>
3 * http://faith.eu.org
4 *
5 * $Id: db.c,v 2.1 2004/12/31 08:59:15 niklas Exp $
6 *
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 675
19 * Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "configure.h"
23 #ifdef HAVE_SYS_TYPES_H
24 # include <sys/types.h>
25 #endif
26
27 #include <stdio.h>
28 #ifdef HAVE_STDLIB_H
29 # include <stdlib.h>
30 #endif
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 #include <string.h>
35 #include <regex.h>
36 #include <pwd.h>
37 #include <grp.h>
38
39 #include "cfg.h"
40 #include "print.h"
41 #include "msg.h"
42 #include "alloc.h"
43 #include "file.h"
44 #include "db.h"
45
46 static void clear_databases(void);
47 static void clear_db(char *[]);
48 static void clear_rdb(regex_t *[]);
49 static void read_db(const char *, char *[]);
50 static void read_rdb(const char *, regex_t *[]);
51 static void read_file(const char *, struct msg *);
52 static void read_config_file(void);
53 static void verify_config(void);
54
55 #define MAX_E 256
56 regex_t *a_ip[MAX_E];
57 regex_t *a_host[MAX_E];
58 char *a_dyndns[MAX_E];
59 regex_t *f_host[MAX_E];
60 regex_t *f_url[MAX_E];
61 regex_t *f_hdr_drop[MAX_E];
62 regex_t *f_hdr_match[MAX_E];
63 char *f_hdr_entry[MAX_E];
64 char *f_hdr_add[MAX_E];
65 regex_t *f_rhdr_drop[MAX_E];
66 regex_t *f_rhdr_match[MAX_E];
67 char *f_rhdr_entry[MAX_E];
68 struct msg e_inv;
69 struct msg e_res;
70 struct msg e_con;
71 struct msg e_post;
72 struct msg e_fil;
73
74
75 void
reload_databases(void)76 reload_databases(void)
77 {
78 clear_databases();
79 load_databases();
80 }
81
82 void
load_databases(void)83 load_databases(void)
84 {
85 extern struct cfg config;
86
87 read_config_file();
88 verify_config();
89
90 if (*config.dbdir != '\0' && chdir(config.dbdir) != 0)
91 fatal("could not chdir() to dbdir (%s)", config.dbdir);
92
93 read_rdb("db/access.ip", a_ip);
94 read_rdb("db/access.host", a_host);
95 read_db("db/access.dyndns", a_dyndns);
96 read_rdb("db/filter.host.match", f_host);
97 read_rdb("db/filter.url.match", f_url);
98 read_rdb("db/filter.header.drop", f_hdr_drop);
99 read_rdb("db/filter.header.match", f_hdr_match);
100 read_db("db/filter.header.entry", f_hdr_entry);
101 read_db("db/filter.header.add", f_hdr_add);
102 read_rdb("db/filter.rheader.drop", f_rhdr_drop);
103 read_rdb("db/filter.rheader.match", f_rhdr_match);
104 read_db("db/filter.rheader.entry", f_rhdr_entry);
105 read_file("html/invalid", &e_inv);
106 read_file("html/resolve", &e_res);
107 read_file("html/connect", &e_con);
108 read_file("html/post", &e_post);
109 read_file("html/filtered", &e_fil);
110 }
111
112 static void
clear_databases(void)113 clear_databases(void)
114 {
115 clear_rdb(a_ip);
116 clear_rdb(a_host);
117 clear_db(a_dyndns);
118 clear_rdb(f_host);
119 clear_rdb(f_url);
120 clear_rdb(f_hdr_drop);
121 clear_rdb(f_hdr_match);
122 clear_db(f_hdr_entry);
123 clear_db(f_hdr_add);
124 clear_rdb(f_rhdr_drop);
125 clear_rdb(f_rhdr_match);
126 clear_db(f_rhdr_entry);
127 free(e_inv.c);
128 free(e_res.c);
129 free(e_con.c);
130 free(e_post.c);
131 free(e_fil.c);
132 e_inv.len = e_res.len = e_con.len = e_post.len = e_fil.len = 0;
133 }
134
135 static void
clear_db(char * db[])136 clear_db(char *db[])
137 {
138 int i;
139
140 i = 0;
141 while (db[i] != NULL) {
142 free(db[i]);
143 db[i++] = NULL;
144 }
145 }
146
147 static void
clear_rdb(regex_t * r[])148 clear_rdb(regex_t * r[])
149 {
150 int i;
151
152 i = 0;
153 while (r[i] != NULL) {
154 regfree(r[i]);
155 free(r[i]);
156 r[i++] = NULL;
157 }
158 }
159
160 static void
read_db(const char * f,char * db[])161 read_db(const char *f, char *db[])
162 {
163 FILE *fp;
164 char buf[512], *p;
165 size_t i;
166
167 fp = my_fopen(f);
168
169 i = 0;
170 while (fgets(buf, sizeof(buf), fp) != NULL && i < MAX_E - 1) {
171 if (buf[0] == '#' || buf[0] == '\r' || buf[0] == '\n')
172 continue;
173 if ((p = strchr(buf, '\n')) == NULL) {
174 (void) fclose(fp);
175 fatal_n("line too long in file %s", f);
176 }
177 *p = '\0';
178 p = (char *) my_alloc(strlen(buf) + 1);
179 strcpy(p, buf);
180 db[i++] = p;
181 }
182 (void) fclose(fp);
183
184 db[i] = NULL;
185 }
186
187 static void
read_rdb(const char * f,regex_t * r[])188 read_rdb(const char *f, regex_t * r[])
189 {
190 FILE *fp;
191 regex_t *regex;
192 char buf[512], *p;
193 char errbuf[512];
194 size_t i;
195 int err;
196
197 fp = my_fopen(f);
198
199 i = 0;
200 while (fgets(buf, sizeof(buf), fp) != NULL && i < MAX_E - 1) {
201 if (buf[0] == '#' || buf[0] == '\n' || buf[0] == '\r')
202 continue;
203 if ((p = strchr(buf, '\n')) == NULL) {
204 (void) fclose(fp);
205 fatal_n("line too long in file %s", f);
206 }
207 *p = '\0';
208 regex = (regex_t *) my_alloc(sizeof(regex_t));
209 if ((err = regcomp(regex, buf, REG_EXTENDED)) != 0) {
210 (void) regerror(err, regex, errbuf, sizeof(errbuf));
211 warn("invalid regular expression (%s) in file (%s): %s", buf, f, errbuf);
212 free(regex);
213 continue;
214 }
215 r[i++] = regex;
216 }
217 (void) fclose(fp);
218
219 r[i] = NULL;
220 }
221
222 static void
read_file(const char * fn,struct msg * m)223 read_file(const char *fn, struct msg * m)
224 {
225 int f;
226 char buf[8192];
227 ssize_t len;
228
229 f = my_open(fn);
230 len = read(f, &buf, sizeof(buf));
231
232 m->c = (char *) my_alloc(len + 1);
233 (void) memcpy(m->c, buf, len);
234 m->c[len] = '\0';
235 m->len = len;
236
237 (void) close(f);
238 }
239
240 #include "dns.h"
241
242 static void
read_config_file(void)243 read_config_file(void)
244 {
245 extern struct cfg config;
246 FILE *fp;
247 char obuf[100];
248 char abuf[100];
249 char b[300];
250
251 if (*config.file == '\0') {
252 ;
253 } else if ((fp = fopen(config.file, "r")) != NULL) {
254 while (fgets(b, sizeof(b), fp) != NULL) {
255 (void) sscanf(b, "%99s %99s", obuf, abuf);
256 if (config.first && strcmp("daemonize", obuf) == 0) {
257 if (strcmp(abuf, "yes") == 0)
258 config.daemon = 1;
259 else
260 config.daemon = 0;
261 continue;
262 } else if (strcmp("child_processes", obuf) == 0) {
263 config.childs = atoi(abuf);
264 continue;
265 } else if (config.first && strcmp("bind_ipv4", obuf) == 0) {
266 if (strcmp(abuf, "yes") == 0)
267 config.bind_ipv4 = 1;
268 else
269 config.bind_ipv4 = 0;
270 continue;
271 } else if (config.first && strcmp("bind_ipv6", obuf) == 0) {
272 if (strcmp(abuf, "yes") == 0)
273 config.bind_ipv6 = 1;
274 else
275 config.bind_ipv6 = 0;
276 continue;
277 } else if (config.first && strcmp("bind_ipv4_host", obuf) == 0) {
278 (void) strncpy(config.ipv4, abuf, sizeof(config.ipv4) - 1);
279 config.ipv4[sizeof(config.ipv4) - 1] = '\0';
280 continue;
281 } else if (config.first && strcmp("bind_ipv6_host", obuf) == 0) {
282 (void) strncpy(config.ipv6, abuf, sizeof(config.ipv6) - 1);
283 config.ipv6[sizeof(config.ipv6) - 1] = '\0';
284 continue;
285 } else if (config.first && strcmp("port", obuf) == 0) {
286 config.port = atoi(abuf);
287 continue;
288 } else if (strcmp("use_ipv6", obuf) == 0) {
289 if (strcmp(abuf, "yes") == 0)
290 config.use_ipv6 = 1;
291 else
292 config.use_ipv6 = 0;
293 continue;
294 } else if (config.first && strcmp("uid", obuf) == 0) {
295 if (!(config.uid = atoi(abuf))) {
296 struct passwd *pwd;
297 if ((pwd = getpwnam(abuf)))
298 config.uid = (unsigned long) pwd->pw_uid;
299 else
300 fatal_n("UID %s not found", abuf);
301 }
302 continue;
303 } else if (config.first && strcmp("gid", obuf) == 0) {
304 if (!(config.gid = atoi(abuf))) {
305 struct group *grp;
306 if ((grp = getgrnam(abuf)))
307 config.gid = (unsigned long) grp->gr_gid;
308 else
309 fatal_n("GID %s not found", abuf);
310 }
311 continue;
312 } else if (config.first && strcmp("chroot_dir", obuf) == 0) {
313 (void) strncpy(config.chroot, abuf, sizeof(config.chroot) - 1);
314 config.chroot[sizeof(config.chroot) - 1] = 0;
315 continue;
316 } else if (strcmp("forward_proxy", obuf) == 0) {
317 (void) strncpy(config.proxyhost, abuf, sizeof(config.proxyhost) - 1);
318 config.proxyhost[sizeof(config.proxyhost) - 1] = 0;
319 continue;
320 } else if (strcmp("forward_proxy_port", obuf) == 0) {
321 config.proxyport = atoi(abuf);
322 continue;
323 } else if (strcmp("forward_proxy_ipv6", obuf) == 0) {
324 if (strcmp(abuf, "yes") == 0)
325 config.aux_proxy_ipv6 = 1;
326 else
327 config.aux_proxy_ipv6 = 0;
328 continue;
329 } else if (config.first && strcmp("db_files_path", obuf) == 0) {
330 (void) strncpy(config.dbdir, abuf, sizeof(config.dbdir) - 1);
331 config.dbdir[sizeof(config.dbdir) - 1] = 0;
332 continue;
333 } else if (strcmp("backlog_size", obuf) == 0) {
334 config.backlog = atoi(abuf);
335 continue;
336 } else if (strcmp("use_syslog", obuf) == 0) {
337 if (strcmp(abuf, "yes") == 0)
338 config.syslog = 1;
339 else
340 config.syslog = 0;
341 continue;
342 } else if (strcmp("log_all_requests", obuf) == 0) {
343 if (strcmp(abuf, "yes") == 0)
344 config.logrequests = 1;
345 else
346 config.logrequests = 0;
347 continue;
348 } else if (strcmp("accel_host", obuf) == 0) {
349 (void) strncpy(config.accelhost, abuf, sizeof(config.accelhost) - 1);
350 config.accelhost[sizeof(config.accelhost) - 1] = '\0';
351 continue;
352 } else if (strcmp("accel_port", obuf) == 0) {
353 config.accelport = atoi(abuf);
354 continue;
355 } else if (strcmp("accel_user_host", obuf) == 0) {
356 if (strcmp(abuf, "yes") == 0)
357 config.accelusrhost = 1;
358 else
359 config.accelusrhost = 0;
360 continue;
361 } else if (strcmp("use_keep_alive", obuf) == 0) {
362 if (strcmp(abuf, "yes") == 0)
363 config.kalive = 1;
364 else
365 config.kalive = 0;
366 continue;
367 } else if (strcmp("unrestricted_connect", obuf) == 0) {
368 if (strcmp(abuf, "yes") == 0)
369 config.unr_con = 1;
370 else
371 config.unr_con = 0;
372 continue;
373 } else if (strcmp("timeout_connect", obuf) == 0) {
374 config.to_con = atoi(abuf);
375 continue;
376 } else if (!config.first) {
377 continue;
378 } else if (*obuf != '#') {
379 warn("unknown option in config file %s: %s", config.file, obuf);
380 continue;
381 }
382 }
383 (void) fclose(fp);
384 } else {
385 if (strcmp(config.file, CFGFILE) == 0)
386 info("default config file (%s) not available, not using config file", CFGFILE);
387 else
388 fatal("unable to open config file %s", config.file);
389 }
390 config.first = 0;
391 }
392
393 #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);
394 #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);
395 #define HUWRONG(a, o, v) if(a > v) fatal_n("Value of %s is set too high (maximum: %d, current: %d)", o, v, a);
396
397 static void
verify_config(void)398 verify_config(void)
399 {
400 extern struct cfg config;
401
402 HUWRONG(config.port, "port", MAX_PORTS);
403 ZHWRONG(config.childs, "child_processes", MAX_CHILDS);
404 HWRONG(config.backlog, "backlog_size", MAX_BACKLOG);
405 HUWRONG(config.proxyport, "forward_proxy_port", MAX_PORTS);
406 HUWRONG(config.uid, "uid", MAX_UID);
407 HUWRONG(config.gid, "gid", MAX_GID);
408 HUWRONG(config.accelport, "accel_port", MAX_PORTS);
409
410 if ((config.uid && !config.gid) || (!config.uid && config.gid))
411 fatal_n("Only one of uid and gid is set to non-zero.\nYou have to use both or none of them");
412 if (*config.accelhost && config.accelport)
413 config.accel = 1;
414 else
415 config.accel = 0;
416 if (!config.bind_ipv4 && !config.bind_ipv6)
417 fatal_n("Both IPv4 and IPv6 binding disabled. This makes no sense");
418 }
419