Unblock cURL advisories.
[privoxy.git] / loadcfg.c
1 const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.71 2007/12/23 15:24:56 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/loadcfg.c,v $
5  *
6  * Purpose     :  Loads settings from the configuration file into
7  *                global variables.  This file contains both the
8  *                routine to load the configuration and the global
9  *                variables it writes to.
10  *
11  * Copyright   :  Written by and Copyright (C) 2001-2007 the SourceForge
12  *                Privoxy team. http://www.privoxy.org/
13  *
14  *                Based on the Internet Junkbuster originally written
15  *                by and Copyright (C) 1997 Anonymous Coders and
16  *                Junkbusters Corporation.  http://www.junkbusters.com
17  *
18  *                This program is free software; you can redistribute it
19  *                and/or modify it under the terms of the GNU General
20  *                Public License as published by the Free Software
21  *                Foundation; either version 2 of the License, or (at
22  *                your option) any later version.
23  *
24  *                This program is distributed in the hope that it will
25  *                be useful, but WITHOUT ANY WARRANTY; without even the
26  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
27  *                PARTICULAR PURPOSE.  See the GNU General Public
28  *                License for more details.
29  *
30  *                The GNU General Public License should be included with
31  *                this file.  If not, you can view it at
32  *                http://www.gnu.org/copyleft/gpl.html
33  *                or write to the Free Software Foundation, Inc., 59
34  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  *
36  * Revisions   :
37  *    $Log: loadcfg.c,v $
38  *    Revision 1.71  2007/12/23 15:24:56  fabiankeil
39  *    Reword "unrecognized directive" warning, use better
40  *    mark up and add a <br>. Fixes parts of #1856559.
41  *
42  *    Revision 1.70  2007/12/15 14:24:05  fabiankeil
43  *    Plug memory leak if listen-address only specifies the port.
44  *
45  *    Revision 1.69  2007/10/27 13:02:27  fabiankeil
46  *    Relocate daemon-mode-related log messages to make sure
47  *    they aren't shown again in case of configuration reloads.
48  *
49  *    Revision 1.68  2007/10/19 16:32:34  fabiankeil
50  *    Plug memory leak introduced with my last commit.
51  *
52  *    Revision 1.67  2007/10/14 14:12:41  fabiankeil
53  *    When in daemon mode, close stderr after the configuration file has been
54  *    parsed the first time. If logfile isn't set, stop logging. Fixes BR#897436.
55  *
56  *    Revision 1.66  2007/08/05 14:02:09  fabiankeil
57  *    #1763173 from Stefan Huehner: declare unload_configfile() static.
58  *
59  *    Revision 1.65  2007/07/21 11:51:36  fabiankeil
60  *    As Hal noticed, checking dispatch_cgi() as the last cruncher
61  *    looks like a bug if CGI requests are blocked unintentionally,
62  *    so don't do it unless the user enabled the new config option
63  *    "allow-cgi-request-crunching".
64  *
65  *    Revision 1.64  2007/05/21 10:44:08  fabiankeil
66  *    - Use strlcpy() instead of strcpy().
67  *    - Stop treating actions files special. Expect a complete file name
68  *      (with or without path) like it's done for the rest of the files.
69  *      Closes FR#588084.
70  *    - Remove an unnecessary temporary memory allocation.
71  *    - Don't log anything to the console when running as
72  *      daemon and no errors occurred.
73  *
74  *    Revision 1.63  2007/04/09 18:11:36  fabiankeil
75  *    Don't mistake VC++'s _snprintf() for a snprintf() replacement.
76  *
77  *    Revision 1.62  2007/03/17 15:20:05  fabiankeil
78  *    New config option: enforce-blocks.
79  *
80  *    Revision 1.61  2007/03/16 16:47:35  fabiankeil
81  *    - Mention other reasons why acl directive loading might have failed.
82  *    - Don't log the acl source if the acl destination is to blame.
83  *
84  *    Revision 1.60  2007/01/27 13:09:16  fabiankeil
85  *    Add new config option "templdir" to
86  *    change the templates directory.
87  *
88  *    Revision 1.59  2006/12/31 17:56:38  fabiankeil
89  *    Added config option accept-intercepted-requests
90  *    and disabled it by default.
91  *
92  *    Revision 1.58  2006/12/31 14:24:29  fabiankeil
93  *    Fix gcc43 compiler warnings.
94  *
95  *    Revision 1.57  2006/12/21 12:57:48  fabiankeil
96  *    Add config option "split-large-forms"
97  *    to work around the browser bug reported
98  *    in BR #1570678.
99  *
100  *    Revision 1.56  2006/12/17 17:04:51  fabiankeil
101  *    Move the <br> in the generated HTML for the config
102  *    options from the beginning of the string to its end.
103  *    Keeps the white space in balance.
104  *
105  *    Revision 1.55  2006/11/28 15:31:52  fabiankeil
106  *    Fix memory leak in case of config file reloads.
107  *
108  *    Revision 1.54  2006/10/21 16:04:22  fabiankeil
109  *    Modified kludge for win32 to make ming32 menu
110  *    "Options/Edit Filters" (sort of) work again.
111  *    Same limitations as for the action files apply.
112  *    Fixes BR 1567373.
113  *
114  *    Revision 1.53  2006/09/06 18:45:03  fabiankeil
115  *    Incorporate modified version of Roland Rosenfeld's patch to
116  *    optionally access the user-manual via Privoxy. Closes patch 679075.
117  *
118  *    Formatting changed to Privoxy style, added call to
119  *    cgi_error_no_template if the requested file doesn't
120  *    exist and modified check whether or not Privoxy itself
121  *    should serve the manual. Should work cross-platform now.
122  *
123  *    Revision 1.52  2006/09/06 10:43:32  fabiankeil
124  *    Added config option enable-remote-http-toggle
125  *    to specify if Privoxy should recognize special
126  *    headers (currently only X-Filter) to change its
127  *    behaviour. Disabled by default.
128  *
129  *    Revision 1.51  2006/09/06 09:23:37  fabiankeil
130  *    Make number of retries in case of forwarded-connect problems
131  *    a config file option (forwarded-connect-retries) and use 0 as
132  *    default.
133  *
134  *    Revision 1.50  2006/07/18 14:48:46  david__schmidt
135  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
136  *    with what was really the latest development (the v_3_0_branch branch)
137  *
138  *    Revision 1.48.2.7  2006/02/02 17:29:16  david__schmidt
139  *    Don't forget to malloc space for the null terminator...
140  *
141  *    Revision 1.48.2.6  2006/01/29 23:10:56  david__schmidt
142  *    Multiple filter file support
143  *
144  *    Revision 1.48.2.5  2003/05/08 15:17:25  oes
145  *    Closed two memory leaks; hopefully the last remaining ones
146  *    (in the main execution paths, anyway).
147  *
148  *    Revision 1.48.2.4  2003/04/11 12:06:14  oes
149  *    Addressed bug #719435
150  *     - Extraneous filterfile directives now logged as errors
151  *     - This and unrecnonised directives now really obvious on status page
152  *
153  *    Revision 1.48.2.3  2003/03/11 11:53:59  oes
154  *    Cosmetic: Renamed cryptic variable
155  *
156  *    Revision 1.48.2.2  2002/11/12 16:28:20  oes
157  *    Move unrelated variable declaration out of #ifdef FEATURE_ACL; fixes bug #636655
158  *
159  *    Revision 1.48.2.1  2002/08/21 17:58:05  oes
160  *    Temp kludge to let user and default action file be edited through win32 GUI (FR 592080)
161  *
162  *    Revision 1.48  2002/05/14 21:30:38  oes
163  *    savearg now uses own linking code instead of (now special-cased) add_help_link
164  *
165  *    Revision 1.47  2002/05/12 21:36:29  jongfoster
166  *    Correcting function comments
167  *
168  *    Revision 1.46  2002/04/26 12:55:14  oes
169  *     - New option "user-manual", defaults to our site
170  *       via project.h #define
171  *     - savearg now embeds option names in help links
172  *
173  *    Revision 1.45  2002/04/24 02:11:54  oes
174  *    Jon's multiple AF patch: Allow up to MAX_AF_FILES actionsfile options
175  *
176  *    Revision 1.44  2002/04/08 20:37:13  swa
177  *    fixed JB spelling
178  *
179  *    Revision 1.43  2002/04/08 20:36:50  swa
180  *    fixed JB spelling
181  *
182  *    Revision 1.42  2002/04/05 15:50:15  oes
183  *    fix for invalid HTML proxy_args
184  *
185  *    Revision 1.41  2002/03/31 17:19:00  jongfoster
186  *    Win32 only: Enabling STRICT to fix a VC++ compile warning.
187  *
188  *    Revision 1.40  2002/03/26 22:29:55  swa
189  *    we have a new homepage!
190  *
191  *    Revision 1.39  2002/03/24 13:25:43  swa
192  *    name change related issues
193  *
194  *    Revision 1.38  2002/03/24 13:05:48  jongfoster
195  *    Renaming re_filterfile to filterfile
196  *
197  *    Revision 1.37  2002/03/16 23:54:06  jongfoster
198  *    Adding graceful termination feature, to help look for memory leaks.
199  *    If you enable this (which, by design, has to be done by hand
200  *    editing config.h) and then go to http://i.j.b/die, then the program
201  *    will exit cleanly after the *next* request.  It should free all the
202  *    memory that was used.
203  *
204  *    Revision 1.36  2002/03/13 00:27:05  jongfoster
205  *    Killing warnings
206  *
207  *    Revision 1.35  2002/03/07 03:52:44  oes
208  *    Set logging to tty for --no-daemon mode
209  *
210  *    Revision 1.34  2002/03/06 23:14:35  jongfoster
211  *    Trivial cosmetic changes to make function comments easier to find.
212  *
213  *    Revision 1.33  2002/03/05 04:52:42  oes
214  *    Deleted non-errlog debugging code
215  *
216  *    Revision 1.32  2002/03/04 18:24:53  oes
217  *    Re-enabled output of unknown config directive hash
218  *
219  *    Revision 1.31  2002/03/03 15:07:20  oes
220  *    Re-enabled automatic config reloading
221  *
222  *    Revision 1.30  2002/01/22 23:31:43  jongfoster
223  *    Replacing strsav() with string_append()
224  *
225  *    Revision 1.29  2002/01/17 21:02:30  jongfoster
226  *    Moving all our URL and URL pattern parsing code to urlmatch.c.
227  *
228  *    Renaming free_url to free_url_spec, since it frees a struct url_spec.
229  *
230  *    Revision 1.28  2001/12/30 14:07:32  steudten
231  *    - Add signal handling (unix)
232  *    - Add SIGHUP handler (unix)
233  *    - Add creation of pidfile (unix)
234  *    - Add action 'top' in rc file (RH)
235  *    - Add entry 'SIGNALS' to manpage
236  *    - Add exit message to logfile (unix)
237  *
238  *    Revision 1.27  2001/11/07 00:02:13  steudten
239  *    Add line number in error output for lineparsing for
240  *    actionsfile and configfile.
241  *    Special handling for CLF added.
242  *
243  *    Revision 1.26  2001/11/05 21:41:43  steudten
244  *    Add changes to be a real daemon just for unix os.
245  *    (change cwd to /, detach from controlling tty, set
246  *    process group and session leader to the own process.
247  *    Add DBG() Macro.
248  *    Add some fatal-error log message for failed malloc().
249  *    Add '-d' if compiled with 'configure --with-debug' to
250  *    enable debug output.
251  *
252  *    Revision 1.25  2001/10/25 03:40:48  david__schmidt
253  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
254  *    threads to call select() simultaneously.  So, it's time to do a real, live,
255  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
256  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
257  *
258  *    Revision 1.24  2001/10/23 21:40:30  jongfoster
259  *    Added support for enable-edit-actions and enable-remote-toggle config
260  *    file options.
261  *
262  *    Revision 1.23  2001/10/07 15:36:00  oes
263  *    Introduced new config option "buffer-limit"
264  *
265  *    Revision 1.22  2001/09/22 16:36:59  jongfoster
266  *    Removing unused parameter fs from read_config_line()
267  *
268  *    Revision 1.21  2001/09/16 17:10:43  jongfoster
269  *    Moving function savearg() here, since it was the only thing left in
270  *    showargs.c.
271  *
272  *    Revision 1.20  2001/07/30 22:08:36  jongfoster
273  *    Tidying up #defines:
274  *    - All feature #defines are now of the form FEATURE_xxx
275  *    - Permanently turned off WIN_GUI_EDIT
276  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
277  *
278  *    Revision 1.19  2001/07/15 17:45:16  jongfoster
279  *    Removing some unused #includes
280  *
281  *    Revision 1.18  2001/07/13 14:01:14  oes
282  *     - Removed all #ifdef PCRS
283  *     - Removed vim-settings
284  *
285  *    Revision 1.17  2001/06/29 13:31:03  oes
286  *    - Improved comments
287  *    - Fixed (actionsfile) and sorted hashes
288  *    - Introduced admin_address and proxy-info-url
289  *      as config parameters
290  *    - Renamed config->proxy_args_invocation (which didn't have
291  *      the invocation but the options!) to config->proxy_args
292  *    - Various adaptions
293  *    - Removed logentry from cancelled commit
294  *
295  *    Revision 1.16  2001/06/09 10:55:28  jongfoster
296  *    Changing BUFSIZ ==> BUFFER_SIZE
297  *
298  *    Revision 1.15  2001/06/07 23:13:40  jongfoster
299  *    Merging ACL and forward files into config file.
300  *    Cosmetic: Sorting config file options alphabetically.
301  *    Cosmetic: Adding brief syntax comments to config file options.
302  *
303  *    Revision 1.14  2001/06/07 14:46:25  joergs
304  *    Missing make_path() added for re_filterfile.
305  *
306  *    Revision 1.13  2001/06/05 22:33:54  jongfoster
307  *
308  *    Fixed minor memory leak.
309  *    Also now uses make_path to prepend the pathnames.
310  *
311  *    Revision 1.12  2001/06/05 20:04:09  jongfoster
312  *    Now uses _snprintf() in place of snprintf() under Win32.
313  *
314  *    Revision 1.11  2001/06/04 18:31:58  swa
315  *    files are now prefixed with either `confdir' or `logdir'.
316  *    `make redhat-dist' replaces both entries confdir and logdir
317  *    with redhat values
318  *
319  *    Revision 1.10  2001/06/03 19:11:54  oes
320  *    introduced confdir option
321  *
322  *    Revision 1.9  2001/06/01 20:06:24  jongfoster
323  *    Removed support for "tinygif" option - moved to actions file.
324  *
325  *    Revision 1.8  2001/05/31 21:27:13  jongfoster
326  *    Removed many options from the config file and into the
327  *    "actions" file: add_forwarded, suppress_vanilla_wafer,
328  *    wafer, add_header, user_agent, referer, from
329  *    Also globally replaced "permission" with "action".
330  *
331  *    Revision 1.7  2001/05/29 09:50:24  jongfoster
332  *    Unified blocklist/imagelist/permissionslist.
333  *    File format is still under discussion, but the internal changes
334  *    are (mostly) done.
335  *
336  *    Also modified interceptor behaviour:
337  *    - We now intercept all URLs beginning with one of the following
338  *      prefixes (and *only* these prefixes):
339  *        * http://i.j.b/
340  *        * http://ijbswa.sf.net/config/
341  *        * http://ijbswa.sourceforge.net/config/
342  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
343  *    - Internal changes so that intercepted and fast redirect pages
344  *      are not replaced with an image.
345  *    - Interceptors now have the option to send a binary page direct
346  *      to the client. (i.e. ijb-send-banner uses this)
347  *    - Implemented show-url-info interceptor.  (Which is why I needed
348  *      the above interceptors changes - a typical URL is
349  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
350  *      The previous mechanism would not have intercepted that, and
351  *      if it had been intercepted then it then it would have replaced
352  *      it with an image.)
353  *
354  *    Revision 1.6  2001/05/26 00:28:36  jongfoster
355  *    Automatic reloading of config file.
356  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
357  *    Most of the global variables have been moved to a new
358  *    struct configuration_spec, accessed through csp->config->globalname
359  *    Most of the globals remaining are used by the Win32 GUI.
360  *
361  *    Revision 1.5  2001/05/25 22:34:30  jongfoster
362  *    Hard tabs->Spaces
363  *
364  *    Revision 1.4  2001/05/22 18:46:04  oes
365  *
366  *    - Enabled filtering banners by size rather than URL
367  *      by adding patterns that replace all standard banner
368  *      sizes with the "Junkbuster" gif to the re_filterfile
369  *
370  *    - Enabled filtering WebBugs by providing a pattern
371  *      which kills all 1x1 images
372  *
373  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
374  *      which is selected by the (nonstandard and therefore
375  *      capital) letter 'U' in the option string.
376  *      It causes the quantifiers to be ungreedy by default.
377  *      Appending a ? turns back to greedy (!).
378  *
379  *    - Added a new interceptor ijb-send-banner, which
380  *      sends back the "Junkbuster" gif. Without imagelist or
381  *      MSIE detection support, or if tinygif = 1, or the
382  *      URL isn't recognized as an imageurl, a lame HTML
383  *      explanation is sent instead.
384  *
385  *    - Added new feature, which permits blocking remote
386  *      script redirects and firing back a local redirect
387  *      to the browser.
388  *      The feature is conditionally compiled, i.e. it
389  *      can be disabled with --disable-fast-redirects,
390  *      plus it must be activated by a "fast-redirects"
391  *      line in the config file, has its own log level
392  *      and of course wants to be displayed by show-proxy-args
393  *      Note: Boy, all the #ifdefs in 1001 locations and
394  *      all the fumbling with configure.in and acconfig.h
395  *      were *way* more work than the feature itself :-(
396  *
397  *    - Because a generic redirect template was needed for
398  *      this, tinygif = 3 now uses the same.
399  *
400  *    - Moved GIFs, and other static HTTP response templates
401  *      to project.h
402  *
403  *    - Some minor fixes
404  *
405  *    - Removed some >400 CRs again (Jon, you really worked
406  *      a lot! ;-)
407  *
408  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
409  *    Version 2.9.4 checkin.
410  *    - Merged popupfile and cookiefile, and added control over PCRS
411  *      filtering, in new "permissionsfile".
412  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
413  *      file error you now get a message box (in the Win32 GUI) rather
414  *      than the program exiting with no explanation.
415  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
416  *      skipping.
417  *    - Removed tabs from "config"
418  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
419  *    - Bumped up version number.
420  *
421  *    Revision 1.2  2001/05/17 23:01:01  oes
422  *     - Cleaned CRLF's from the sources and related files
423  *
424  *    Revision 1.1.1.1  2001/05/15 13:58:58  oes
425  *    Initial import of version 2.9.3 source tree
426  *
427  *
428  *********************************************************************/
429 \f
430
431 #include "config.h"
432
433 #include <stdio.h>
434 #include <sys/types.h>
435 #include <stdlib.h>
436 #include <string.h>
437 #include <signal.h>
438 #include <fcntl.h>
439 #include <errno.h>
440 #include <ctype.h>
441 #include <assert.h>
442
443 #ifdef _WIN32
444
445 # ifndef STRICT
446 #  define STRICT
447 # endif
448 # include <windows.h>
449
450 # include "win32.h"
451 # ifndef _WIN_CONSOLE
452 #  include "w32log.h"
453 # endif /* ndef _WIN_CONSOLE */
454
455 #else /* ifndef _WIN32 */
456
457 #ifndef __OS2__
458 # include <unistd.h>
459 # include <sys/wait.h>
460 #endif
461 # include <sys/time.h>
462 # include <sys/stat.h>
463 # include <signal.h>
464
465 #endif
466
467 #include "loadcfg.h"
468 #include "list.h"
469 #include "jcc.h"
470 #include "filters.h"
471 #include "loaders.h"
472 #include "miscutil.h"
473 #include "errlog.h"
474 #include "ssplit.h"
475 #include "encode.h"
476 #include "urlmatch.h"
477 #include "cgi.h"
478
479 const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
480
481 /*
482  * Fix a problem with Solaris.  There should be no effect on other
483  * platforms.
484  * Solaris's isspace() is a macro which uses it's argument directly
485  * as an array index.  Therefore we need to make sure that high-bit
486  * characters generate +ve values, and ideally we also want to make
487  * the argument match the declared parameter type of "int".
488  */
489 #define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
490 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
491
492 #ifdef FEATURE_TOGGLE
493 /* Privoxy is enabled by default. */
494 int global_toggle_state = 1;
495 #endif /* def FEATURE_TOGGLE */
496
497 /* The filename of the configfile */
498 const char *configfile  = NULL;
499
500 /*
501  * CGI functions will later need access to the invocation args,
502  * so we will make argc and argv global.
503  */
504 int Argc = 0;
505 const char **Argv = NULL;
506
507 static struct file_list *current_configfile = NULL;
508
509
510 /*
511  * This takes the "cryptic" hash of each keyword and aliases them to
512  * something a little more readable.  This also makes changing the
513  * hash values easier if they should change or the hash algorthm changes.
514  * Use the included "hash" program to find out what the hash will be
515  * for any string supplied on the command line.  (Or just put it in the
516  * config file and read the number from the error message in the log).
517  *
518  * Please keep this list sorted alphabetically (but with the Windows
519  * console and GUI specific options last).
520  */
521
522 #define hash_actions_file                1196306641ul /* "actionsfile" */
523 #define hash_accept_intercepted_requests 1513024973ul /* "accept-intercepted-requests" */
524 #define hash_admin_address               4112573064ul /* "admin-address" */
525 #define hash_allow_cgi_request_crunching  258915987ul /* "allow-cgi-request-crunching" */
526 #define hash_buffer_limit                1881726070ul /* "buffer-limit */
527 #define hash_confdir                        1978389ul /* "confdir" */
528 #define hash_debug                            78263ul /* "debug" */
529 #define hash_deny_access                 1227333715ul /* "deny-access" */
530 #define hash_enable_edit_actions         2517097536ul /* "enable-edit-actions" */
531 #define hash_enable_remote_toggle        2979744683ul /* "enable-remote-toggle" */
532 #define hash_enable_remote_http_toggle    110543988ul /* "enable-remote-http-toggle" */
533 #define hash_enforce_blocks              1862427469ul /* "enforce-blocks" */
534 #define hash_filterfile                   250887266ul /* "filterfile" */
535 #define hash_forward                        2029845ul /* "forward" */
536 #define hash_forward_socks4              3963965521ul /* "forward-socks4" */
537 #define hash_forward_socks4a             2639958518ul /* "forward-socks4a" */
538 #define hash_forward_socks5              3963965522ul /* "forward-socks5" */
539 #define hash_forwarded_connect_retries    101465292ul /* "forwarded-connect-retries" */
540 #define hash_jarfile                        2046641ul /* "jarfile" */
541 #define hash_listen_address              1255650842ul /* "listen-address" */
542 #define hash_logdir                          422889ul /* "logdir" */
543 #define hash_logfile                        2114766ul /* "logfile" */
544 #define hash_permit_access               3587953268ul /* "permit-access" */
545 #define hash_proxy_info_url              3903079059ul /* "proxy-info-url" */
546 #define hash_single_threaded             4250084780ul /* "single-threaded" */
547 #define hash_split_large_cgi_forms        671658948ul /* "split-large-cgi-forms" */
548 #define hash_suppress_blocklists         1948693308ul /* "suppress-blocklists" */
549 #define hash_templdir                      11067889ul /* "templdir" */
550 #define hash_toggle                          447966ul /* "toggle" */
551 #define hash_trust_info_url               430331967ul /* "trust-info-url" */
552 #define hash_trustfile                     56494766ul /* "trustfile" */
553 #define hash_usermanual                  1416668518ul /* "user-manual" */
554 #define hash_activity_animation          1817904738ul /* "activity-animation" */
555 #define hash_close_button_minimizes      3651284693ul /* "close-button-minimizes" */
556 #define hash_hide_console                2048809870ul /* "hide-console" */
557 #define hash_log_buffer_size             2918070425ul /* "log-buffer-size" */
558 #define hash_log_font_name               2866730124ul /* "log-font-name" */
559 #define hash_log_font_size               2866731014ul /* "log-font-size" */
560 #define hash_log_highlight_messages      4032101240ul /* "log-highlight-messages" */
561 #define hash_log_max_lines               2868344173ul /* "log-max-lines" */
562 #define hash_log_messages                2291744899ul /* "log-messages" */
563 #define hash_show_on_task_bar             215410365ul /* "show-on-task-bar" */
564
565
566 static void savearg(char *command, char *argument, struct configuration_spec * config);
567
568 /*********************************************************************
569  *
570  * Function    :  unload_configfile
571  *
572  * Description :  Free the config structure and all components.
573  *
574  * Parameters  :
575  *          1  :  data: struct configuration_spec to unload
576  *
577  * Returns     :  N/A
578  *
579  *********************************************************************/
580 static void unload_configfile (void * data)
581 {
582    struct configuration_spec * config = (struct configuration_spec *)data;
583    struct forward_spec *cur_fwd = config->forward;
584    int i;
585
586 #ifdef FEATURE_ACL
587    struct access_control_list *cur_acl = config->acl;
588
589    while (cur_acl != NULL)
590    {
591       struct access_control_list * next_acl = cur_acl->next;
592       free(cur_acl);
593       cur_acl = next_acl;
594    }
595    config->acl = NULL;
596 #endif /* def FEATURE_ACL */
597
598    while (cur_fwd != NULL)
599    {
600       struct forward_spec * next_fwd = cur_fwd->next;
601       free_url_spec(cur_fwd->url);
602
603       freez(cur_fwd->gateway_host);
604       freez(cur_fwd->forward_host);
605       free(cur_fwd);
606       cur_fwd = next_fwd;
607    }
608    config->forward = NULL;
609
610 #ifdef FEATURE_COOKIE_JAR
611    if ( NULL != config->jar )
612    {
613       fclose( config->jar );
614       config->jar = NULL;
615    }
616 #endif /* def FEATURE_COOKIE_JAR */
617
618    freez(config->confdir);
619    freez(config->logdir);
620    freez(config->templdir);
621
622    freez(config->haddr);
623    freez(config->logfile);
624
625    for (i = 0; i < MAX_AF_FILES; i++)
626    {
627       freez(config->actions_file_short[i]);
628       freez(config->actions_file[i]);
629       freez(config->re_filterfile_short[i]);
630       freez(config->re_filterfile[i]);
631    }
632
633    freez(config->admin_address);
634    freez(config->proxy_info_url);
635    freez(config->proxy_args);
636    freez(config->usermanual);
637
638 #ifdef FEATURE_COOKIE_JAR
639    freez(config->jarfile);
640 #endif /* def FEATURE_COOKIE_JAR */
641
642 #ifdef FEATURE_TRUST
643    freez(config->trustfile);
644    list_remove_all(config->trust_info);
645 #endif /* def FEATURE_TRUST */
646
647    for (i = 0; i < MAX_AF_FILES; i++)
648    {
649       freez(config->re_filterfile[i]);
650    }
651
652    freez(config);
653 }
654
655
656 #ifdef FEATURE_GRACEFUL_TERMINATION
657 /*********************************************************************
658  *
659  * Function    :  unload_current_config_file
660  *
661  * Description :  Unloads current config file - reset to state at
662  *                beginning of program.
663  *
664  * Parameters  :  None
665  *
666  * Returns     :  N/A
667  *
668  *********************************************************************/
669 void unload_current_config_file(void)
670 {
671    if (current_configfile)
672    {
673       current_configfile->unloader = unload_configfile;
674       current_configfile = NULL;
675    }
676 }
677 #endif
678
679
680 /*********************************************************************
681  *
682  * Function    :  load_config
683  *
684  * Description :  Load the config file and all parameters.
685  *
686  *                XXX: more than thousand lines long
687  *                and thus in serious need of refactoring.
688  *
689  * Parameters  :  None
690  *
691  * Returns     :  The configuration_spec, or NULL on error.
692  *
693  *********************************************************************/
694 struct configuration_spec * load_config(void)
695 {
696    char buf[BUFFER_SIZE];
697    char *p, *q;
698    FILE *configfp = NULL;
699    struct configuration_spec * config = NULL;
700    struct client_state * fake_csp;
701    struct file_list *fs;
702    unsigned long linenum = 0;
703    int i;
704    char *logfile = NULL;
705
706    if ( !check_file_changed(current_configfile, configfile, &fs))
707    {
708       /* No need to load */
709       return ((struct configuration_spec *)current_configfile->f);
710    }
711    if (!fs)
712    {
713       log_error(LOG_LEVEL_FATAL, "can't check configuration file '%s':  %E",
714                 configfile);
715    }
716
717    if (NULL != current_configfile)
718    {
719       log_error(LOG_LEVEL_INFO, "Reloading configuration file '%s'", configfile);
720    }
721
722 #ifdef FEATURE_TOGGLE
723    global_toggle_state      = 1;
724 #endif /* def FEATURE_TOGGLE */
725
726    fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
727
728    if (config==NULL)
729    {
730       freez(fs->filename);
731       freez(fs);
732       log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
733       /* Never get here - LOG_LEVEL_FATAL causes program exit */
734    }
735
736    /*
737     * This is backwards from how it's usually done.
738     * Following the usual pattern, "fs" would be stored in a member
739     * variable in "csp", and then we'd access "config" from "fs->f",
740     * using a cast.  However, "config" is used so often that a
741     * cast each time would be very ugly, and the extra indirection
742     * would waste CPU cycles.  Therefore we store "config" in
743     * "csp->config", and "fs" in "csp->config->config_file_list".
744     */
745    config->config_file_list = fs;
746
747    /*
748     * Set to defaults
749     */
750    config->multi_threaded            = 1;
751    config->hport                     = HADDR_PORT;
752    config->buffer_limit              = 4096 * 1024;
753    config->usermanual                = strdup(USER_MANUAL_URL);
754    config->proxy_args                = strdup("");
755    config->forwarded_connect_retries = 0;
756    config->feature_flags            &= ~RUNTIME_FEATURE_CGI_TOGGLE;
757    config->feature_flags            &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
758    config->feature_flags            &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
759
760    if ((configfp = fopen(configfile, "r")) == NULL)
761    {
762       log_error(LOG_LEVEL_FATAL, "can't open configuration file '%s':  %E",
763               configfile);
764       /* Never get here - LOG_LEVEL_FATAL causes program exit */
765    }
766
767    while (read_config_line(buf, sizeof(buf), configfp, &linenum) != NULL)
768    {
769       char cmd[BUFFER_SIZE];
770       char arg[BUFFER_SIZE];
771       char tmp[BUFFER_SIZE];
772 #ifdef FEATURE_ACL
773       struct access_control_list *cur_acl;
774 #endif /* def FEATURE_ACL */
775       struct forward_spec *cur_fwd;
776       int vec_count;
777       char *vec[3];
778       unsigned long directive_hash;
779
780       strlcpy(tmp, buf, sizeof(tmp));
781
782       /* Copy command (i.e. up to space or tab) into cmd */
783       p = buf;
784       q = cmd;
785       while (*p && (*p != ' ') && (*p != '\t'))
786       {
787          *q++ = *p++;
788       }
789       *q = '\0';
790
791       /* Skip over the whitespace in buf */
792       while (*p && ((*p == ' ') || (*p == '\t')))
793       {
794          p++;
795       }
796
797       /* Copy the argument into arg */
798       strlcpy(arg, p, sizeof(arg));
799
800       /* Should never happen, but check this anyway */
801       if (*cmd == '\0')
802       {
803          continue;
804       }
805
806       /* Make sure the command field is lower case */
807       for (p=cmd; *p; p++)
808       {
809          if (ijb_isupper(*p))
810          {
811             *p = (char)ijb_tolower(*p);
812          }
813       }
814
815       /* Save the argument for show-proxy-args */
816       savearg(cmd, arg, config);
817
818       directive_hash = hash_string(cmd);
819       switch (directive_hash)
820       {
821 /* *************************************************************************
822  * actionsfile actions-file-name
823  * In confdir by default
824  * *************************************************************************/
825          case hash_actions_file :
826             i = 0;
827             while ((i < MAX_AF_FILES) && (NULL != config->actions_file[i]))
828             {
829                i++;
830             }
831
832             if (i >= MAX_AF_FILES)
833             {
834                log_error(LOG_LEVEL_FATAL, "Too many 'actionsfile' directives in config file - limit is %d.\n"
835                   "(You can increase this limit by changing MAX_AF_FILES in project.h and recompiling).",
836                   MAX_AF_FILES);
837             }
838             config->actions_file_short[i] = strdup(arg);
839             config->actions_file[i] = make_path(config->confdir, arg);
840
841             continue;
842 /* *************************************************************************
843  * accept-intercepted-requests
844  * *************************************************************************/
845          case hash_accept_intercepted_requests:
846             if ((*arg != '\0') && (0 != atoi(arg)))
847             {
848                config->feature_flags |= RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
849             }
850             else
851             {
852                config->feature_flags &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
853             }
854             continue;
855
856 /* *************************************************************************
857  * admin-address email-address
858  * *************************************************************************/
859          case hash_admin_address :
860             freez(config->admin_address);
861             config->admin_address = strdup(arg);
862             continue;
863
864 /* *************************************************************************
865  * allow-cgi-request-crunching
866  * *************************************************************************/
867          case hash_allow_cgi_request_crunching:
868             if ((*arg != '\0') && (0 != atoi(arg)))
869             {
870                config->feature_flags |= RUNTIME_FEATURE_CGI_CRUNCHING;
871             }
872             else
873             {
874                config->feature_flags &= ~RUNTIME_FEATURE_CGI_CRUNCHING;
875             }
876             continue;
877
878 /* *************************************************************************
879  * buffer-limit n
880  * *************************************************************************/
881          case hash_buffer_limit :
882             config->buffer_limit = (size_t)(1024 * atoi(arg));
883             continue;
884
885 /* *************************************************************************
886  * confdir directory-name
887  * *************************************************************************/
888          case hash_confdir :
889             freez(config->confdir);
890             config->confdir = make_path( NULL, arg);
891             continue;
892
893 /* *************************************************************************
894  * debug n
895  * Specifies debug level, multiple values are ORed together.
896  * *************************************************************************/
897          case hash_debug :
898             config->debug |= atoi(arg);
899             continue;
900
901 /* *************************************************************************
902  * deny-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
903  * *************************************************************************/
904 #ifdef FEATURE_ACL
905          case hash_deny_access:
906             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
907
908             if ((vec_count != 1) && (vec_count != 2))
909             {
910                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
911                      "deny-access directive in configuration file.");
912                string_append(&config->proxy_args,
913                   "<br>\nWARNING: Wrong number of parameters for "
914                   "deny-access directive in configuration file.<br><br>\n");
915                continue;
916             }
917
918             /* allocate a new node */
919             cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
920
921             if (cur_acl == NULL)
922             {
923                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
924                /* Never get here - LOG_LEVEL_FATAL causes program exit */
925                continue;
926             }
927             cur_acl->action = ACL_DENY;
928
929             if (acl_addr(vec[0], cur_acl->src) < 0)
930             {
931                log_error(LOG_LEVEL_ERROR, "Invalid source address, port or netmask "
932                   "for deny-access directive in configuration file: \"%s\"", vec[0]);
933                string_append(&config->proxy_args,
934                   "<br>\nWARNING: Invalid source address, port or netmask "
935                   "for deny-access directive in configuration file: \"");
936                string_append(&config->proxy_args,
937                   vec[0]);
938                string_append(&config->proxy_args,
939                   "\"<br><br>\n");
940                freez(cur_acl);
941                continue;
942             }
943             if (vec_count == 2)
944             {
945                if (acl_addr(vec[1], cur_acl->dst) < 0)
946                {
947                   log_error(LOG_LEVEL_ERROR, "Invalid destination address, port or netmask "
948                      "for deny-access directive in configuration file: \"%s\"", vec[1]);
949                   string_append(&config->proxy_args,
950                      "<br>\nWARNING: Invalid destination address, port or netmask "
951                      "for deny-access directive in configuration file: \"");
952                   string_append(&config->proxy_args,
953                      vec[1]);
954                   string_append(&config->proxy_args,
955                      "\"<br><br>\n");
956                   freez(cur_acl);
957                   continue;
958                }
959             }
960
961             /*
962              * Add it to the list.  Note we reverse the list to get the
963              * behaviour the user expects.  With both the ACL and
964              * actions file, the last match wins.  However, the internal
965              * implementations are different:  The actions file is stored
966              * in the same order as the file, and scanned completely.
967              * With the ACL, we reverse the order as we load it, then
968              * when we scan it we stop as soon as we get a match.
969              */
970             cur_acl->next  = config->acl;
971             config->acl = cur_acl;
972
973             continue;
974 #endif /* def FEATURE_ACL */
975
976 /* *************************************************************************
977  * enable-edit-actions 0|1
978  * *************************************************************************/
979 #ifdef FEATURE_CGI_EDIT_ACTIONS
980          case hash_enable_edit_actions:
981             if ((*arg != '\0') && (0 != atoi(arg)))
982             {
983                config->feature_flags |= RUNTIME_FEATURE_CGI_EDIT_ACTIONS;
984             }
985             else
986             {
987                config->feature_flags &= ~RUNTIME_FEATURE_CGI_EDIT_ACTIONS;
988             }
989             continue;
990 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
991
992 /* *************************************************************************
993  * enable-remote-toggle 0|1
994  * *************************************************************************/
995 #ifdef FEATURE_CGI_EDIT_ACTIONS
996          case hash_enable_remote_toggle:
997             if ((*arg != '\0') && (0 != atoi(arg)))
998             {
999                config->feature_flags |= RUNTIME_FEATURE_CGI_TOGGLE;
1000             }
1001             else
1002             {
1003                config->feature_flags &= ~RUNTIME_FEATURE_CGI_TOGGLE;
1004             }
1005             continue;
1006 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
1007
1008 /* *************************************************************************
1009  * enable-remote-http-toggle 0|1
1010  * *************************************************************************/
1011          case hash_enable_remote_http_toggle:
1012             if ((*arg != '\0') && (0 != atoi(arg)))
1013             {
1014                config->feature_flags |= RUNTIME_FEATURE_HTTP_TOGGLE;
1015             }
1016             else
1017             {
1018                config->feature_flags &= ~RUNTIME_FEATURE_HTTP_TOGGLE;
1019             }
1020             continue;
1021
1022 /* *************************************************************************
1023  * hash_enforce_blocks 0|1
1024  * *************************************************************************/
1025 #ifdef FEATURE_FORCE_LOAD
1026          case hash_enforce_blocks:
1027             if ((*arg != '\0') && (0 != atoi(arg)))
1028             {
1029                config->feature_flags |= RUNTIME_FEATURE_ENFORCE_BLOCKS;
1030             }
1031             else
1032             {
1033                config->feature_flags &= ~RUNTIME_FEATURE_ENFORCE_BLOCKS;
1034             }
1035             continue;
1036 #endif /* def FEATURE_FORCE_LOAD */
1037
1038 /* *************************************************************************
1039  * filterfile file-name
1040  * In confdir by default.
1041  * *************************************************************************/
1042          case hash_filterfile :
1043             i = 0;
1044             while ((i < MAX_AF_FILES) && (NULL != config->re_filterfile[i]))
1045             {
1046                i++;
1047             }
1048
1049             if (i >= MAX_AF_FILES)
1050             {
1051                log_error(LOG_LEVEL_FATAL, "Too many 'filterfile' directives in config file - limit is %d.\n"
1052                   "(You can increase this limit by changing MAX_AF_FILES in project.h and recompiling).",
1053                   MAX_AF_FILES);
1054             }
1055             config->re_filterfile_short[i] = strdup(arg);
1056             config->re_filterfile[i] = make_path(config->confdir, arg);
1057
1058             continue;
1059
1060 /* *************************************************************************
1061  * forward url-pattern (.|http-proxy-host[:port])
1062  * *************************************************************************/
1063          case hash_forward:
1064             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
1065
1066             if (vec_count != 2)
1067             {
1068                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for forward "
1069                      "directive in configuration file.");
1070                string_append(&config->proxy_args,
1071                   "<br>\nWARNING: Wrong number of parameters for "
1072                   "forward directive in configuration file.");
1073                continue;
1074             }
1075
1076             /* allocate a new node */
1077             cur_fwd = zalloc(sizeof(*cur_fwd));
1078             if (cur_fwd == NULL)
1079             {
1080                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
1081                /* Never get here - LOG_LEVEL_FATAL causes program exit */
1082                continue;
1083             }
1084
1085             cur_fwd->type = SOCKS_NONE;
1086
1087             /* Save the URL pattern */
1088             if (create_url_spec(cur_fwd->url, vec[0]))
1089             {
1090                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward "
1091                      "directive in configuration file.");
1092                string_append(&config->proxy_args,
1093                   "<br>\nWARNING: Bad URL specifier for "
1094                   "forward directive in configuration file.");
1095                continue;
1096             }
1097
1098             /* Parse the parent HTTP proxy host:port */
1099             p = vec[1];
1100
1101             if (strcmp(p, ".") != 0)
1102             {
1103                cur_fwd->forward_host = strdup(p);
1104
1105                if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1106                {
1107                   *p++ = '\0';
1108                   cur_fwd->forward_port = atoi(p);
1109                }
1110
1111                if (cur_fwd->forward_port <= 0)
1112                {
1113                   cur_fwd->forward_port = 8000;
1114                }
1115             }
1116
1117             /* Add to list. */
1118             cur_fwd->next = config->forward;
1119             config->forward = cur_fwd;
1120
1121             continue;
1122
1123 /* *************************************************************************
1124  * forward-socks4 url-pattern socks-proxy[:port] (.|http-proxy[:port])
1125  * *************************************************************************/
1126          case hash_forward_socks4:
1127             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
1128
1129             if (vec_count != 3)
1130             {
1131                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
1132                      "forward-socks4 directive in configuration file.");
1133                string_append(&config->proxy_args,
1134                   "<br>\nWARNING: Wrong number of parameters for "
1135                   "forward-socks4 directive in configuration file.");
1136                continue;
1137             }
1138
1139             /* allocate a new node */
1140             cur_fwd = zalloc(sizeof(*cur_fwd));
1141             if (cur_fwd == NULL)
1142             {
1143                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
1144                /* Never get here - LOG_LEVEL_FATAL causes program exit */
1145                continue;
1146             }
1147
1148             cur_fwd->type = SOCKS_4;
1149
1150             /* Save the URL pattern */
1151             if (create_url_spec(cur_fwd->url, vec[0]))
1152             {
1153                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4 "
1154                      "directive in configuration file.");
1155                string_append(&config->proxy_args,
1156                   "<br>\nWARNING: Bad URL specifier for "
1157                   "forward-socks4 directive in configuration file.");
1158                continue;
1159             }
1160
1161             /* Parse the SOCKS proxy host[:port] */
1162             p = vec[1];
1163
1164             if (strcmp(p, ".") != 0)
1165             {
1166                cur_fwd->gateway_host = strdup(p);
1167
1168                if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
1169                {
1170                   *p++ = '\0';
1171                   cur_fwd->gateway_port = atoi(p);
1172                }
1173                if (cur_fwd->gateway_port <= 0)
1174                {
1175                   cur_fwd->gateway_port = 1080;
1176                }
1177             }
1178
1179             /* Parse the parent HTTP proxy host[:port] */
1180             p = vec[2];
1181
1182             if (strcmp(p, ".") != 0)
1183             {
1184                cur_fwd->forward_host = strdup(p);
1185
1186                if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1187                {
1188                   *p++ = '\0';
1189                   cur_fwd->forward_port = atoi(p);
1190                }
1191
1192                if (cur_fwd->forward_port <= 0)
1193                {
1194                   cur_fwd->forward_port = 8000;
1195                }
1196             }
1197
1198             /* Add to list. */
1199             cur_fwd->next = config->forward;
1200             config->forward = cur_fwd;
1201
1202             continue;
1203
1204 /* *************************************************************************
1205  * forward-socks4a url-pattern socks-proxy[:port] (.|http-proxy[:port])
1206  * *************************************************************************/
1207          case hash_forward_socks4a:
1208          case hash_forward_socks5:
1209             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
1210
1211             if (vec_count != 3)
1212             {
1213                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
1214                      "forward-socks4a directive in configuration file.");
1215                string_append(&config->proxy_args,
1216                   "<br>\nWARNING: Wrong number of parameters for "
1217                   "forward-socks4a directive in configuration file.");
1218                continue;
1219             }
1220
1221             /* allocate a new node */
1222             cur_fwd = zalloc(sizeof(*cur_fwd));
1223             if (cur_fwd == NULL)
1224             {
1225                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
1226                /* Never get here - LOG_LEVEL_FATAL causes program exit */
1227                continue;
1228             }
1229
1230             if (directive_hash == hash_forward_socks4a)
1231             {
1232                cur_fwd->type = SOCKS_4A;
1233             }
1234             else
1235             {
1236                cur_fwd->type = SOCKS_5;
1237             }
1238
1239             /* Save the URL pattern */
1240             if (create_url_spec(cur_fwd->url, vec[0]))
1241             {
1242                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4a "
1243                      "directive in configuration file.");
1244                string_append(&config->proxy_args,
1245                   "<br>\nWARNING: Bad URL specifier for "
1246                   "forward-socks4a directive in configuration file.");
1247                continue;
1248             }
1249
1250             /* Parse the SOCKS proxy host[:port] */
1251             p = vec[1];
1252
1253             cur_fwd->gateway_host = strdup(p);
1254
1255             if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
1256             {
1257                *p++ = '\0';
1258                cur_fwd->gateway_port = atoi(p);
1259             }
1260             if (cur_fwd->gateway_port <= 0)
1261             {
1262                cur_fwd->gateway_port = 1080;
1263             }
1264
1265             /* Parse the parent HTTP proxy host[:port] */
1266             p = vec[2];
1267
1268             if (strcmp(p, ".") != 0)
1269             {
1270                cur_fwd->forward_host = strdup(p);
1271
1272                if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1273                {
1274                   *p++ = '\0';
1275                   cur_fwd->forward_port = atoi(p);
1276                }
1277
1278                if (cur_fwd->forward_port <= 0)
1279                {
1280                   cur_fwd->forward_port = 8000;
1281                }
1282             }
1283
1284             /* Add to list. */
1285             cur_fwd->next = config->forward;
1286             config->forward = cur_fwd;
1287
1288             continue;
1289
1290 /* *************************************************************************
1291  * forwarded-connect-retries n
1292  * *************************************************************************/
1293          case hash_forwarded_connect_retries :
1294             config->forwarded_connect_retries = atoi(arg);
1295             continue;
1296
1297 /* *************************************************************************
1298  * jarfile jar-file-name
1299  * In logdir by default
1300  * *************************************************************************/
1301 #ifdef FEATURE_COOKIE_JAR
1302          case hash_jarfile :
1303             freez(config->jarfile);
1304             config->jarfile = make_path(config->logdir, arg);
1305             continue;
1306 #endif /* def FEATURE_COOKIE_JAR */
1307
1308 /* *************************************************************************
1309  * listen-address [ip][:port]
1310  * *************************************************************************/
1311          case hash_listen_address :
1312             freez(config->haddr);
1313             config->haddr = strdup(arg);
1314             continue;
1315
1316 /* *************************************************************************
1317  * logdir directory-name
1318  * *************************************************************************/
1319          case hash_logdir :
1320             freez(config->logdir);
1321             config->logdir = make_path(NULL, arg);
1322             continue;
1323
1324 /* *************************************************************************
1325  * logfile log-file-name
1326  * In logdir by default
1327  * *************************************************************************/
1328          case hash_logfile :
1329             if (!no_daemon)
1330             {
1331                logfile = make_path(config->logdir, arg);
1332                if (NULL == logfile)
1333                {
1334                   log_error(LOG_LEVEL_FATAL, "Out of memory while creating logfile path");
1335                }
1336             }
1337             continue;
1338
1339 /* *************************************************************************
1340  * permit-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
1341  * *************************************************************************/
1342 #ifdef FEATURE_ACL
1343          case hash_permit_access:
1344             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
1345
1346             if ((vec_count != 1) && (vec_count != 2))
1347             {
1348                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
1349                      "permit-access directive in configuration file.");
1350                string_append(&config->proxy_args,
1351                   "<br>\nWARNING: Wrong number of parameters for "
1352                   "permit-access directive in configuration file.<br><br>\n");
1353
1354                continue;
1355             }
1356
1357             /* allocate a new node */
1358             cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
1359
1360             if (cur_acl == NULL)
1361             {
1362                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
1363                /* Never get here - LOG_LEVEL_FATAL causes program exit */
1364                continue;
1365             }
1366             cur_acl->action = ACL_PERMIT;
1367
1368             if (acl_addr(vec[0], cur_acl->src) < 0)
1369             {
1370                log_error(LOG_LEVEL_ERROR, "Invalid source address, port or netmask "
1371                   "for permit-access directive in configuration file: \"%s\"", vec[0]);
1372                string_append(&config->proxy_args,
1373                   "<br>\nWARNING: Invalid source address, port or netmask for "
1374                   "permit-access directive in configuration file: \"");
1375                string_append(&config->proxy_args,
1376                   vec[0]);
1377                string_append(&config->proxy_args,
1378                   "\"<br><br>\n");
1379                freez(cur_acl);
1380                continue;
1381             }
1382             if (vec_count == 2)
1383             {
1384                if (acl_addr(vec[1], cur_acl->dst) < 0)
1385                {
1386                   log_error(LOG_LEVEL_ERROR, "Invalid destination address, port or netmask "
1387                      "for permit-access directive in configuration file: \"%s\"", vec[1]);
1388                   string_append(&config->proxy_args,
1389                      "<br>\nWARNING: Invalid destination address, port or netmask for "
1390                      "permit-access directive in configuration file: \"");
1391                   string_append(&config->proxy_args,
1392                      vec[1]);
1393                   string_append(&config->proxy_args,
1394                      "\"<br><br>\n");
1395                   freez(cur_acl);
1396                   continue;
1397                }
1398             }
1399
1400             /*
1401              * Add it to the list.  Note we reverse the list to get the
1402              * behaviour the user expects.  With both the ACL and
1403              * actions file, the last match wins.  However, the internal
1404              * implementations are different:  The actions file is stored
1405              * in the same order as the file, and scanned completely.
1406              * With the ACL, we reverse the order as we load it, then
1407              * when we scan it we stop as soon as we get a match.
1408              */
1409             cur_acl->next  = config->acl;
1410             config->acl = cur_acl;
1411
1412             continue;
1413 #endif /* def FEATURE_ACL */
1414
1415 /* *************************************************************************
1416  * proxy-info-url url
1417  * *************************************************************************/
1418          case hash_proxy_info_url :
1419             freez(config->proxy_info_url);
1420             config->proxy_info_url = strdup(arg);
1421             continue;
1422
1423 /* *************************************************************************
1424  * single-threaded
1425  * *************************************************************************/
1426          case hash_single_threaded :
1427             config->multi_threaded = 0;
1428             continue;
1429
1430 /* *************************************************************************
1431  * split-large-cgi-forms
1432  * *************************************************************************/
1433          case hash_split_large_cgi_forms :
1434             if ((*arg != '\0') && (0 != atoi(arg)))
1435             {
1436                config->feature_flags |= RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
1437             }
1438             else
1439             {
1440                config->feature_flags &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
1441             }
1442             continue;
1443
1444 /* *************************************************************************
1445  * templdir directory-name
1446  * *************************************************************************/
1447          case hash_templdir :
1448             freez(config->templdir);
1449             config->templdir = make_path(NULL, arg);
1450             continue;
1451
1452 /* *************************************************************************
1453  * toggle (0|1)
1454  * *************************************************************************/
1455 #ifdef FEATURE_TOGGLE
1456          case hash_toggle :
1457             global_toggle_state = atoi(arg);
1458             continue;
1459 #endif /* def FEATURE_TOGGLE */
1460
1461 /* *************************************************************************
1462  * trust-info-url url
1463  * *************************************************************************/
1464 #ifdef FEATURE_TRUST
1465          case hash_trust_info_url :
1466             enlist(config->trust_info, arg);
1467             continue;
1468 #endif /* def FEATURE_TRUST */
1469
1470 /* *************************************************************************
1471  * trustfile filename
1472  * (In confdir by default.)
1473  * *************************************************************************/
1474 #ifdef FEATURE_TRUST
1475          case hash_trustfile :
1476             freez(config->trustfile);
1477             config->trustfile = make_path(config->confdir, arg);
1478             continue;
1479 #endif /* def FEATURE_TRUST */
1480
1481 /* *************************************************************************
1482  * usermanual url
1483  * *************************************************************************/
1484          case hash_usermanual :
1485             freez(config->usermanual);
1486             config->usermanual = strdup(arg);
1487             continue;
1488
1489 /* *************************************************************************
1490  * Win32 Console options:
1491  * *************************************************************************/
1492
1493 /* *************************************************************************
1494  * hide-console
1495  * *************************************************************************/
1496 #ifdef _WIN_CONSOLE
1497          case hash_hide_console :
1498             hideConsole = 1;
1499             continue;
1500 #endif /*def _WIN_CONSOLE*/
1501
1502
1503 /* *************************************************************************
1504  * Win32 GUI options:
1505  * *************************************************************************/
1506
1507 #if defined(_WIN32) && ! defined(_WIN_CONSOLE)
1508 /* *************************************************************************
1509  * activity-animation (0|1)
1510  * *************************************************************************/
1511          case hash_activity_animation :
1512             g_bShowActivityAnimation = atoi(arg);
1513             continue;
1514
1515 /* *************************************************************************
1516  *  close-button-minimizes (0|1)
1517  * *************************************************************************/
1518          case hash_close_button_minimizes :
1519             g_bCloseHidesWindow = atoi(arg);
1520             continue;
1521
1522 /* *************************************************************************
1523  * log-buffer-size (0|1)
1524  * *************************************************************************/
1525          case hash_log_buffer_size :
1526             g_bLimitBufferSize = atoi(arg);
1527             continue;
1528
1529 /* *************************************************************************
1530  * log-font-name fontnane
1531  * *************************************************************************/
1532          case hash_log_font_name :
1533             strcpy( g_szFontFaceName, arg );
1534             continue;
1535
1536 /* *************************************************************************
1537  * log-font-size n
1538  * *************************************************************************/
1539          case hash_log_font_size :
1540             g_nFontSize = atoi(arg);
1541             continue;
1542
1543 /* *************************************************************************
1544  * log-highlight-messages (0|1)
1545  * *************************************************************************/
1546          case hash_log_highlight_messages :
1547             g_bHighlightMessages = atoi(arg);
1548             continue;
1549
1550 /* *************************************************************************
1551  * log-max-lines n
1552  * *************************************************************************/
1553          case hash_log_max_lines :
1554             g_nMaxBufferLines = atoi(arg);
1555             continue;
1556
1557 /* *************************************************************************
1558  * log-messages (0|1)
1559  * *************************************************************************/
1560          case hash_log_messages :
1561             g_bLogMessages = atoi(arg);
1562             continue;
1563
1564 /* *************************************************************************
1565  * show-on-task-bar (0|1)
1566  * *************************************************************************/
1567          case hash_show_on_task_bar :
1568             g_bShowOnTaskBar = atoi(arg);
1569             continue;
1570
1571 #endif /* defined(_WIN32) && ! defined(_WIN_CONSOLE) */
1572
1573
1574 /* *************************************************************************
1575  * Warnings about unsupported features
1576  * *************************************************************************/
1577 #ifndef FEATURE_ACL
1578          case hash_deny_access:
1579 #endif /* ndef FEATURE_ACL */
1580 #ifndef FEATURE_CGI_EDIT_ACTIONS
1581          case hash_enable_edit_actions:
1582          case hash_enable_remote_toggle:
1583 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
1584 #ifndef FEATURE_COOKIE_JAR
1585          case hash_jarfile :
1586 #endif /* ndef FEATURE_COOKIE_JAR */
1587 #ifndef FEATURE_ACL
1588          case hash_permit_access:
1589 #endif /* ndef FEATURE_ACL */
1590 #ifndef FEATURE_TOGGLE
1591          case hash_toggle :
1592 #endif /* ndef FEATURE_TOGGLE */
1593 #ifndef FEATURE_TRUST
1594          case hash_trustfile :
1595          case hash_trust_info_url :
1596 #endif /* ndef FEATURE_TRUST */
1597
1598 #ifndef _WIN_CONSOLE
1599          case hash_hide_console :
1600 #endif /* ndef _WIN_CONSOLE */
1601
1602 #if defined(_WIN_CONSOLE) || ! defined(_WIN32)
1603          case hash_activity_animation :
1604          case hash_close_button_minimizes :
1605          case hash_log_buffer_size :
1606          case hash_log_font_name :
1607          case hash_log_font_size :
1608          case hash_log_highlight_messages :
1609          case hash_log_max_lines :
1610          case hash_log_messages :
1611          case hash_show_on_task_bar :
1612 #endif /* defined(_WIN_CONSOLE) || ! defined(_WIN32) */
1613             /* These warnings are annoying - so hide them. -- Jon */
1614             /* log_error(LOG_LEVEL_INFO, "Unsupported directive \"%s\" ignored.", cmd); */
1615             continue;
1616
1617 /* *************************************************************************/
1618          default :
1619 /* *************************************************************************/
1620             /*
1621              * I decided that I liked this better as a warning than an
1622              * error.  To change back to an error, just change log level
1623              * to LOG_LEVEL_FATAL.
1624              */
1625             log_error(LOG_LEVEL_ERROR, "Ignoring unrecognized directive '%s' (%luul) in line %lu "
1626                   "in configuration file (%s).",  buf, hash_string(cmd), linenum, configfile);
1627             string_append(&config->proxy_args,
1628                " <strong class='warning'>Warning: ignored unrecognized directive above.</strong><br>");
1629             continue;
1630
1631 /* *************************************************************************/
1632       } /* end switch( hash_string(cmd) ) */
1633    } /* end while ( read_config_line(...) ) */
1634
1635    fclose(configfp);
1636
1637    set_debug_level(config->debug);
1638
1639    freez(config->logfile);
1640
1641    if (!no_daemon)
1642    {
1643       if (NULL != logfile)
1644       {
1645          config->logfile = logfile;
1646          init_error_log(Argv[0], config->logfile);
1647       }
1648       else
1649       {
1650          disable_logging();
1651       }
1652    }
1653
1654    if (NULL == config->proxy_args)
1655    {
1656       log_error(LOG_LEVEL_FATAL, "Out of memory loading config - insufficient memory for config->proxy_args");
1657    }
1658
1659    if (config->actions_file[0])
1660    {
1661       add_loader(load_actions_file, config);
1662    }
1663
1664    if (config->re_filterfile)
1665    {
1666       add_loader(load_re_filterfile, config);
1667    }
1668
1669 #ifdef FEATURE_TRUST
1670    if (config->trustfile)
1671    {
1672       add_loader(load_trustfile, config);
1673    }
1674 #endif /* def FEATURE_TRUST */
1675
1676 #ifdef FEATURE_COOKIE_JAR
1677    if ( NULL != config->jarfile )
1678    {
1679       if ( NULL == (config->jar = fopen(config->jarfile, "a")) )
1680       {
1681          log_error(LOG_LEVEL_FATAL, "can't open jarfile '%s': %E", config->jarfile);
1682          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1683       }
1684       setbuf(config->jar, NULL);
1685    }
1686 #endif /* def FEATURE_COOKIE_JAR */
1687
1688    if ( NULL == config->haddr )
1689    {
1690       config->haddr = strdup( HADDR_DEFAULT );
1691    }
1692
1693    if ( NULL != config->haddr )
1694    {
1695       if (NULL != (p = strchr(config->haddr, ':')))
1696       {
1697          *p++ = '\0';
1698          if (*p)
1699          {
1700             config->hport = atoi(p);
1701          }
1702       }
1703
1704       if (config->hport <= 0)
1705       {
1706          *--p = ':';
1707          log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
1708          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1709       }
1710       if (*config->haddr == '\0')
1711       {
1712          /*
1713           * Only the port specified. We stored it in config->hport
1714           * and don't need its text representation anymore.
1715           */
1716          freez(config->haddr);
1717       }
1718    }
1719
1720    /*
1721     * Want to run all the loaders once now.
1722     *
1723     * Need to set up a fake csp, so they can get to the config.
1724     */
1725    fake_csp = (struct client_state *) zalloc (sizeof(*fake_csp));
1726    fake_csp->config = config;
1727
1728    if (run_loader(fake_csp))
1729    {
1730       freez(fake_csp);
1731       log_error(LOG_LEVEL_FATAL, "A loader failed while loading config file. Exiting.");
1732       /* Never get here - LOG_LEVEL_FATAL causes program exit */
1733    }
1734    freez(fake_csp);
1735
1736 /* FIXME: this is a kludge for win32 */
1737 #if defined(_WIN32) && !defined (_WIN_CONSOLE)
1738
1739    g_default_actions_file  = config->actions_file[1]; /* FIXME Hope this is default.action */
1740    g_user_actions_file = config->actions_file[2]; /* FIXME Hope this is user.action */
1741    g_re_filterfile    = config->re_filterfile[0]; /* FIXME Hope this is default.filter */
1742
1743 #ifdef FEATURE_TRUST
1744    g_trustfile        = config->trustfile;
1745 #endif /* def FEATURE_TRUST */
1746
1747
1748 #endif /* defined(_WIN32) && !defined (_WIN_CONSOLE) */
1749 /* FIXME: end kludge */
1750
1751
1752    config->need_bind = 1;
1753
1754    if (current_configfile)
1755    {
1756       struct configuration_spec * oldcfg = (struct configuration_spec *)
1757                                            current_configfile->f;
1758       /*
1759        * Check if config->haddr,hport == oldcfg->haddr,hport
1760        *
1761        * The following could be written more compactly as a single,
1762        * (unreadably long) if statement.
1763        */
1764       config->need_bind = 0;
1765       if (config->hport != oldcfg->hport)
1766       {
1767          config->need_bind = 1;
1768       }
1769       else if (config->haddr == NULL)
1770       {
1771          if (oldcfg->haddr != NULL)
1772          {
1773             config->need_bind = 1;
1774          }
1775       }
1776       else if (oldcfg->haddr == NULL)
1777       {
1778          config->need_bind = 1;
1779       }
1780       else if (0 != strcmp(config->haddr, oldcfg->haddr))
1781       {
1782          config->need_bind = 1;
1783       }
1784
1785       current_configfile->unloader = unload_configfile;
1786    }
1787
1788    fs->next = files->next;
1789    files->next = fs;
1790
1791    current_configfile = fs;
1792
1793    return (config);
1794 }
1795
1796
1797 /*********************************************************************
1798  *
1799  * Function    :  savearg
1800  *
1801  * Description :  Called from `load_config'.  It saves each non-empty
1802  *                and non-comment line from config into
1803  *                config->proxy_args.  This is used to create the
1804  *                show-proxy-args page.  On error, frees
1805  *                config->proxy_args and sets it to NULL
1806  *
1807  * Parameters  :
1808  *          1  :  command = config setting that was found
1809  *          2  :  argument = the setting's argument (if any)
1810  *          3  :  config = Configuration to save into.
1811  *
1812  * Returns     :  N/A
1813  *
1814  *********************************************************************/
1815 static void savearg(char *command, char *argument, struct configuration_spec * config)
1816 {
1817    char * buf;
1818    char * s;
1819
1820    assert(command);
1821    assert(*command);
1822    assert(argument);
1823
1824    /*
1825     * Add config option name embedded in
1826     * link to it's section in the user-manual
1827     */
1828    buf = strdup("\n<a href=\"");
1829    if (!strncmpic(config->usermanual, "file://", 7) ||
1830        !strncmpic(config->usermanual, "http", 4))
1831    {
1832       string_append(&buf, config->usermanual);
1833    }
1834    else
1835    {
1836       string_append(&buf, "http://");
1837       string_append(&buf, CGI_SITE_2_HOST);
1838       string_append(&buf, "/user-manual/");
1839    }
1840    string_append(&buf, CONFIG_HELP_PREFIX);
1841    string_join  (&buf, string_toupper(command));
1842    string_append(&buf, "\">");
1843    string_append(&buf, command);
1844    string_append(&buf, "</a> ");
1845
1846    if (NULL == buf)
1847    {
1848       freez(config->proxy_args);
1849       return;
1850    }
1851
1852    if ( (NULL != argument) && ('\0' != *argument) )
1853    {
1854       s = html_encode(argument);
1855       if (NULL == s)
1856       {
1857          freez(buf);
1858          freez(config->proxy_args);
1859          return;
1860       }
1861
1862       if (strncmpic(argument, "http://", 7) == 0)
1863       {
1864          string_append(&buf, "<a href=\"");
1865          string_append(&buf, s);
1866          string_append(&buf, "\">");
1867          string_join  (&buf, s);
1868          string_append(&buf, "</a>");
1869       }
1870       else
1871       {
1872          string_join  (&buf, s);
1873       }
1874    }
1875
1876    string_append(&buf, "<br>");
1877    string_join(&config->proxy_args, buf);
1878 }
1879
1880
1881 /*
1882   Local Variables:
1883   tab-width: 3
1884   end:
1885 */