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