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