1 /* tinyproxy - A fast light-weight HTTP proxy
2 * Copyright (C) 2004 Robert James Kaes <rjkaes@users.sourceforge.net>
3 * Copyright (C) 2009 Michael Adam <obnox@samba.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 /* Parses the configuration file and sets up the config_s structure for
21 * use by the application. This file replaces the old grammar.y and
22 * scanner.l files. It takes up less space and _I_ think is easier to
23 * add new directives to. Who knows if I'm right though.
24 */
25
26 #include "common.h"
27 #include <limits.h>
28 #include <regex.h>
29 #include "conf.h"
30
31 #include "acl.h"
32 #include "anonymous.h"
33 #include "filter.h"
34 #include "heap.h"
35 #include "html-error.h"
36 #include "log.h"
37 #include "reqs.h"
38 #include "reverse-proxy.h"
39 #include "upstream.h"
40 #include "connect-ports.h"
41 #include "basicauth.h"
42 #include "conf-tokens.h"
43
44 /*
45 * The configuration directives are defined in the structure below. Each
46 * directive requires a regular expression to match against, and a
47 * function to call when the regex is matched.
48 *
49 * Below are defined certain constant regular expression strings that
50 * can (and likely should) be used when building the regex for the
51 * given directive.
52 */
53 #define DIGIT "[0-9]"
54 #define SPACE "[ \t]"
55 #define WS SPACE "+"
56 #define STR "\"([^\"]+)\""
57 #define BOOL "(yes|on|no|off)"
58 #define INT "(()" DIGIT "+)"
59 #define ALNUM "([-a-z0-9._]+)"
60 #define USERNAME "([^:]*)"
61 #define PASSWORD "([^@]*)"
62 #define IP "((([0-9]{1,3})\\.){3}[0-9]{1,3})"
63 #define IPMASK "(" IP "(/" DIGIT "+)?)"
64 #define IPV6 "(" \
65 "(([0-9a-f:]{2,39}))|" \
66 "(([0-9a-f:]{0,29}:" IP "))" \
67 ")"
68
69 #define IPV6MASK "(" IPV6 "(/" DIGIT "+)?)"
70 #define BEGIN "^" SPACE "*"
71 #define END SPACE "*$"
72
73 /*
74 * Limit the maximum number of substring matches to a reasonably high
75 * number. Given the usual structure of the configuration file, sixteen
76 * substring matches should be plenty.
77 */
78 #define RE_MAX_MATCHES 24
79
80 #define CP_WARN(FMT, ...) \
81 log_message (LOG_WARNING, "line %lu: " FMT, lineno, __VA_ARGS__)
82
83 /*
84 * All configuration handling functions are REQUIRED to be defined
85 * with the same function template as below.
86 */
87 typedef int (*CONFFILE_HANDLER) (struct config_s *, const char *,
88 unsigned long, regmatch_t[]);
89
90 /*
91 * Define the pattern used by any directive handling function. The
92 * following arguments are defined:
93 *
94 * struct config_s* conf pointer to the current configuration structure
95 * const char* line full line matched by the regular expression
96 * regmatch_t match[] offsets to the substrings matched
97 *
98 * The handling function must return 0 if the directive was processed
99 * properly. Any errors are reported by returning a non-zero value.
100 */
101 #define HANDLE_FUNC(func) \
102 int func(struct config_s* conf, const char* line, \
103 unsigned long lineno, regmatch_t match[])
104
105 /*
106 * List all the handling functions. These are defined later, but they need
107 * to be in-scope before the big structure below.
108 */
HANDLE_FUNC(handle_disabled_feature)109 static HANDLE_FUNC (handle_disabled_feature)
110 {
111 fprintf (stderr, "ERROR: accessing feature that was disabled at compiletime on line %lu\n",
112 lineno);
113
114 return -1;
115 }
116
117 static HANDLE_FUNC (handle_allow);
118 static HANDLE_FUNC (handle_basicauth);
119 static HANDLE_FUNC (handle_anonymous);
120 static HANDLE_FUNC (handle_bind);
121 static HANDLE_FUNC (handle_bindsame);
122 static HANDLE_FUNC (handle_connectport);
123 static HANDLE_FUNC (handle_defaulterrorfile);
124 static HANDLE_FUNC (handle_deny);
125 static HANDLE_FUNC (handle_errorfile);
126 static HANDLE_FUNC (handle_addheader);
127 #ifdef FILTER_ENABLE
128 static HANDLE_FUNC (handle_filter);
129 static HANDLE_FUNC (handle_filtercasesensitive);
130 static HANDLE_FUNC (handle_filterdefaultdeny);
131 static HANDLE_FUNC (handle_filterextended);
132 static HANDLE_FUNC (handle_filterurls);
133 #endif
134 static HANDLE_FUNC (handle_group);
135 static HANDLE_FUNC (handle_listen);
136 static HANDLE_FUNC (handle_logfile);
137 static HANDLE_FUNC (handle_loglevel);
138 static HANDLE_FUNC (handle_maxclients);
139 static HANDLE_FUNC (handle_obsolete);
140 static HANDLE_FUNC (handle_pidfile);
141 static HANDLE_FUNC (handle_port);
142 #ifdef REVERSE_SUPPORT
143 static HANDLE_FUNC (handle_reversebaseurl);
144 static HANDLE_FUNC (handle_reversemagic);
145 static HANDLE_FUNC (handle_reverseonly);
146 static HANDLE_FUNC (handle_reversepath);
147 #endif
148 static HANDLE_FUNC (handle_statfile);
149 static HANDLE_FUNC (handle_stathost);
150 static HANDLE_FUNC (handle_syslog);
151 static HANDLE_FUNC (handle_timeout);
152
153 static HANDLE_FUNC (handle_user);
154 static HANDLE_FUNC (handle_viaproxyname);
155 static HANDLE_FUNC (handle_disableviaheader);
156 static HANDLE_FUNC (handle_xtinyproxy);
157
158 #ifdef UPSTREAM_SUPPORT
159 static HANDLE_FUNC (handle_upstream);
160 #endif
161
162 static void config_free_regex (void);
163
164 /*
165 * This macro can be used to make standard directives in the form:
166 * directive arguments [arguments ...]
167 *
168 * The directive itself will be the first matched substring.
169 *
170 * Note that this macro is not required. As you can see below, the
171 * comment and blank line elements are defined explicitly since they
172 * do not follow the pattern above. This macro is for convenience
173 * only.
174 */
175 #define STDCONF(d, re, func) [CD_ ## d] = { BEGIN "()" WS re END, func, NULL }
176
177 /*
178 * Holds the regular expression used to match the configuration directive,
179 * the function pointer to the routine to handle the directive, and
180 * for internal use, a pointer to the compiled regex so it only needs
181 * to be compiled one.
182 */
183 struct {
184 const char *re;
185 CONFFILE_HANDLER handler;
186 regex_t *cre;
187 } directives[] = {
188 /* string arguments */
189 STDCONF (logfile, STR, handle_logfile),
190 STDCONF (pidfile, STR, handle_pidfile),
191 STDCONF (anonymous, STR, handle_anonymous),
192 STDCONF (viaproxyname, STR, handle_viaproxyname),
193 STDCONF (defaulterrorfile, STR, handle_defaulterrorfile),
194 STDCONF (statfile, STR, handle_statfile),
195 STDCONF (stathost, STR, handle_stathost),
196 STDCONF (xtinyproxy, BOOL, handle_xtinyproxy),
197 /* boolean arguments */
198 STDCONF (syslog, BOOL, handle_syslog),
199 STDCONF (bindsame, BOOL, handle_bindsame),
200 STDCONF (disableviaheader, BOOL, handle_disableviaheader),
201 /* integer arguments */
202 STDCONF (port, INT, handle_port),
203 STDCONF (maxclients, INT, handle_maxclients),
204 STDCONF (maxspareservers, INT, handle_obsolete),
205 STDCONF (minspareservers, INT, handle_obsolete),
206 STDCONF (startservers, INT, handle_obsolete),
207 STDCONF (maxrequestsperchild, INT, handle_obsolete),
208 STDCONF (timeout, INT, handle_timeout),
209 STDCONF (connectport, INT, handle_connectport),
210 /* alphanumeric arguments */
211 STDCONF (user, ALNUM, handle_user),
212 STDCONF (group, ALNUM, handle_group),
213 /* ip arguments */
214 STDCONF (listen, "(" IP "|" IPV6 ")", handle_listen),
215 STDCONF (allow, "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
216 handle_allow),
217 STDCONF (deny, "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
218 handle_deny),
219 STDCONF (bind, "(" IP "|" IPV6 ")", handle_bind),
220 /* other */
221 STDCONF (basicauth, ALNUM WS ALNUM, handle_basicauth),
222 STDCONF (errorfile, INT WS STR, handle_errorfile),
223 STDCONF (addheader, STR WS STR, handle_addheader),
224
225 #ifdef FILTER_ENABLE
226 /* filtering */
227 STDCONF (filter, STR, handle_filter),
228 STDCONF (filterurls, BOOL, handle_filterurls),
229 STDCONF (filterextended, BOOL, handle_filterextended),
230 STDCONF (filterdefaultdeny, BOOL, handle_filterdefaultdeny),
231 STDCONF (filtercasesensitive, BOOL, handle_filtercasesensitive),
232 #endif
233 #ifdef REVERSE_SUPPORT
234 /* Reverse proxy arguments */
235 STDCONF (reversebaseurl, STR, handle_reversebaseurl),
236 STDCONF (reverseonly, BOOL, handle_reverseonly),
237 STDCONF (reversemagic, BOOL, handle_reversemagic),
238 STDCONF (reversepath, STR "(" WS STR ")?", handle_reversepath),
239 #endif
240 #ifdef UPSTREAM_SUPPORT
241 STDCONF (upstream,
242 "(" "(none)" WS STR ")|" \
243 "(" "(http|socks4|socks5)" WS \
244 "(" USERNAME /*username*/ ":" PASSWORD /*password*/ "@" ")?"
245 "(" IP "|" ALNUM ")"
246 ":" INT "(" WS STR ")?" ")", handle_upstream),
247 #endif
248 /* loglevel */
249 STDCONF (loglevel, "(critical|error|warning|notice|connect|info)",
250 handle_loglevel)
251 };
252
253 const unsigned int ndirectives = sizeof (directives) / sizeof (directives[0]);
254
255 static void
free_added_headers(sblist * add_headers)256 free_added_headers (sblist* add_headers)
257 {
258 size_t i;
259
260 if (!add_headers) return;
261
262 for (i = 0; i < sblist_getsize (add_headers); i++) {
263 http_header_t *header = sblist_get (add_headers, i);
264
265 safefree (header->name);
266 safefree (header->value);
267 }
268
269 sblist_free (add_headers);
270 }
271
stringlist_free(sblist * sl)272 static void stringlist_free(sblist *sl) {
273 size_t i;
274 char **s;
275 if(sl) {
276 for(i = 0; i < sblist_getsize(sl); i++) {
277 s = sblist_get(sl, i);
278 if(s) safefree(*s);
279 }
280 sblist_free(sl);
281 }
282 }
283
free_config(struct config_s * conf)284 void free_config (struct config_s *conf)
285 {
286 char *k;
287 htab_value *v;
288 size_t it;
289 safefree (conf->logf_name);
290 safefree (conf->stathost);
291 safefree (conf->user);
292 safefree (conf->group);
293 stringlist_free(conf->basicauth_list);
294 stringlist_free(conf->listen_addrs);
295 stringlist_free(conf->bind_addrs);
296 #ifdef FILTER_ENABLE
297 safefree (conf->filter);
298 #endif /* FILTER_ENABLE */
299 #ifdef REVERSE_SUPPORT
300 free_reversepath_list(conf->reversepath_list);
301 safefree (conf->reversebaseurl);
302 #endif
303 #ifdef UPSTREAM_SUPPORT
304 free_upstream_list (conf->upstream_list);
305 #endif /* UPSTREAM_SUPPORT */
306 safefree (conf->pidpath);
307 safefree (conf->via_proxy_name);
308 if (conf->errorpages) {
309 it = 0;
310 while((it = htab_next(conf->errorpages, it, &k, &v))) {
311 safefree(k);
312 safefree(v->p);
313 }
314 htab_destroy (conf->errorpages);
315 }
316 free_added_headers (conf->add_headers);
317 safefree (conf->errorpage_undef);
318 safefree (conf->statpage);
319 flush_access_list (conf->access_list);
320 free_connect_ports_list (conf->connect_ports);
321 if (conf->anonymous_map) {
322 it = 0;
323 while((it = htab_next(conf->anonymous_map, it, &k, &v)))
324 safefree(k);
325 htab_destroy (conf->anonymous_map);
326 }
327
328 memset (conf, 0, sizeof(*conf));
329 }
330
331 /*
332 * Initializes Config parser. Currently this means:
333 * Compiles the regular expressions used by the configuration file. This
334 * routine MUST be called before trying to parse the configuration file.
335 *
336 * Returns 0 on success; negative upon failure.
337 */
338 int
config_init(void)339 config_init (void)
340 {
341 unsigned int i, r;
342
343 for (i = 0; i != ndirectives; ++i) {
344 assert (!directives[i].cre);
345
346 if (!directives[i].handler) {
347 directives[i].handler = handle_disabled_feature;
348 continue;
349 }
350
351 directives[i].cre = (regex_t *) safemalloc (sizeof (regex_t));
352 if (!directives[i].cre)
353 return -1;
354
355 r = regcomp (directives[i].cre,
356 directives[i].re,
357 REG_EXTENDED | REG_ICASE | REG_NEWLINE);
358 if (r)
359 return r;
360 }
361
362 atexit (config_free_regex);
363
364 return 0;
365 }
366
367 /*
368 * Frees pre-compiled regular expressions used by the configuration
369 * file. This function is registered to be automatically called at exit.
370 */
371 static void
config_free_regex(void)372 config_free_regex (void)
373 {
374 unsigned int i;
375
376 for (i = 0; i < ndirectives; i++) {
377 if (directives[i].cre) {
378 regfree (directives[i].cre);
379 safefree (directives[i].cre);
380 directives[i].cre = NULL;
381 }
382 }
383 }
384
385 /*
386 * Attempt to match the supplied line with any of the configuration
387 * regexes defined above. If a match is found, call the handler
388 * function to process the directive.
389 *
390 * Returns 0 if a match was found and successfully processed; otherwise,
391 * a negative number is returned.
392 */
check_match(struct config_s * conf,const char * line,unsigned long lineno,enum config_directive cd)393 static int check_match (struct config_s *conf, const char *line,
394 unsigned long lineno, enum config_directive cd)
395 {
396 regmatch_t match[RE_MAX_MATCHES];
397 unsigned int i = cd;
398
399 if (!directives[i].cre)
400 return (*directives[i].handler) (conf, line, lineno, match);
401
402 if (!regexec
403 (directives[i].cre, line, RE_MAX_MATCHES, match, 0))
404 return (*directives[i].handler) (conf, line, lineno, match);
405 return -1;
406 }
407
408 /*
409 * Parse the previously opened configuration stream.
410 */
config_parse(struct config_s * conf,FILE * f)411 static int config_parse (struct config_s *conf, FILE * f)
412 {
413 char buffer[LINE_MAX], *p, *q, c;
414 const struct config_directive_entry *e;
415 unsigned long lineno = 1;
416
417 for (;fgets (buffer, sizeof (buffer), f);++lineno) {
418 if(buffer[0] == '#') continue;
419 p = buffer;
420 while(isspace(*p))p++;
421 if(!*p) continue;
422 q = p;
423 while(!isspace(*q))q++;
424 c = *q;
425 *q = 0;
426 e = config_directive_find(p, strlen(p));
427 *q = c;
428 if (!e || e->value == CD_NIL || check_match (conf, q, lineno, e->value)) {
429 fprintf (stderr, "ERROR: Syntax error on line %lu\n", lineno);
430 return 1;
431 }
432 }
433 return 0;
434 }
435
436 /**
437 * Read the settings from a config file.
438 */
load_config_file(const char * config_fname,struct config_s * conf)439 static int load_config_file (const char *config_fname, struct config_s *conf)
440 {
441 FILE *config_file;
442 int ret = -1;
443
444 config_file = fopen (config_fname, "r");
445 if (!config_file) {
446 fprintf (stderr,
447 "%s: Could not open config file \"%s\".\n",
448 PACKAGE, config_fname);
449 goto done;
450 }
451
452 if (config_parse (conf, config_file)) {
453 fprintf (stderr, "Unable to parse config file. "
454 "Not starting.\n");
455 goto done;
456 }
457
458 ret = 0;
459
460 done:
461 if (config_file)
462 fclose (config_file);
463
464 return ret;
465 }
466
initialize_config_defaults(struct config_s * conf)467 static void initialize_config_defaults (struct config_s *conf)
468 {
469 memset (conf, 0, sizeof(*conf));
470
471 /*
472 * Make sure the HTML error pages array is NULL to begin with.
473 * (FIXME: Should have a better API for all this)
474 */
475 conf->errorpages = NULL;
476 conf->stathost = safestrdup (TINYPROXY_STATHOST);
477 conf->idletimeout = MAX_IDLE_TIME;
478 conf->logf_name = NULL;
479 conf->pidpath = NULL;
480 conf->maxclients = 100;
481 }
482
483 /**
484 * Load the configuration.
485 */
reload_config_file(const char * config_fname,struct config_s * conf)486 int reload_config_file (const char *config_fname, struct config_s *conf)
487 {
488 int ret;
489
490 initialize_config_defaults (conf);
491
492 ret = load_config_file (config_fname, conf);
493 if (ret != 0) {
494 goto done;
495 }
496
497 /* Set the default values if they were not set in the config file. */
498 if (conf->port == 0) {
499 /*
500 * Don't log here in error path:
501 * logging might not be set up yet!
502 */
503 fprintf (stderr, PACKAGE ": You MUST set a Port in the "
504 "config file.\n");
505 ret = -1;
506 goto done;
507 }
508
509 if (!conf->user) {
510 log_message (LOG_WARNING, "You SHOULD set a UserName in the "
511 "config file. Using current user instead.");
512 }
513
514 if (conf->idletimeout == 0) {
515 log_message (LOG_WARNING, "Invalid idle time setting. "
516 "Only values greater than zero are allowed. "
517 "Therefore setting idle timeout to %u seconds.",
518 MAX_IDLE_TIME);
519 conf->idletimeout = MAX_IDLE_TIME;
520 }
521
522 done:
523 return ret;
524 }
525
526 /***********************************************************************
527 *
528 * The following are basic data extraction building blocks that can
529 * be used to simplify the parsing of a directive.
530 *
531 ***********************************************************************/
532
get_string_arg(const char * line,regmatch_t * match)533 static char *get_string_arg (const char *line, regmatch_t * match)
534 {
535 char *p;
536 const unsigned int len = match->rm_eo - match->rm_so;
537
538 assert (line);
539 assert (len > 0);
540
541 p = (char *) safemalloc (len + 1);
542 if (!p)
543 return NULL;
544
545 memcpy (p, line + match->rm_so, len);
546 p[len] = '\0';
547 return p;
548 }
549
set_string_arg(char ** var,const char * line,regmatch_t * match)550 static int set_string_arg (char **var, const char *line, regmatch_t * match)
551 {
552 char *arg = get_string_arg (line, match);
553
554 if (!arg)
555 return -1;
556
557 if (*var != NULL) {
558 safefree (*var);
559 }
560
561 *var = arg;
562
563 return 0;
564 }
565
get_bool_arg(const char * line,regmatch_t * match)566 static int get_bool_arg (const char *line, regmatch_t * match)
567 {
568 const char *p = line + match->rm_so;
569
570 assert (line);
571 assert (match && match->rm_so != -1);
572
573 /* "y"es or o"n" map as true, otherwise it's false. */
574 if (tolower (p[0]) == 'y' || tolower (p[1]) == 'n')
575 return 1;
576 else
577 return 0;
578 }
579
580 static int
set_bool_arg(unsigned int * var,const char * line,regmatch_t * match)581 set_bool_arg (unsigned int *var, const char *line, regmatch_t * match)
582 {
583 assert (var);
584 assert (line);
585 assert (match && match->rm_so != -1);
586
587 *var = get_bool_arg (line, match);
588 return 0;
589 }
590
591 static unsigned long
get_long_arg(const char * line,regmatch_t * match)592 get_long_arg (const char *line, regmatch_t * match)
593 {
594 assert (line);
595 assert (match && match->rm_so != -1);
596
597 return strtoul (line + match->rm_so, NULL, 0);
598 }
599
600 static int
set_int_arg(unsigned int * var,const char * line,regmatch_t * match)601 set_int_arg (unsigned int *var, const char *line, regmatch_t * match)
602 {
603 assert (var);
604 assert (line);
605 assert (match);
606
607 *var = (unsigned int) get_long_arg (line, match);
608 return 0;
609 }
610
611 /***********************************************************************
612 *
613 * Below are all the directive handling functions. You will notice
614 * that most of the directives delegate to one of the basic data
615 * extraction routines. This is deliberate. To add a new directive
616 * to tinyproxy only requires you to define the regular expression
617 * above and then figure out what data extract routine to use.
618 *
619 * However, you will also notice that more complicated directives are
620 * possible. You can make your directive as complicated as you require
621 * to express a solution to the problem you're tackling.
622 *
623 * See the definition/comment about the HANDLE_FUNC() macro to learn
624 * what arguments are supplied to the handler, and to determine what
625 * values to return.
626 *
627 ***********************************************************************/
628
HANDLE_FUNC(handle_logfile)629 static HANDLE_FUNC (handle_logfile)
630 {
631 return set_string_arg (&conf->logf_name, line, &match[2]);
632 }
633
HANDLE_FUNC(handle_pidfile)634 static HANDLE_FUNC (handle_pidfile)
635 {
636 return set_string_arg (&conf->pidpath, line, &match[2]);
637 }
638
HANDLE_FUNC(handle_anonymous)639 static HANDLE_FUNC (handle_anonymous)
640 {
641 char *arg = get_string_arg (line, &match[2]);
642
643 if (!arg)
644 return -1;
645
646 if(anonymous_insert (conf, arg) < 0) {
647 CP_WARN ("anonymous_insert() failed: '%s'", arg);
648 safefree(arg);
649 return -1;
650 }
651
652 return 0;
653 }
654
HANDLE_FUNC(handle_viaproxyname)655 static HANDLE_FUNC (handle_viaproxyname)
656 {
657 int r = set_string_arg (&conf->via_proxy_name, line, &match[2]);
658
659 if (r)
660 return r;
661 log_message (LOG_INFO,
662 "Setting \"Via\" header to '%s'",
663 conf->via_proxy_name);
664 return 0;
665 }
666
HANDLE_FUNC(handle_disableviaheader)667 static HANDLE_FUNC (handle_disableviaheader)
668 {
669 int r = set_bool_arg (&conf->disable_viaheader, line, &match[2]);
670
671 if (r) {
672 return r;
673 }
674
675 log_message (LOG_INFO,
676 "Disabling transmission of the \"Via\" header.");
677 return 0;
678 }
679
HANDLE_FUNC(handle_defaulterrorfile)680 static HANDLE_FUNC (handle_defaulterrorfile)
681 {
682 return set_string_arg (&conf->errorpage_undef, line, &match[2]);
683 }
684
HANDLE_FUNC(handle_statfile)685 static HANDLE_FUNC (handle_statfile)
686 {
687 return set_string_arg (&conf->statpage, line, &match[2]);
688 }
689
HANDLE_FUNC(handle_stathost)690 static HANDLE_FUNC (handle_stathost)
691 {
692 int r = set_string_arg (&conf->stathost, line, &match[2]);
693
694 if (r)
695 return r;
696 log_message (LOG_INFO, "Stathost set to \"%s\"", conf->stathost);
697 return 0;
698 }
699
HANDLE_FUNC(handle_xtinyproxy)700 static HANDLE_FUNC (handle_xtinyproxy)
701 {
702 #ifdef XTINYPROXY_ENABLE
703 return set_bool_arg (&conf->add_xtinyproxy, line, &match[2]);
704 #else
705 fprintf (stderr,
706 "XTinyproxy NOT Enabled! Recompile with --enable-xtinyproxy\n");
707 return 1;
708 #endif
709 }
710
HANDLE_FUNC(handle_syslog)711 static HANDLE_FUNC (handle_syslog)
712 {
713 return set_bool_arg (&conf->syslog, line, &match[2]);
714 }
715
HANDLE_FUNC(handle_bindsame)716 static HANDLE_FUNC (handle_bindsame)
717 {
718 int r = set_bool_arg (&conf->bindsame, line, &match[2]);
719
720 if (r)
721 return r;
722 log_message (LOG_INFO, "Binding outgoing connection to incoming IP");
723 return 0;
724 }
725
HANDLE_FUNC(handle_port)726 static HANDLE_FUNC (handle_port)
727 {
728 set_int_arg (&conf->port, line, &match[2]);
729
730 if (conf->port > 65535) {
731 fprintf (stderr, "Bad port number (%d) supplied for Port.\n",
732 conf->port);
733 return 1;
734 }
735
736 return 0;
737 }
738
HANDLE_FUNC(handle_maxclients)739 static HANDLE_FUNC (handle_maxclients)
740 {
741 set_int_arg (&conf->maxclients, line, &match[2]);
742 return 0;
743 }
744
HANDLE_FUNC(handle_obsolete)745 static HANDLE_FUNC (handle_obsolete)
746 {
747 fprintf (stderr, "WARNING: obsolete config item on line %lu\n",
748 lineno);
749 return 0;
750 }
751
HANDLE_FUNC(handle_timeout)752 static HANDLE_FUNC (handle_timeout)
753 {
754 return set_int_arg (&conf->idletimeout, line, &match[2]);
755 }
756
HANDLE_FUNC(handle_connectport)757 static HANDLE_FUNC (handle_connectport)
758 {
759 add_connect_port_allowed (get_long_arg (line, &match[2]),
760 &conf->connect_ports);
761 return 0;
762 }
763
HANDLE_FUNC(handle_user)764 static HANDLE_FUNC (handle_user)
765 {
766 return set_string_arg (&conf->user, line, &match[2]);
767 }
768
HANDLE_FUNC(handle_group)769 static HANDLE_FUNC (handle_group)
770 {
771 return set_string_arg (&conf->group, line, &match[2]);
772 }
773
warn_invalid_address(char * arg,unsigned long lineno)774 static void warn_invalid_address(char *arg, unsigned long lineno) {
775 CP_WARN ("Invalid address %s", arg);
776 }
777
HANDLE_FUNC(handle_allow)778 static HANDLE_FUNC (handle_allow)
779 {
780 char *arg = get_string_arg (line, &match[2]);
781
782 if(insert_acl (arg, ACL_ALLOW, &conf->access_list) < 0)
783 warn_invalid_address (arg, lineno);
784 safefree (arg);
785 return 0;
786 }
787
HANDLE_FUNC(handle_deny)788 static HANDLE_FUNC (handle_deny)
789 {
790 char *arg = get_string_arg (line, &match[2]);
791
792 if(insert_acl (arg, ACL_DENY, &conf->access_list) < 0)
793 warn_invalid_address (arg, lineno);
794 safefree (arg);
795 return 0;
796 }
797
HANDLE_FUNC(handle_bind)798 static HANDLE_FUNC (handle_bind)
799 {
800 char *arg = get_string_arg (line, &match[2]);
801
802 if (arg == NULL) {
803 return -1;
804 }
805
806 if (conf->bind_addrs == NULL) {
807 conf->bind_addrs = sblist_new(sizeof(char*), 16);
808 if (conf->bind_addrs == NULL) {
809 CP_WARN ("Could not create a list "
810 "of bind addresses.", "");
811 safefree(arg);
812 return -1;
813 }
814 }
815
816 sblist_add (conf->bind_addrs, &arg);
817
818 log_message (LOG_INFO,
819 "Added bind address [%s] for outgoing connections.", arg);
820
821 return 0;
822 }
823
HANDLE_FUNC(handle_listen)824 static HANDLE_FUNC (handle_listen)
825 {
826 char *arg = get_string_arg (line, &match[2]);
827
828 if (arg == NULL) {
829 return -1;
830 }
831
832 if (conf->listen_addrs == NULL) {
833 conf->listen_addrs = sblist_new(sizeof(char*), 16);
834 if (conf->listen_addrs == NULL) {
835 CP_WARN ("Could not create a list "
836 "of listen addresses.", "");
837 safefree(arg);
838 return -1;
839 }
840 }
841
842 sblist_add (conf->listen_addrs, &arg);
843
844 log_message(LOG_INFO, "Added address [%s] to listen addresses.", arg);
845
846 return 0;
847 }
848
HANDLE_FUNC(handle_errorfile)849 static HANDLE_FUNC (handle_errorfile)
850 {
851 /*
852 * Because an integer is defined as ((0x)?[[:digit:]]+) _two_
853 * match places are used. match[2] matches the full digit
854 * string, while match[3] matches only the "0x" part if
855 * present. This is why the "string" is located at
856 * match[4] (rather than the more intuitive match[3].
857 */
858 unsigned long int err = get_long_arg (line, &match[2]);
859 char *page = get_string_arg (line, &match[4]);
860
861 if(add_new_errorpage (conf, page, err) < 0) {
862 CP_WARN ("add_new_errorpage() failed: '%s'", page);
863 safefree (page);
864 }
865 return 0;
866 }
867
HANDLE_FUNC(handle_addheader)868 static HANDLE_FUNC (handle_addheader)
869 {
870 char *name = get_string_arg (line, &match[2]);
871 char *value = get_string_arg (line, &match[3]);
872 http_header_t header;
873
874 if (!conf->add_headers) {
875 conf->add_headers = sblist_new (sizeof(http_header_t), 16);
876 }
877
878 header.name = name;
879 header.value = value;
880
881 sblist_add (conf->add_headers, &header);
882
883 /* Don't free name or value here, as they are referenced in the
884 * struct inserted into the vector. */
885
886 return 0;
887 }
888
889 /*
890 * Log level's strings.
891
892 */
893 struct log_levels_s {
894 const char *string;
895 int level;
896 };
897 static struct log_levels_s log_levels[] = {
898 {"critical", LOG_CRIT},
899 {"error", LOG_ERR},
900 {"warning", LOG_WARNING},
901 {"notice", LOG_NOTICE},
902 {"connect", LOG_CONN},
903 {"info", LOG_INFO}
904 };
905
HANDLE_FUNC(handle_loglevel)906 static HANDLE_FUNC (handle_loglevel)
907 {
908 static const unsigned int nlevels =
909 sizeof (log_levels) / sizeof (log_levels[0]);
910 unsigned int i;
911
912 char *arg = get_string_arg (line, &match[2]);
913
914 for (i = 0; i != nlevels; ++i) {
915 if (!strcasecmp (arg, log_levels[i].string)) {
916 set_log_level (log_levels[i].level);
917 safefree (arg);
918 return 0;
919 }
920 }
921
922 safefree (arg);
923 return -1;
924 }
925
HANDLE_FUNC(handle_basicauth)926 static HANDLE_FUNC (handle_basicauth)
927 {
928 char *user, *pass;
929 user = get_string_arg(line, &match[2]);
930 if (!user)
931 return -1;
932 pass = get_string_arg(line, &match[3]);
933 if (!pass) {
934 safefree (user);
935 return -1;
936 }
937 if (!conf->basicauth_list) {
938 conf->basicauth_list = sblist_new (sizeof(char*), 16);
939 }
940
941 basicauth_add (conf->basicauth_list, user, pass);
942 safefree (user);
943 safefree (pass);
944 return 0;
945 }
946
947 #ifdef FILTER_ENABLE
HANDLE_FUNC(handle_filter)948 static HANDLE_FUNC (handle_filter)
949 {
950 return set_string_arg (&conf->filter, line, &match[2]);
951 }
952
HANDLE_FUNC(handle_filterurls)953 static HANDLE_FUNC (handle_filterurls)
954 {
955 return set_bool_arg (&conf->filter_url, line, &match[2]);
956 }
957
HANDLE_FUNC(handle_filterextended)958 static HANDLE_FUNC (handle_filterextended)
959 {
960 return set_bool_arg (&conf->filter_extended, line, &match[2]);
961 }
962
HANDLE_FUNC(handle_filterdefaultdeny)963 static HANDLE_FUNC (handle_filterdefaultdeny)
964 {
965 assert (match[2].rm_so != -1);
966
967 if (get_bool_arg (line, &match[2]))
968 filter_set_default_policy (FILTER_DEFAULT_DENY);
969 return 0;
970 }
971
HANDLE_FUNC(handle_filtercasesensitive)972 static HANDLE_FUNC (handle_filtercasesensitive)
973 {
974 return set_bool_arg (&conf->filter_casesensitive, line, &match[2]);
975 }
976 #endif
977
978 #ifdef REVERSE_SUPPORT
HANDLE_FUNC(handle_reverseonly)979 static HANDLE_FUNC (handle_reverseonly)
980 {
981 return set_bool_arg (&conf->reverseonly, line, &match[2]);
982 }
983
HANDLE_FUNC(handle_reversemagic)984 static HANDLE_FUNC (handle_reversemagic)
985 {
986 return set_bool_arg (&conf->reversemagic, line, &match[2]);
987 }
988
HANDLE_FUNC(handle_reversebaseurl)989 static HANDLE_FUNC (handle_reversebaseurl)
990 {
991 return set_string_arg (&conf->reversebaseurl, line, &match[2]);
992 }
993
HANDLE_FUNC(handle_reversepath)994 static HANDLE_FUNC (handle_reversepath)
995 {
996 /*
997 * The second string argument is optional.
998 */
999 char *arg1, *arg2;
1000
1001 arg1 = get_string_arg (line, &match[2]);
1002 if (!arg1)
1003 return -1;
1004
1005 if (match[4].rm_so != -1) {
1006 arg2 = get_string_arg (line, &match[4]);
1007 if (!arg2) {
1008 safefree (arg1);
1009 return -1;
1010 }
1011 reversepath_add (arg1, arg2, &conf->reversepath_list);
1012 safefree (arg1);
1013 safefree (arg2);
1014 } else {
1015 reversepath_add (NULL, arg1, &conf->reversepath_list);
1016 safefree (arg1);
1017 }
1018 return 0;
1019 }
1020 #endif
1021
1022 #ifdef UPSTREAM_SUPPORT
1023
pt_from_string(const char * s)1024 static enum proxy_type pt_from_string(const char *s)
1025 {
1026 static const char pt_map[][7] = {
1027 [PT_NONE] = "none",
1028 [PT_HTTP] = "http",
1029 [PT_SOCKS4] = "socks4",
1030 [PT_SOCKS5] = "socks5",
1031 };
1032 unsigned i;
1033 for (i = 0; i < sizeof(pt_map)/sizeof(pt_map[0]); i++)
1034 if (!strcmp(pt_map[i], s))
1035 return i;
1036 return PT_NONE;
1037 }
1038
HANDLE_FUNC(handle_upstream)1039 static HANDLE_FUNC (handle_upstream)
1040 {
1041 char *ip;
1042 int port, mi;
1043 char *domain = 0, *user = 0, *pass = 0, *tmp;
1044 enum proxy_type pt;
1045 enum upstream_build_error ube;
1046
1047 if (match[3].rm_so != -1) {
1048 tmp = get_string_arg (line, &match[3]);
1049 if(!strcmp(tmp, "none")) {
1050 safefree(tmp);
1051 if (match[4].rm_so == -1) return -1;
1052 domain = get_string_arg (line, &match[4]);
1053 if (!domain)
1054 return -1;
1055 ube = upstream_add (NULL, 0, domain, 0, 0, PT_NONE, &conf->upstream_list);
1056 safefree (domain);
1057 goto check_err;
1058 }
1059 }
1060
1061 mi = 6;
1062
1063 tmp = get_string_arg (line, &match[mi]);
1064 pt = pt_from_string(tmp);
1065 safefree(tmp);
1066 mi += 2;
1067
1068 if (match[mi].rm_so != -1)
1069 user = get_string_arg (line, &match[mi]);
1070 mi++;
1071
1072 if (match[mi].rm_so != -1)
1073 pass = get_string_arg (line, &match[mi]);
1074 mi++;
1075
1076 ip = get_string_arg (line, &match[mi]);
1077 if (!ip)
1078 return -1;
1079 mi += 5;
1080
1081 port = (int) get_long_arg (line, &match[mi]);
1082 mi += 3;
1083
1084 if (match[mi].rm_so != -1)
1085 domain = get_string_arg (line, &match[mi]);
1086
1087 ube = upstream_add (ip, port, domain, user, pass, pt, &conf->upstream_list);
1088
1089 safefree (user);
1090 safefree (pass);
1091 safefree (domain);
1092 safefree (ip);
1093
1094 check_err:;
1095 if(ube != UBE_SUCCESS)
1096 CP_WARN("%s", upstream_build_error_string(ube));
1097 return 0;
1098 }
1099
1100 #endif
1101