Remove the unconditional block in get_http_time().
[privoxy.git] / cgi.c
1 const char cgi_rcs[] = "$Id: cgi.c,v 1.108 2008/05/26 17:30:53 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/cgi.c,v $
5  *
6  * Purpose     :  Declares functions to intercept request, generate
7  *                html or gif answers, and to compose HTTP resonses.
8  *                This only contains the framework functions, the
9  *                actual handler functions are declared elsewhere.
10  *                
11  *                Functions declared include:
12  * 
13  *
14  * Copyright   :  Written by and Copyright (C) 2001-2004, 2006-2008
15  *                the SourceForge Privoxy team. http://www.privoxy.org/
16  *
17  *                Based on the Internet Junkbuster originally written
18  *                by and Copyright (C) 1997 Anonymous Coders and 
19  *                Junkbusters Corporation.  http://www.junkbusters.com
20  *
21  *                This program is free software; you can redistribute it 
22  *                and/or modify it under the terms of the GNU General
23  *                Public License as published by the Free Software
24  *                Foundation; either version 2 of the License, or (at
25  *                your option) any later version.
26  *
27  *                This program is distributed in the hope that it will
28  *                be useful, but WITHOUT ANY WARRANTY; without even the
29  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
30  *                PARTICULAR PURPOSE.  See the GNU General Public
31  *                License for more details.
32  *
33  *                The GNU General Public License should be included with
34  *                this file.  If not, you can view it at
35  *                http://www.gnu.org/copyleft/gpl.html
36  *                or write to the Free Software Foundation, Inc., 59
37  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
38  *
39  * Revisions   :
40  *    $Log: cgi.c,v $
41  *    Revision 1.108  2008/05/26 17:30:53  fabiankeil
42  *    Provide an OpenSearch Description to access the
43  *    show-url-info page through "search engine plugins".
44  *
45  *    Revision 1.107  2008/05/26 16:23:19  fabiankeil
46  *    - Fix spelling in template-not-found message.
47  *    - Declare referrer_is_safe()'s alternative_prefix[] static.
48  *
49  *    Revision 1.106  2008/05/21 15:24:38  fabiankeil
50  *    Mark csp as immutable for a bunch of functions.
51  *
52  *    Revision 1.105  2008/04/17 14:40:47  fabiankeil
53  *    Provide get_http_time() with the buffer size so it doesn't
54  *    have to blindly assume that the buffer is big enough.
55  *
56  *    Revision 1.104  2008/03/26 18:07:06  fabiankeil
57  *    Add hostname directive. Closes PR#1918189.
58  *
59  *    Revision 1.103  2008/03/21 11:13:57  fabiankeil
60  *    Only gather host information if it's actually needed.
61  *    Also move the code out of accept_connection() so it's less likely
62  *    to delay other incoming connections if the host is misconfigured.
63  *
64  *    Revision 1.102  2008/02/23 16:33:43  fabiankeil
65  *    Let forward_url() use the standard parameter ordering
66  *    and mark its second parameter immutable.
67  *
68  *    Revision 1.101  2008/02/03 15:45:06  fabiankeil
69  *    Add SOCKS5 support for "Forwarding failure" CGI page.
70  *
71  *    Revision 1.100  2007/10/17 18:40:53  fabiankeil
72  *    - Send CGI pages as HTTP/1.1 unless the client asked for HTTP/1.0.
73  *    - White space fix.
74  *
75  *    Revision 1.99  2007/08/05 13:42:22  fabiankeil
76  *    #1763173 from Stefan Huehner: declare some more functions static.
77  *
78  *    Revision 1.98  2007/05/14 10:33:51  fabiankeil
79  *    - Use strlcpy() and strlcat() instead of strcpy() and strcat().
80  *
81  *    Revision 1.97  2007/04/09 18:11:35  fabiankeil
82  *    Don't mistake VC++'s _snprintf() for a snprintf() replacement.
83  *
84  *    Revision 1.96  2007/03/08 17:41:05  fabiankeil
85  *    Use sizeof() more often.
86  *
87  *    Revision 1.95  2007/02/10 17:01:37  fabiankeil
88  *    Don't overlook map result for the forwarding-type.
89  *
90  *    Revision 1.94  2007/02/08 19:44:49  fabiankeil
91  *    Use a transparent background for the PNG replacement pattern.
92  *
93  *    Revision 1.93  2007/02/07 10:45:22  fabiankeil
94  *    - Save the reason for generating http_responses.
95  *    - Fix --disable-toggle (again).
96  *    - Use TBL birthday hack for 403 responses as well.
97  *    - Uglify the @menu@ again to fix JavaScript
98  *      errors on the "blocked" template.
99  *    - Escape an ampersand in cgi_error_unknown().
100  *
101  *    Revision 1.92  2007/01/28 13:41:17  fabiankeil
102  *    - Add HEAD support to finish_http_response.
103  *    - Add error favicon to internal HTML error messages.
104  *
105  *    Revision 1.91  2007/01/27 13:09:16  fabiankeil
106  *    Add new config option "templdir" to
107  *    change the templates directory.
108  *
109  *    Revision 1.90  2007/01/25 13:47:26  fabiankeil
110  *    Added "forwarding-failed" template support for error_response().
111  *
112  *    Revision 1.89  2007/01/23 15:51:16  fabiankeil
113  *    Add favicon delivery functions.
114  *
115  *    Revision 1.88  2007/01/23 13:14:32  fabiankeil
116  *    - Map variables that aren't guaranteed to be
117  *      pure ASCII html_encoded.
118  *    - Use CGI_PREFIX to generate URL for user manual
119  *      CGI page to make sure CGI_SITE_2_PATH is included.
120  *
121  *    Revision 1.87  2007/01/22 15:34:13  fabiankeil
122  *    - "Protect" against a rather lame JavaScript-based
123  *      Privoxy detection "attack" and check the referrer
124  *      before delivering the CGI style sheet.
125  *    - Move referrer check for unsafe CGI pages into
126  *      referrer_is_safe() and log the result.
127  *    - Map @url@ in cgi-error-disabled page.
128  *      It's required for the "go there anyway" link.
129  *    - Mark *csp as immutable for grep_cgi_referrer().
130  *
131  *    Revision 1.86  2007/01/09 11:54:26  fabiankeil
132  *    Fix strdup() error handling in cgi_error_unknown()
133  *    and cgi_error_no_template(). Reported by Markus Elfring.
134  *
135  *    Revision 1.85  2007/01/05 14:19:02  fabiankeil
136  *    Handle pcrs_execute() errors in template_fill() properly.
137  *
138  *    Revision 1.84  2006/12/28 17:54:22  fabiankeil
139  *    Fixed gcc43 conversion warnings and replaced sprintf
140  *    calls with snprintf to give OpenBSD's gcc one less reason
141  *    to complain.
142  *
143  *    Revision 1.83  2006/12/17 19:35:19  fabiankeil
144  *    Escape ampersand in Privoxy menu.
145  *
146  *    Revision 1.82  2006/12/17 17:53:39  fabiankeil
147  *    Suppress the toggle link if remote toggling is disabled.
148  *
149  *    Revision 1.81  2006/12/09 13:49:16  fabiankeil
150  *    Fix configure option --disable-toggle.
151  *    Thanks to Peter Thoenen for reporting this.
152  *
153  *    Revision 1.80  2006/12/08 14:45:32  fabiankeil
154  *    Don't lose the FORCE_PREFIX in case of
155  *    connection problems. Fixes #612235.
156  *
157  *    Revision 1.79  2006/11/13 19:05:50  fabiankeil
158  *    Make pthread mutex locking more generic. Instead of
159  *    checking for OSX and OpenBSD, check for FEATURE_PTHREAD
160  *    and use mutex locking unless there is an _r function
161  *    available. Better safe than sorry.
162  *
163  *    Fixes "./configure --disable-pthread" and should result
164  *    in less threading-related problems on pthread-using platforms,
165  *    but it still doesn't fix BR#1122404.
166  *
167  *    Revision 1.78  2006/09/21 19:22:07  fabiankeil
168  *    Use CGI_PREFIX to check the referrer.
169  *    The check for "http://config.privoxy.org/" fails
170  *    if the user modified CGI_SITE_2_HOST.
171  *
172  *    Revision 1.77  2006/09/21 15:17:23  fabiankeil
173  *    Adjusted headers for Privoxy's cgi responses:
174  *    Don't set Last-Modified, Expires and Cache-Control
175  *    headers for redirects; always set "Connection: close".
176  *
177  *    Revision 1.76  2006/09/07 14:06:38  fabiankeil
178  *    Only predate the Last-Modified header for cgi responses
179  *    that are delivered with status code 404 or 503.
180  *
181  *    Revision 1.75  2006/09/07 11:56:39  fabiankeil
182  *    Mark cgi_send_user_manual as harmless,
183  *    to fix the access denied problem Hal spotted.
184  *    The manual has no secret content, therefore we
185  *    don't have to care about "secure" referrers.
186  *
187  *    Revision 1.74  2006/09/06 18:45:03  fabiankeil
188  *    Incorporate modified version of Roland Rosenfeld's patch to
189  *    optionally access the user-manual via Privoxy. Closes patch 679075.
190  *
191  *    Formatting changed to Privoxy style, added call to
192  *    cgi_error_no_template if the requested file doesn't
193  *    exist and modified check whether or not Privoxy itself
194  *    should serve the manual. Should work cross-platform now.
195  *
196  *    Revision 1.73  2006/08/03 02:46:41  david__schmidt
197  *    Incorporate Fabian Keil's patch work:\rhttp://www.fabiankeil.de/sourcecode/privoxy/
198  *
199  *    Revision 1.72  2006/07/18 14:48:45  david__schmidt
200  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
201  *    with what was really the latest development (the v_3_0_branch branch)
202  *
203  *    Revision 1.70.2.13  2004/02/17 13:30:23  oes
204  *    Moved cgi_error_disabled() from cgiedit.c to
205  *    cgi.c to re-enable build with --disable-editor.
206  *    Fixes Bug #892744. Thanks to Matthew Fischer
207  *    for spotting.
208  *
209  *    Revision 1.70.2.12  2003/12/17 16:33:16  oes
210  *     - Added new function cgi_redirect to handle creation of
211  *       HTTP redirect messages formerly repeated in the code.
212  *     - Send cgi_error_disabled instead of cgi_error_404 when
213  *       referrer check fails
214  *     - Dynamic content now gets Expires header field with date
215  *       in the past
216  *
217  *    Revision 1.70.2.11  2003/10/23 12:29:26  oes
218  *    Bugfix: Transparent PNG was not transparent. Thanks to
219  *    Dan Razzell of Starfish Systems for notice and new PNG.
220  *
221  *    Revision 1.70.2.10  2003/06/06 07:54:25  oes
222  *    Security fix: dspatch_known_cgi no longer considers an empty
223  *    referrer safe for critical CGIs, since malicious links could
224  *    reside on https:// locations which browsers don't advertize as
225  *    referrers. Closes bug #749916, thanks to Jeff Epler for the
226  *    hint. Goodbye One-Click[tm] toggling :-(
227  *
228  *    Revision 1.70.2.9  2003/05/08 15:11:31  oes
229  *    Nit
230  *
231  *    Revision 1.70.2.8  2003/04/29 13:33:51  oes
232  *    Killed a compiler warning on OSX
233  *
234  *    Revision 1.70.2.7  2003/04/03 13:50:58  oes
235  *    - Don't call cgi_error_disabled ifndef FEATURE_CGI_EDIT_ACTIONS
236  *      (fixes bug #710056)
237  *    - Show toggle info only if we have it
238  *
239  *    Revision 1.70.2.6  2003/03/12 01:26:25  david__schmidt
240  *    Move declaration of struct tm dummy outside of a control block so it is
241  *    accessible later on during snprintf in get_http_time.
242  *
243  *    Revision 1.70.2.5  2003/03/11 11:53:58  oes
244  *    Cosmetic: Renamed cryptic variable
245  *
246  *    Revision 1.70.2.4  2003/03/07 03:41:03  david__schmidt
247  *    Wrapping all *_r functions (the non-_r versions of them) with mutex semaphores for OSX.  Hopefully this will take care of all of those pesky crash reports.
248  *
249  *    Revision 1.70.2.3  2002/11/28 18:14:32  oes
250  *    Disable access to critical CGIs via untrusted referrers.
251  *    This prevents users from being tricked by malicious websites
252  *    into making unintentional configuration changes:
253  *
254  *     - Added flag to each cgi_dispatcher that allows or denies
255  *       external linking
256  *     - Introduced proviorical function that greps for the
257  *       referrer header before regular header parsing happens
258  *     - Added safety check to dispatch_known_cgi. CGI is called
259  *       if (cgi harmless || no referrer || we are referrer).
260  *       Else a) toggle calls are modified not to change status and
261  *       b) all other calls are denied.
262  *
263  *    Revision 1.70.2.2  2002/11/12 16:20:37  oes
264  *    Added missing #ifdef FEATURE_TOGGLE around g_bToggleIJB; fixes bug #636651
265  *
266  *    Revision 1.70.2.1  2002/08/05 11:17:46  oes
267  *    Fixed Bug #587820, i.e. added workaround for IE bug that includes fragment identifier in (cgi) query
268  *
269  *    Revision 1.70  2002/05/19 11:33:20  jongfoster
270  *    If a CGI error was not handled, and propogated back to
271  *    dispatch_known_cgi(), then it was assumed to be "out of memory".
272  *    This gave a very misleading error message.
273  *
274  *    Now other errors will cause a simple message giving the error
275  *    number and asking the user to report a bug.
276  *
277  *    Bug report:
278  *    http://sourceforge.net/tracker/index.php?func=detail
279  *    &aid=557905&group_id=11118&atid=111118
280  *
281  *    Revision 1.69  2002/05/14 21:28:40  oes
282  *     - Fixed add_help_link to link to the (now split) actions
283  *       part of the config chapter
284  *     - Renamed helplink export to actions-help-prefix
285  *
286  *    Revision 1.68  2002/05/12 21:36:29  jongfoster
287  *    Correcting function comments
288  *
289  *    Revision 1.67  2002/04/30 12:02:07  oes
290  *    Nit: updated a comment
291  *
292  *    Revision 1.66  2002/04/26 18:32:57  jongfoster
293  *    Fixing a memory leak on error
294  *
295  *    Revision 1.65  2002/04/26 12:53:51  oes
296  *     - New function add_help_link
297  *     - default_exports now exports links to the user manual
298  *       and a prefix for links into the config chapter
299  *
300  *    Revision 1.64  2002/04/24 02:17:21  oes
301  *     - Better descriptions for CGIs
302  *     - Hide edit-actions, more shortcuts
303  *     - Moved get_char_param, get_string_param and get_number_param here
304  *       from cgiedit.c
305  *
306  *    Revision 1.63  2002/04/15 19:06:43  jongfoster
307  *    Typos
308  *
309  *    Revision 1.62  2002/04/10 19:59:46  jongfoster
310  *    Fixes to #include in templates:
311  *    - Didn't close main file if loading an included template fails.
312  *    - I'm paranoid and want to disallow "#include /etc/passwd".
313  *
314  *    Revision 1.61  2002/04/10 13:37:48  oes
315  *    Made templates modular: template_load now recursive with max depth 1
316  *
317  *    Revision 1.60  2002/04/08 20:50:25  swa
318  *    fixed JB spelling
319  *
320  *    Revision 1.59  2002/04/05 15:51:51  oes
321  *     - added send-stylesheet CGI
322  *     - bugfix: error-pages now get correct request protocol
323  *     - fixed
324  *     - kludged CGI descriptions and menu not to break JS syntax
325  *
326  *    Revision 1.58  2002/03/29 03:33:13  david__schmidt
327  *    Fix Mac OSX compiler warnings
328  *
329  *    Revision 1.57  2002/03/26 22:29:54  swa
330  *    we have a new homepage!
331  *
332  *    Revision 1.56  2002/03/24 17:50:46  jongfoster
333  *    Fixing compile error if actions file editor disabled
334  *
335  *    Revision 1.55  2002/03/24 16:55:06  oes
336  *    Making GIF checkerboard transparent
337  *
338  *    Revision 1.54  2002/03/24 16:18:15  jongfoster
339  *    Removing old logo
340  *
341  *    Revision 1.53  2002/03/24 16:06:00  oes
342  *    Correct transparency for checkerboard PNG. Thanks, Magnus!
343  *
344  *    Revision 1.52  2002/03/24 15:23:33  jongfoster
345  *    Name changes
346  *
347  *    Revision 1.51  2002/03/24 13:25:43  swa
348  *    name change related issues
349  *
350  *    Revision 1.50  2002/03/16 23:54:06  jongfoster
351  *    Adding graceful termination feature, to help look for memory leaks.
352  *    If you enable this (which, by design, has to be done by hand
353  *    editing config.h) and then go to http://i.j.b/die, then the program
354  *    will exit cleanly after the *next* request.  It should free all the
355  *    memory that was used.
356  *
357  *    Revision 1.49  2002/03/13 00:27:04  jongfoster
358  *    Killing warnings
359  *
360  *    Revision 1.48  2002/03/08 17:47:07  jongfoster
361  *    Adding comments
362  *
363  *    Revision 1.47  2002/03/08 16:41:33  oes
364  *    Added GIF images again
365  *
366  *    Revision 1.46  2002/03/07 03:48:38  oes
367  *     - Changed built-in images from GIF to PNG
368  *       (with regard to Unisys patent issue)
369  *     - Added a 4x4 pattern PNG which is less intrusive
370  *       than the logo but also clearly marks the deleted banners
371  *
372  *    Revision 1.45  2002/03/06 22:54:35  jongfoster
373  *    Automated function-comment nitpicking.
374  *
375  *    Revision 1.44  2002/03/05 22:43:45  david__schmidt
376  *    - Better error reporting on OS/2
377  *    - Fix double-slash comment (oops)
378  *
379  *    Revision 1.43  2002/03/05 21:33:45  david__schmidt
380  *    - Re-enable OS/2 building after new parms were added
381  *    - Fix false out of memory report when resolving CGI templates when no IP
382  *      address is available of failed attempt (a la no such domain)
383  *
384  *    Revision 1.42  2002/01/21 00:33:20  jongfoster
385  *    Replacing strsav() with the safer string_append() or string_join().
386  *    Adding map_block_keep() to save a few bytes in the edit-actions-list HTML.
387  *    Adding missing html_encode() to error message generators.
388  *    Adding edit-actions-section-swap and many "shortcuts" to the list of CGIs.
389  *
390  *    Revision 1.41  2002/01/17 20:56:22  jongfoster
391  *    Replacing hard references to the URL of the config interface
392  *    with #defines from project.h
393  *
394  *    Revision 1.40  2002/01/09 14:26:46  oes
395  *    Added support for thread-safe gmtime_r call.
396  *
397  *    Revision 1.39  2001/11/16 00:48:13  jongfoster
398  *    Fixing a compiler warning
399  *
400  *    Revision 1.38  2001/11/13 00:31:21  jongfoster
401  *    - Adding new CGIs for use by non-JavaScript browsers:
402  *        edit-actions-url-form
403  *        edit-actions-add-url-form
404  *        edit-actions-remove-url-form
405  *    - Fixing make_menu()'s HTML generation - it now quotes the href parameter.
406  *    - Fixing || bug.
407  *
408  *    Revision 1.37  2001/11/01 14:28:47  david__schmidt
409  *    Show enablement/disablement status in almost all templates.
410  *    There is a little trickiness here: apparent recursive resolution of
411  *    @if-enabled-then@ caused the toggle template to show status out-of-phase with
412  *    the actual enablement status.  So a similar construct,
413  *    @if-enabled-display-then@, is used to resolve the status display on non-'toggle'
414  *    templates.
415  *
416  *    Revision 1.36  2001/10/26 17:33:27  oes
417  *    marginal bugfix
418  *
419  *    Revision 1.35  2001/10/23 21:48:19  jongfoster
420  *    Cleaning up error handling in CGI functions - they now send back
421  *    a HTML error page and should never cause a FATAL error.  (Fixes one
422  *    potential source of "denial of service" attacks).
423  *
424  *    CGI actions file editor that works and is actually useful.
425  *
426  *    Ability to toggle Junkbuster remotely using a CGI call.
427  *
428  *    You can turn off both the above features in the main configuration
429  *    file, e.g. if you are running a multi-user proxy.
430  *
431  *    Revision 1.34  2001/10/18 22:22:09  david__schmidt
432  *    Only show "Local support" on templates conditionally:
433  *      - if either 'admin-address' or 'proxy-info-url' are uncommented in config
434  *      - if not, no Local support section appears
435  *
436  *    Revision 1.33  2001/10/14 22:28:41  jongfoster
437  *    Fixing stupid typo.
438  *
439  *    Revision 1.32  2001/10/14 22:20:18  jongfoster
440  *    - Changes to CGI dispatching method to match CGI names exactly,
441  *      rather than doing a prefix match.
442  *    - No longer need to count the length of the CGI handler names by hand.
443  *    - Adding new handler for 404 error when disptching a CGI, if none of
444  *      the handlers match.
445  *    - Adding new handlers for CGI actionsfile editor.
446  *
447  *    Revision 1.31  2001/10/10 10:56:39  oes
448  *    Failiure to load template now fatal. Before, the user got a hard-to-understand assertion failure from cgi.c
449  *
450  *    Revision 1.30  2001/10/02 15:30:57  oes
451  *    Introduced show-request cgi
452  *
453  *    Revision 1.29  2001/09/20 15:47:44  steudten
454  *
455  *    Fix BUG: Modify int size to size_t size in fill_template()
456  *     - removes big trouble on machines where sizeof(int) != sizeof(size_t).
457  *
458  *    Revision 1.28  2001/09/19 18:00:37  oes
459  *     - Deletef time() FIXME (Can't fail under Linux either, if
460  *       the argument is guaranteed to be in out address space,
461  *       which it is.)
462  *     - Fixed comments
463  *     - Pointer notation cosmetics
464  *     - Fixed a minor bug in template_fill(): Failiure of
465  *       pcrs_execute() now secure.
466  *
467  *    Revision 1.27  2001/09/16 17:08:54  jongfoster
468  *    Moving simple CGI functions from cgi.c to new file cgisimple.c
469  *
470  *    Revision 1.26  2001/09/16 15:47:37  jongfoster
471  *    First version of CGI-based edit interface.  This is very much a
472  *    work-in-progress, and you can't actually use it to edit anything
473  *    yet.  You must #define FEATURE_CGI_EDIT_ACTIONS for these changes
474  *    to have any effect.
475  *
476  *    Revision 1.25  2001/09/16 15:02:35  jongfoster
477  *    Adding i.j.b/robots.txt.
478  *    Inlining add_stats() since it's only ever called from one place.
479  *
480  *    Revision 1.24  2001/09/16 11:38:01  jongfoster
481  *    Splitting fill_template() into 2 functions:
482  *    template_load() loads the file
483  *    template_fill() performs the PCRS regexps.
484  *    This is because the CGI edit interface has a "table row"
485  *    template which is used many times in the page - this
486  *    change means it's only loaded from disk once.
487  *
488  *    Revision 1.23  2001/09/16 11:16:05  jongfoster
489  *    Better error handling in dispatch_cgi() and parse_cgi_parameters()
490  *
491  *    Revision 1.22  2001/09/16 11:00:10  jongfoster
492  *    New function alloc_http_response, for symmetry with free_http_response
493  *
494  *    Revision 1.21  2001/09/13 23:53:03  jongfoster
495  *    Support for both static and dynamically generated CGI pages.
496  *    Correctly setting Last-Modified: and Expires: HTTP headers.
497  *
498  *    Revision 1.20  2001/09/13 23:40:36  jongfoster
499  *    (Cosmetic only) Indentation correction
500  *
501  *    Revision 1.19  2001/09/13 23:31:25  jongfoster
502  *    Moving image data to cgi.c rather than cgi.h.
503  *
504  *    Revision 1.18  2001/08/05 16:06:20  jongfoster
505  *    Modifiying "struct map" so that there are now separate header and
506  *    "map_entry" structures.  This means that functions which modify a
507  *    map no longer need to return a pointer to the modified map.
508  *    Also, it no longer reverses the order of the entries (which may be
509  *    important with some advanced template substitutions).
510  *
511  *    Revision 1.17  2001/08/05 15:57:38  oes
512  *    Adapted finish_http_response to new list_to_text
513  *
514  *    Revision 1.16  2001/08/01 21:33:18  jongfoster
515  *    Changes to fill_template() that reduce memory usage without having
516  *    an impact on performance.  I also renamed some variables so as not
517  *    to clash with the C++ keywords "new" and "template".
518  *
519  *    Revision 1.15  2001/08/01 21:19:22  jongfoster
520  *    Moving file version information to a separate CGI page.
521  *
522  *    Revision 1.14  2001/08/01 00:19:03  jongfoster
523  *    New function: map_conditional() for an if-then-else syntax.
524  *    Changing to use new version of show_defines()
525  *
526  *    Revision 1.13  2001/07/30 22:08:36  jongfoster
527  *    Tidying up #defines:
528  *    - All feature #defines are now of the form FEATURE_xxx
529  *    - Permanently turned off WIN_GUI_EDIT
530  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
531  *
532  *    Revision 1.12  2001/07/29 18:47:05  jongfoster
533  *    Adding missing #include "loadcfg.h"
534  *
535  *    Revision 1.11  2001/07/18 17:24:37  oes
536  *    Changed to conform to new pcrs interface
537  *
538  *    Revision 1.10  2001/07/13 13:53:13  oes
539  *    Removed all #ifdef PCRS and related code
540  *
541  *    Revision 1.9  2001/06/29 21:45:41  oes
542  *    Indentation, CRLF->LF, Tab-> Space
543  *
544  *    Revision 1.8  2001/06/29 13:21:46  oes
545  *    - Cosmetics: renamed and reordered functions, variables,
546  *      texts, improved comments  etc
547  *
548  *    - Removed ij_untrusted_url() The relevant
549  *      info is now part of the "untrusted" page,
550  *      which is generated by filters.c:trust_url()
551  *
552  *    - Generators of content now call finish_http_response()
553  *      themselves, making jcc.c:chat() a little less
554  *      cluttered
555  *
556  *    - Removed obsolete "Pragma: no-cache" from our headers
557  *
558  *    - http_responses now know their head length
559  *
560  *    - fill_template now uses the new interface to pcrs, so that
561  *       - long jobs (like whole files) no longer have to be assembled
562  *         in a fixed size buffer
563  *       - the new T (trivial) option is used, and the replacement may
564  *         contain Perl syntax backrefs without confusing pcrs
565  *
566  *    - Introduced default_exports() which generates a set of exports
567  *      common to all CGIs and other content generators
568  *
569  *    - Introduced convenience function map_block_killer()
570  *
571  *    - Introduced convenience function make_menu()
572  *
573  *    - Introduced CGI-like function error_response() which generates
574  *      the "No such domain" and "Connect failed" messages using the
575  *      CGI platform
576  *
577  *    - cgi_show_url_info:
578  *      - adapted to new CGI features
579  *      - form and answers now generated from same template
580  *      - http:// prefix in URL now OK
581  *
582  *    - cgi_show_status:
583  *      - adapted to new CGI features
584  *      - no longer uses csp->init_proxy_args
585  *
586  *    - cgi_default:
587  *      - moved menu generation to make_menu()
588  *
589  *    - add_stats now writes single export map entries instead
590  *      of a fixed string
591  *
592  *    - Moved redirect_url() to filters.c
593  *
594  *    - Fixed mem leak in free_http_response(), map_block_killer(),
595  *
596  *    - Removed logentry from cancelled commit
597  *
598  *    Revision 1.7  2001/06/09 10:51:58  jongfoster
599  *    Changing "show URL info" handler to new style.
600  *    Changing BUFSIZ ==> BUFFER_SIZE
601  *
602  *    Revision 1.6  2001/06/07 23:05:19  jongfoster
603  *    Removing code related to old forward and ACL files.
604  *
605  *    Revision 1.5  2001/06/05 19:59:16  jongfoster
606  *    Fixing multiline character string (a GCC-only "feature"), and snprintf (it's _snprintf under VC++).
607  *
608  *    Revision 1.4  2001/06/04 10:41:52  swa
609  *    show version string of cgi.h and cgi.c
610  *
611  *    Revision 1.3  2001/06/03 19:12:16  oes
612  *    introduced new cgi handling
613  *
614  *    No revisions before 1.3
615  *
616  **********************************************************************/
617 \f
618
619 #include "config.h"
620
621 #include <stdio.h>
622 #include <sys/types.h>
623 #include <stdlib.h>
624 #include <ctype.h>
625 #include <string.h>
626 #include <limits.h>
627 #include <assert.h>
628
629 #include "project.h"
630 #include "cgi.h"
631 #include "list.h"
632 #include "encode.h"
633 #include "ssplit.h"
634 #include "errlog.h"
635 #include "filters.h"
636 #include "miscutil.h"
637 #include "cgisimple.h"
638 #include "jbsockets.h"
639 #ifdef FEATURE_CGI_EDIT_ACTIONS
640 #include "cgiedit.h"
641 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
642 #include "loadcfg.h"
643 /* loadcfg.h is for global_toggle_state only */
644 #ifdef FEATURE_PTHREAD
645 #include "jcc.h"
646 /* jcc.h is for mutex semaphore globals only */
647 #endif /* def FEATURE_PTHREAD */
648 const char cgi_h_rcs[] = CGI_H_VERSION;
649
650 /*
651  * List of CGI functions: name, handler, description
652  * Note: Do NOT use single quotes in the description;
653  *       this will break the dynamic "blocked" template!
654  */
655 static const struct cgi_dispatcher cgi_dispatchers[] = {
656    { "",
657          cgi_default,
658          "Privoxy main page",
659          TRUE },
660 #ifdef FEATURE_GRACEFUL_TERMINATION
661    { "die", 
662          cgi_die,  
663          "<b>Shut down</b> - <em class=\"warning\">Do not deploy this build in a production environment, "
664         "this is a one click Denial Of Service attack!!!</em>",
665          FALSE }, 
666 #endif
667    { "show-status", 
668          cgi_show_status,  
669 #ifdef FEATURE_CGI_EDIT_ACTIONS
670         "View &amp; change the current configuration",
671 #else
672         "View the current configuration",
673 #endif
674          TRUE }, 
675    { "show-version", 
676          cgi_show_version,  
677          "View the source code version numbers",
678           TRUE }, 
679    { "show-request", 
680          cgi_show_request,  
681          "View the request headers.",
682          TRUE }, 
683    { "show-url-info",
684          cgi_show_url_info, 
685          "Look up which actions apply to a URL and why",
686          TRUE },
687 #ifdef FEATURE_CGI_EDIT_ACTIONS
688 #ifdef FEATURE_TOGGLE
689    { "toggle",
690          cgi_toggle, 
691          "Toggle Privoxy on or off",
692          FALSE },
693 #endif /* def FEATURE_TOGGLE */
694    { "edit-actions", /* Edit the actions list */
695          cgi_edit_actions, 
696          NULL, FALSE },
697    { "eaa", /* Shortcut for edit-actions-add-url-form */
698          cgi_edit_actions_add_url_form, 
699          NULL, FALSE },
700    { "eau", /* Shortcut for edit-actions-url-form */
701          cgi_edit_actions_url_form, 
702          NULL, FALSE },
703    { "ear", /* Shortcut for edit-actions-remove-url-form */
704          cgi_edit_actions_remove_url_form, 
705          NULL, FALSE },
706    { "eal", /* Shortcut for edit-actions-list */
707          cgi_edit_actions_list, 
708          NULL, FALSE },
709    { "eafu", /* Shortcut for edit-actions-for-url */
710          cgi_edit_actions_for_url, 
711          NULL, FALSE },
712    { "eas", /* Shortcut for edit-actions-submit */
713          cgi_edit_actions_submit, 
714          NULL, FALSE },
715    { "easa", /* Shortcut for edit-actions-section-add */
716          cgi_edit_actions_section_add, 
717          NULL, FALSE  },
718    { "easr", /* Shortcut for edit-actions-section-remove */
719          cgi_edit_actions_section_remove, 
720          NULL, FALSE  },
721    { "eass", /* Shortcut for edit-actions-section-swap */
722          cgi_edit_actions_section_swap, 
723          NULL, FALSE  },
724    { "edit-actions-for-url",
725          cgi_edit_actions_for_url, 
726          NULL, FALSE  /* Edit the actions for (a) specified URL(s) */ },
727    { "edit-actions-list",
728          cgi_edit_actions_list, 
729          NULL, TRUE /* Edit the actions list */ },
730    { "edit-actions-submit",
731          cgi_edit_actions_submit, 
732          NULL, FALSE /* Change the actions for (a) specified URL(s) */ },
733    { "edit-actions-url",
734          cgi_edit_actions_url, 
735          NULL, FALSE /* Change a URL pattern in the actionsfile */ },
736    { "edit-actions-url-form",
737          cgi_edit_actions_url_form, 
738          NULL, FALSE /* Form to change a URL pattern in the actionsfile */ },
739    { "edit-actions-add-url",
740          cgi_edit_actions_add_url, 
741          NULL, FALSE /* Add a URL pattern to the actionsfile */ },
742    { "edit-actions-add-url-form",
743          cgi_edit_actions_add_url_form, 
744          NULL, FALSE /* Form to add a URL pattern to the actionsfile */ },
745    { "edit-actions-remove-url",
746          cgi_edit_actions_remove_url, 
747          NULL, FALSE /* Remove a URL pattern from the actionsfile */ },
748    { "edit-actions-remove-url-form",
749          cgi_edit_actions_remove_url_form, 
750          NULL, FALSE /* Form to remove a URL pattern from the actionsfile */ },
751    { "edit-actions-section-add",
752          cgi_edit_actions_section_add, 
753          NULL, FALSE /* Remove a section from the actionsfile */ },
754    { "edit-actions-section-remove",
755          cgi_edit_actions_section_remove, 
756          NULL, FALSE /* Remove a section from the actionsfile */ },
757    { "edit-actions-section-swap",
758          cgi_edit_actions_section_swap, 
759          NULL, FALSE /* Swap two sections in the actionsfile */ },
760 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
761    { "error-favicon.ico", 
762          cgi_send_error_favicon,  
763          NULL, TRUE /* Sends the favicon image for error pages. */ },
764    { "favicon.ico", 
765          cgi_send_default_favicon,  
766          NULL, TRUE /* Sends the default favicon image. */ },
767    { "robots.txt", 
768          cgi_robots_txt,  
769          NULL, TRUE /* Sends a robots.txt file to tell robots to go away. */ }, 
770    { "send-banner",
771          cgi_send_banner, 
772          NULL, TRUE /* Send a built-in image */ },
773    { "send-stylesheet",
774          cgi_send_stylesheet, 
775          NULL, FALSE /* Send templates/cgi-style.css */ },
776    { "t",
777          cgi_transparent_image, 
778          NULL, TRUE /* Send a transparent image (short name) */ },
779    { "url-info-osd.xml",
780          cgi_send_url_info_osd, 
781          NULL, TRUE /* Send templates/url-info-osd.xml */ },
782    { "user-manual",
783           cgi_send_user_manual,
784           NULL, TRUE /* Send user-manual */ },
785    { NULL, /* NULL Indicates end of list and default page */
786          cgi_error_404,
787          NULL, TRUE /* Unknown CGI page */ }
788 };
789
790
791 /*
792  * Built-in images for ad replacement
793  *
794  * Hint: You can encode your own images like this:
795  * cat your-image | perl -e 'while (read STDIN, $c, 1) { printf("\\%.3o", unpack("C", $c)); }'
796  */
797
798 #ifdef FEATURE_NO_GIFS
799
800 /*
801  * Checkerboard pattern, as a PNG.
802  */
803 const char image_pattern_data[] =
804    "\211\120\116\107\015\012\032\012\000\000\000\015\111\110\104"
805    "\122\000\000\000\004\000\000\000\004\010\006\000\000\000\251"
806    "\361\236\176\000\000\000\006\142\113\107\104\000\000\000\000"
807    "\000\000\371\103\273\177\000\000\000\033\111\104\101\124\010"
808    "\327\143\140\140\140\060\377\377\377\077\003\234\106\341\060"
809    "\060\230\063\020\124\001\000\161\021\031\241\034\364\030\143"
810    "\000\000\000\000\111\105\116\104\256\102\140\202";
811
812 /*
813  * 1x1 transparant PNG.
814  */
815 const char image_blank_data[] =
816  "\211\120\116\107\015\012\032\012\000\000\000\015\111\110\104\122"
817  "\000\000\000\001\000\000\000\001\001\003\000\000\000\045\333\126"
818  "\312\000\000\000\003\120\114\124\105\377\377\377\247\304\033\310"
819  "\000\000\000\001\164\122\116\123\000\100\346\330\146\000\000\000"
820  "\001\142\113\107\104\000\210\005\035\110\000\000\000\012\111\104"
821  "\101\124\170\001\143\140\000\000\000\002\000\001\163\165\001\030"
822  "\000\000\000\000\111\105\116\104\256\102\140\202";
823 #else
824
825 /*
826  * Checkerboard pattern, as a GIF.
827  */
828 const char image_pattern_data[] =
829    "\107\111\106\070\071\141\004\000\004\000\200\000\000\310\310"
830    "\310\377\377\377\041\376\016\111\040\167\141\163\040\141\040"
831    "\142\141\156\156\145\162\000\041\371\004\001\012\000\001\000"
832    "\054\000\000\000\000\004\000\004\000\000\002\005\104\174\147"
833    "\270\005\000\073";
834
835 /*
836  * 1x1 transparant GIF.
837  */
838 const char image_blank_data[] =
839    "GIF89a\001\000\001\000\200\000\000\377\377\377\000\000"
840    "\000!\371\004\001\000\000\000\000,\000\000\000\000\001"
841    "\000\001\000\000\002\002D\001\000;";
842 #endif
843
844 const size_t image_pattern_length = sizeof(image_pattern_data) - 1;
845 const size_t image_blank_length   = sizeof(image_blank_data) - 1;
846
847
848 static struct http_response cgi_error_memory_response[1];
849
850 static struct http_response *dispatch_known_cgi(struct client_state * csp,
851                                                 const char * path);
852 static struct map *parse_cgi_parameters(char *argstring);
853
854
855 /*********************************************************************
856  * 
857  * Function    :  dispatch_cgi
858  *
859  * Description :  Checks if a request URL has either the magical
860  *                hostname CGI_SITE_1_HOST (usually http://p.p/) or
861  *                matches CGI_SITE_2_HOST CGI_SITE_2_PATH (usually
862  *                http://config.privoxy.org/). If so, it passes
863  *                the (rest of the) path onto dispatch_known_cgi, which
864  *                calls the relevant CGI handler function.
865  *
866  * Parameters  :
867  *          1  :  csp = Current client state (buffers, headers, etc...)
868  *
869  * Returns     :  http_response if match, NULL if nonmatch or handler fail
870  *
871  *********************************************************************/
872 struct http_response *dispatch_cgi(struct client_state *csp)
873 {
874    const char *host = csp->http->host;
875    const char *path = csp->http->path;
876
877    /*
878     * Should we intercept ?
879     */
880
881    /* Note: "example.com" and "example.com." are equivalent hostnames. */
882
883    /* Either the host matches CGI_SITE_1_HOST ..*/
884    if (   ( (0 == strcmpic(host, CGI_SITE_1_HOST))
885          || (0 == strcmpic(host, CGI_SITE_1_HOST ".")))
886        && (path[0] == '/') )
887    {
888       /* ..then the path will all be for us.  Remove leading '/' */
889       path++;
890    }
891    /* Or it's the host part CGI_SITE_2_HOST, and the path CGI_SITE_2_PATH */
892    else if ( ( (0 == strcmpic(host, CGI_SITE_2_HOST ))
893             || (0 == strcmpic(host, CGI_SITE_2_HOST ".")) )
894           && (0 == strncmpic(path, CGI_SITE_2_PATH, strlen(CGI_SITE_2_PATH))) )
895    {
896       /* take everything following CGI_SITE_2_PATH */
897       path += strlen(CGI_SITE_2_PATH);
898       if (*path == '/')
899       {
900          /* skip the forward slash after CGI_SITE_2_PATH */
901          path++;
902       }
903       else if (*path != '\0')
904       {
905          /*
906           * weirdness: URL is /configXXX, where XXX is some string
907           * Do *NOT* intercept.
908           */
909          return NULL;
910       }
911    }
912    else
913    {
914       /* Not a CGI */
915       return NULL;
916    }
917
918    /* 
919     * This is a CGI call.
920     */
921
922    return dispatch_known_cgi(csp, path);
923 }
924
925
926 /*********************************************************************
927  *
928  * Function    :  grep_cgi_referrer
929  *
930  * Description :  Ugly provisorical fix that greps the value of the
931  *                referer HTTP header field out of a linked list of
932  *                strings like found at csp->headers. Will disappear
933  *                in Privoxy 3.1.
934  *
935  *                FIXME: csp->headers ought to be csp->http->headers
936  *                FIXME: Parsing all client header lines should
937  *                       happen right after the request is received!
938  *
939  * Parameters  :
940  *          1  :  csp = Current client state (buffers, headers, etc...)
941  *
942  * Returns     :  pointer to value (no copy!), or NULL if none found.
943  *
944  *********************************************************************/
945 static char *grep_cgi_referrer(const struct client_state *csp)
946 {
947    struct list_entry *p;
948
949    for (p = csp->headers->first; p != NULL; p = p->next)
950    {
951       if (p->str == NULL) continue;
952       if (strncmpic(p->str, "Referer: ", 9) == 0)
953       {
954          return ((p->str) + 9);
955       }
956    }
957    return NULL;
958
959 }
960
961
962 /*********************************************************************
963  * 
964  * Function    :  referrer_is_safe
965  *
966  * Description :  Decides whether we trust the Referer for
967  *                CGI pages which are only meant to be reachable
968  *                through Privoxy's web interface directly.
969  *
970  * Parameters  :
971  *          1  :  csp = Current client state (buffers, headers, etc...)
972  *
973  * Returns     :  TRUE  if the referrer is safe, or
974  *                FALSE if the referrer is unsafe or not set.
975  *
976  *********************************************************************/
977 static int referrer_is_safe(const struct client_state *csp)
978 {
979    char *referrer;
980    static const char alternative_prefix[] = "http://" CGI_SITE_1_HOST "/";
981
982    referrer = grep_cgi_referrer(csp);
983
984    if (NULL == referrer)
985    {
986       /* No referrer, no access  */
987       log_error(LOG_LEVEL_ERROR, "Denying access to %s. No referrer found.",
988          csp->http->url);
989    }
990    else if ((0 == strncmp(referrer, CGI_PREFIX, sizeof(CGI_PREFIX)-1)
991          || (0 == strncmp(referrer, alternative_prefix, strlen(alternative_prefix)))))
992    {
993       /* Trustworthy referrer */
994       log_error(LOG_LEVEL_CGI, "Granting access to %s, referrer %s is trustworthy.",
995          csp->http->url, referrer);
996
997       return TRUE;
998    }
999    else
1000    {
1001       /* Untrustworthy referrer */
1002       log_error(LOG_LEVEL_ERROR, "Denying access to %s, referrer %s isn't trustworthy.",
1003          csp->http->url, referrer);
1004    }
1005
1006    return FALSE;
1007
1008 }
1009
1010 /*********************************************************************
1011  * 
1012  * Function    :  dispatch_known_cgi
1013  *
1014  * Description :  Processes a CGI once dispatch_cgi has determined that
1015  *                it matches one of the magic prefixes. Parses the path
1016  *                as a cgi name plus query string, prepares a map that
1017  *                maps CGI parameter names to their values, initializes
1018  *                the http_response struct, and calls the relevant CGI
1019  *                handler function.
1020  *
1021  * Parameters  :
1022  *          1  :  csp = Current client state (buffers, headers, etc...)
1023  *          2  :  path = Path of CGI, with the CGI prefix removed.
1024  *                       Should not have a leading "/".
1025  *
1026  * Returns     :  http_response, or NULL on handler failure or out of
1027  *                memory.
1028  *
1029  *********************************************************************/
1030 static struct http_response *dispatch_known_cgi(struct client_state * csp,
1031                                                 const char * path)
1032 {
1033    const struct cgi_dispatcher *d;
1034    struct map *param_list;
1035    struct http_response *rsp;
1036    char *query_args_start;
1037    char *path_copy;
1038    jb_err err;
1039
1040    if (NULL == (path_copy = strdup(path)))
1041    {
1042       return cgi_error_memory();
1043    }
1044    query_args_start = path_copy;
1045    while (*query_args_start && *query_args_start != '?' && *query_args_start != '/')
1046    {
1047       query_args_start++;
1048    }
1049    if (*query_args_start == '/') 
1050    {
1051       *query_args_start++ = '\0';
1052       if ((param_list = new_map()))
1053       {
1054          map(param_list, "file", 1, url_decode(query_args_start), 0);
1055       }
1056    }
1057    else
1058    {
1059       if (*query_args_start == '?')
1060       {
1061          *query_args_start++ = '\0';
1062       }
1063       if (NULL == (param_list = parse_cgi_parameters(query_args_start)))
1064       {
1065          free(path_copy);
1066          return cgi_error_memory();
1067       }
1068    }
1069
1070    /*
1071     * At this point:
1072     * path_copy        = CGI call name
1073     * param_list       = CGI params, as map
1074     */
1075
1076    /* Get mem for response or fail*/
1077    if (NULL == (rsp = alloc_http_response()))
1078    {
1079       free(path_copy);
1080       free_map(param_list);
1081       return cgi_error_memory();
1082    }
1083
1084    /* 
1085     * Find and start the right CGI function
1086     */
1087    d = cgi_dispatchers;
1088    for (;;)
1089    {
1090       if ((d->name == NULL) || (strcmp(path_copy, d->name) == 0))
1091       {
1092          /*
1093           * If the called CGI is either harmless, or referred
1094           * from a trusted source, start it.
1095           */
1096          if (d->harmless || referrer_is_safe(csp))
1097          {
1098             err = (d->handler)(csp, rsp, param_list);
1099          }
1100          else
1101          {
1102             /*
1103              * Else, modify toggle calls so that they only display
1104              * the status, and deny all other calls.
1105              */
1106             if (0 == strcmp(path_copy, "toggle"))
1107             {
1108                unmap(param_list, "set");
1109                err = (d->handler)(csp, rsp, param_list);
1110             }
1111             else
1112             {
1113                err = cgi_error_disabled(csp, rsp);
1114             }
1115          }
1116
1117          free(path_copy);
1118          free_map(param_list);
1119
1120          if (err == JB_ERR_CGI_PARAMS)
1121          {
1122             err = cgi_error_bad_param(csp, rsp);
1123          }
1124          if (err && (err != JB_ERR_MEMORY))
1125          {
1126             /* Unexpected error! Shouldn't get here */
1127             log_error(LOG_LEVEL_ERROR, "Unexpected CGI error %d in top-level handler.  Please file a bug report!", err);
1128             err = cgi_error_unknown(csp, rsp, err);
1129          }
1130          if (!err)
1131          {
1132             /* It worked */
1133             rsp->reason = RSP_REASON_CGI_CALL;
1134             return finish_http_response(csp, rsp);
1135          }
1136          else
1137          {
1138             /* Error in handler, probably out-of-memory */
1139             free_http_response(rsp);
1140             return cgi_error_memory();
1141          }
1142       }
1143       d++;
1144    }
1145 }
1146    
1147         
1148 /*********************************************************************
1149  *
1150  * Function    :  parse_cgi_parameters
1151  *
1152  * Description :  Parse a URL-encoded argument string into name/value
1153  *                pairs and store them in a struct map list.
1154  *
1155  * Parameters  :
1156  *          1  :  argstring = string to be parsed.  Will be trashed.
1157  *
1158  * Returns     :  pointer to param list, or NULL if out of memory.
1159  *
1160  *********************************************************************/
1161 static struct map *parse_cgi_parameters(char *argstring)
1162 {
1163    char *p;
1164    char *vector[BUFFER_SIZE];
1165    int pairs, i;
1166    struct map *cgi_params;
1167
1168    if (NULL == (cgi_params = new_map()))
1169    {
1170       return NULL;
1171    }
1172
1173    /* 
1174     * IE 5 does, of course, violate RFC 2316 Sect 4.1 and sends
1175     * the fragment identifier along with the request, so we must
1176     * cut it off here, so it won't pollute the CGI params:
1177     */
1178    if (NULL != (p = strchr(argstring, '#')))
1179    {
1180       *p = '\0';
1181    }
1182
1183    pairs = ssplit(argstring, "&", vector, SZ(vector), 1, 1);
1184
1185    for (i = 0; i < pairs; i++)
1186    {
1187       if ((NULL != (p = strchr(vector[i], '='))) && (*(p+1) != '\0'))
1188       {
1189          *p = '\0';
1190          if (map(cgi_params, url_decode(vector[i]), 0, url_decode(++p), 0))
1191          {
1192             free_map(cgi_params);
1193             return NULL;
1194          }
1195       }
1196    }
1197
1198    return cgi_params;
1199
1200 }
1201
1202
1203 /*********************************************************************
1204  *
1205  * Function    :  get_char_param
1206  *
1207  * Description :  Get a single-character parameter passed to a CGI
1208  *                function.
1209  *
1210  * Parameters  :
1211  *          1  :  parameters = map of cgi parameters
1212  *          2  :  param_name = The name of the parameter to read
1213  *
1214  * Returns     :  Uppercase character on success, '\0' on error.
1215  *
1216  *********************************************************************/
1217 char get_char_param(const struct map *parameters,
1218                     const char *param_name)
1219 {
1220    char ch;
1221
1222    assert(parameters);
1223    assert(param_name);
1224
1225    ch = *(lookup(parameters, param_name));
1226    if ((ch >= 'a') && (ch <= 'z'))
1227    {
1228       ch = (char)(ch - 'a' + 'A');
1229    }
1230
1231    return ch;
1232 }
1233
1234
1235 /*********************************************************************
1236  *
1237  * Function    :  get_string_param
1238  *
1239  * Description :  Get a string paramater, to be used as an
1240  *                ACTION_STRING or ACTION_MULTI paramater.
1241  *                Validates the input to prevent stupid/malicious
1242  *                users from corrupting their action file.
1243  *
1244  * Parameters  :
1245  *          1  :  parameters = map of cgi parameters
1246  *          2  :  param_name = The name of the parameter to read
1247  *          3  :  pparam = destination for paramater.  Allocated as
1248  *                part of the map "parameters", so don't free it.
1249  *                Set to NULL if not specified.
1250  *
1251  * Returns     :  JB_ERR_OK         on success, or if the paramater
1252  *                                  was not specified.
1253  *                JB_ERR_MEMORY     on out-of-memory.
1254  *                JB_ERR_CGI_PARAMS if the paramater is not valid.
1255  *
1256  *********************************************************************/
1257 jb_err get_string_param(const struct map *parameters,
1258                         const char *param_name,
1259                         const char **pparam)
1260 {
1261    const char *param;
1262    const char *s;
1263    char ch;
1264
1265    assert(parameters);
1266    assert(param_name);
1267    assert(pparam);
1268
1269    *pparam = NULL;
1270
1271    param = lookup(parameters, param_name);
1272    if (!*param)
1273    {
1274       return JB_ERR_OK;
1275    }
1276
1277    if (strlen(param) >= CGI_PARAM_LEN_MAX)
1278    {
1279       /*
1280        * Too long.
1281        *
1282        * Note that the length limit is arbitrary, it just seems
1283        * sensible to limit it to *something*.  There's no
1284        * technical reason for any limit at all.
1285        */
1286       return JB_ERR_CGI_PARAMS;
1287    }
1288
1289    /* Check every character to see if it's legal */
1290    s = param;
1291    while ((ch = *s++) != '\0')
1292    {
1293       if ( ((unsigned char)ch < (unsigned char)' ')
1294         || (ch == '}') )
1295       {
1296          /* Probable hack attempt, or user accidentally used '}'. */
1297          return JB_ERR_CGI_PARAMS;
1298       }
1299    }
1300
1301    /* Success */
1302    *pparam = param;
1303
1304    return JB_ERR_OK;
1305 }
1306
1307
1308 /*********************************************************************
1309  *
1310  * Function    :  get_number_param
1311  *
1312  * Description :  Get a non-negative integer from the parameters
1313  *                passed to a CGI function.
1314  *
1315  * Parameters  :
1316  *          1  :  csp = Current client state (buffers, headers, etc...)
1317  *          2  :  parameters = map of cgi parameters
1318  *          3  :  name = Name of CGI parameter to read
1319  *          4  :  pvalue = destination for value.
1320  *                         Set to -1 on error.
1321  *
1322  * Returns     :  JB_ERR_OK         on success
1323  *                JB_ERR_MEMORY     on out-of-memory
1324  *                JB_ERR_CGI_PARAMS if the parameter was not specified
1325  *                                  or is not valid.
1326  *
1327  *********************************************************************/
1328 jb_err get_number_param(struct client_state *csp,
1329                         const struct map *parameters,
1330                         char *name,
1331                         unsigned *pvalue)
1332 {
1333    const char *param;
1334    char ch;
1335    unsigned value;
1336
1337    assert(csp);
1338    assert(parameters);
1339    assert(name);
1340    assert(pvalue);
1341
1342    *pvalue = 0; 
1343
1344    param = lookup(parameters, name);
1345    if (!*param)
1346    {
1347       return JB_ERR_CGI_PARAMS;
1348    }
1349
1350    /* We don't use atoi because I want to check this carefully... */
1351
1352    value = 0;
1353    while ((ch = *param++) != '\0')
1354    {
1355       if ((ch < '0') || (ch > '9'))
1356       {
1357          return JB_ERR_CGI_PARAMS;
1358       }
1359
1360       ch = (char)(ch - '0');
1361
1362       /* Note:
1363        *
1364        * <limits.h> defines UINT_MAX
1365        *
1366        * (UINT_MAX - ch) / 10 is the largest number that
1367        *     can be safely multiplied by 10 then have ch added.
1368        */
1369       if (value > ((UINT_MAX - (unsigned)ch) / 10U))
1370       {
1371          return JB_ERR_CGI_PARAMS;
1372       }
1373
1374       value = value * 10 + (unsigned)ch;
1375    }
1376
1377    /* Success */
1378    *pvalue = value;
1379
1380    return JB_ERR_OK;
1381
1382 }
1383
1384
1385 /*********************************************************************
1386  *
1387  * Function    :  error_response
1388  *
1389  * Description :  returns an http_response that explains the reason
1390  *                why a request failed.
1391  *
1392  * Parameters  :
1393  *          1  :  csp = Current client state (buffers, headers, etc...)
1394  *          2  :  templatename = Which template should be used for the answer
1395  *          3  :  sys_err = system error number
1396  *
1397  * Returns     :  A http_response.  If we run out of memory, this
1398  *                will be cgi_error_memory().
1399  *
1400  *********************************************************************/
1401 struct http_response *error_response(struct client_state *csp,
1402                                      const char *templatename,
1403                                      int sys_err)
1404 {
1405    jb_err err;
1406    struct http_response *rsp;
1407    struct map *exports = default_exports(csp, NULL);
1408    char *path = NULL;
1409
1410    if (exports == NULL)
1411    {
1412       return cgi_error_memory();
1413    }
1414
1415    if (NULL == (rsp = alloc_http_response()))
1416    {
1417       free_map(exports);
1418       return cgi_error_memory();
1419    }
1420
1421 #ifdef FEATURE_FORCE_LOAD
1422    if (csp->flags & CSP_FLAG_FORCED)
1423    {
1424       path = strdup(FORCE_PREFIX);
1425    }
1426    else
1427 #endif /* def FEATURE_FORCE_LOAD */
1428    {
1429       path = strdup("");
1430    }
1431    err = string_append(&path, csp->http->path);
1432
1433    if (!err) err = map(exports, "host", 1, html_encode(csp->http->host), 0);
1434    if (!err) err = map(exports, "hostport", 1, html_encode(csp->http->hostport), 0);
1435    if (!err) err = map(exports, "path", 1, html_encode_and_free_original(path), 0);
1436    if (!err) err = map(exports, "error", 1, html_encode_and_free_original(safe_strerror(sys_err)), 0);
1437    if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1); 
1438    if (!err)
1439    {
1440      err = map(exports, "host-ip", 1, html_encode(csp->http->host_ip_addr_str), 0);
1441      if (err)
1442      {
1443        /* Some failures, like "404 no such domain", don't have an IP address. */
1444        err = map(exports, "host-ip", 1, html_encode(csp->http->host), 0);
1445      }
1446    }
1447
1448
1449    if (err)
1450    {
1451       free_map(exports);
1452       free_http_response(rsp);
1453       return cgi_error_memory();
1454    }
1455
1456    if (!strcmp(templatename, "no-such-domain"))
1457    {
1458       rsp->status = strdup("404 No such domain");
1459       if (rsp->status == NULL)
1460       {
1461          free_map(exports);
1462          free_http_response(rsp);
1463          return cgi_error_memory();
1464       }
1465       rsp->reason = RSP_REASON_NO_SUCH_DOMAIN;
1466    }
1467    else if (!strcmp(templatename, "forwarding-failed"))
1468    {
1469       const struct forward_spec *fwd = forward_url(csp, csp->http);
1470       char *socks_type = NULL;
1471       if (fwd == NULL)
1472       {
1473          log_error(LOG_LEVEL_FATAL, "gateway spec is NULL. This shouldn't happen!");
1474          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1475       }
1476
1477       /*
1478        * XXX: While the template is called forwarding-failed,
1479        * it currently only handles socks forwarding failures.
1480        */
1481       assert(fwd->type != SOCKS_NONE);
1482
1483       /*
1484        * Map failure reason, forwarding type and forwarder.
1485        */
1486       if (NULL == csp->error_message)
1487       {
1488          /*
1489           * Either we forgot to record the failure reason,
1490           * or the memory allocation failed.
1491           */
1492          log_error(LOG_LEVEL_ERROR, "Socks failure reason missing.");
1493          csp->error_message = strdup("Failure reason missing. Check the log file for details.");
1494       }
1495       if (!err) err = map(exports, "gateway", 1, fwd->gateway_host, 1);
1496
1497       /*
1498        * XXX: this is almost the same code as in cgi_show_url_info()
1499        * and thus should be factored out and shared.
1500        */
1501       switch (fwd->type)
1502       {
1503          case SOCKS_4:
1504             socks_type = "socks4-";
1505             break;
1506          case SOCKS_4A:
1507             socks_type = "socks4a-";
1508             break;
1509          case SOCKS_5:
1510             socks_type = "socks5-";
1511             break;
1512          default:
1513             log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
1514       }
1515
1516       if (!err) err = map(exports, "forwarding-type", 1, socks_type, 1);
1517       if (!err) err = map(exports, "error-message", 1, html_encode(csp->error_message), 0);
1518
1519       if (!err) rsp->status = strdup("503 Forwarding failure");
1520       if ((rsp->status == NULL) || (NULL == csp->error_message) || err)
1521       {
1522          free_map(exports);
1523          free_http_response(rsp);
1524          return cgi_error_memory();
1525       }
1526       rsp->reason = RSP_REASON_FORWARDING_FAILED;
1527    }
1528    else if (!strcmp(templatename, "connect-failed"))
1529    {
1530       rsp->status = strdup("503 Connect failed");
1531       if (rsp->status == NULL)
1532       {
1533          free_map(exports);
1534          free_http_response(rsp);
1535          return cgi_error_memory();
1536       }
1537       rsp->reason = RSP_REASON_CONNECT_FAILED;
1538    }
1539
1540    err = template_fill_for_cgi(csp, templatename, exports, rsp);
1541    if (err)
1542    {
1543       free_http_response(rsp);
1544       return cgi_error_memory();
1545    }
1546
1547    return finish_http_response(csp, rsp);
1548 }
1549
1550
1551 /*********************************************************************
1552  *
1553  * Function    :  cgi_error_disabled
1554  *
1555  * Description :  CGI function that is called to generate an error
1556  *                response if the actions editor or toggle CGI are
1557  *                accessed despite having being disabled at compile-
1558  *                or run-time, or if the user followed an untrusted link
1559  *                to access a unsafe CGI feature that is only reachable
1560  *                through Privoxy directly.
1561  *
1562  * Parameters  :
1563  *          1  :  csp = Current client state (buffers, headers, etc...)
1564  *          2  :  rsp = http_response data structure for output
1565  *
1566  * CGI Parameters : none
1567  *
1568  * Returns     :  JB_ERR_OK on success
1569  *                JB_ERR_MEMORY on out-of-memory error.
1570  *
1571  *********************************************************************/
1572 jb_err cgi_error_disabled(const struct client_state *csp,
1573                           struct http_response *rsp)
1574 {
1575    struct map *exports;
1576
1577    assert(csp);
1578    assert(rsp);
1579
1580    if (NULL == (exports = default_exports(csp, "cgi-error-disabled")))
1581    {
1582       return JB_ERR_MEMORY;
1583    }
1584    if (map(exports, "url", 1, html_encode(csp->http->url), 0))
1585    {
1586       /* Not important enough to do anything */
1587       log_error(LOG_LEVEL_ERROR, "Failed to fill in url.");
1588    }
1589
1590    return template_fill_for_cgi(csp, "cgi-error-disabled", exports, rsp);
1591 }
1592
1593
1594 /*********************************************************************
1595  *
1596  * Function    :  cgi_init_error_messages
1597  *
1598  * Description :  Call at the start of the program to initialize
1599  *                the error message used by cgi_error_memory().
1600  *
1601  * Parameters  :  N/A
1602  *
1603  * Returns     :  N/A
1604  *
1605  *********************************************************************/
1606 void cgi_init_error_messages(void)
1607 {
1608    memset(cgi_error_memory_response, '\0', sizeof(*cgi_error_memory_response));
1609    cgi_error_memory_response->head =
1610       "HTTP/1.0 500 Internal Privoxy Error\r\n"
1611       "Content-Type: text/html\r\n"
1612       "\r\n";
1613    cgi_error_memory_response->body =
1614       "<html>\r\n"
1615       "<head>\r\n"
1616       " <title>500 Internal Privoxy Error</title>\r\n"
1617       " <link rel=\"shortcut icon\" href=\"" CGI_PREFIX "error-favicon.ico\" type=\"image/x-icon\">"
1618       "</head>\r\n"
1619       "<body>\r\n"
1620       "<h1>500 Internal Privoxy Error</h1>\r\n"
1621       "<p>Privoxy <b>ran out of memory</b> while processing your request.</p>\r\n"
1622       "<p>Please contact your proxy administrator, or try again later</p>\r\n"
1623       "</body>\r\n"
1624       "</html>\r\n";
1625
1626    cgi_error_memory_response->head_length =
1627       strlen(cgi_error_memory_response->head);
1628    cgi_error_memory_response->content_length =
1629       strlen(cgi_error_memory_response->body);
1630    cgi_error_memory_response->reason = RSP_REASON_OUT_OF_MEMORY;
1631 }
1632
1633
1634 /*********************************************************************
1635  *
1636  * Function    :  cgi_error_memory
1637  *
1638  * Description :  Called if a CGI function runs out of memory.
1639  *                Returns a statically-allocated error response.
1640  *
1641  * Parameters  :  N/A
1642  *
1643  * Returns     :  http_response data structure for output.  This is
1644  *                statically allocated, for obvious reasons.
1645  *
1646  *********************************************************************/
1647 struct http_response *cgi_error_memory(void)
1648 {
1649    /* assert that it's been initialized. */
1650    assert(cgi_error_memory_response->head);
1651
1652    return cgi_error_memory_response;
1653 }
1654
1655
1656 /*********************************************************************
1657  *
1658  * Function    :  cgi_error_no_template
1659  *
1660  * Description :  Almost-CGI function that is called if a template
1661  *                cannot be loaded.  Note this is not a true CGI,
1662  *                it takes a template name rather than a map of 
1663  *                parameters.
1664  *
1665  * Parameters  :
1666  *          1  :  csp = Current client state (buffers, headers, etc...)
1667  *          2  :  rsp = http_response data structure for output
1668  *          3  :  template_name = Name of template that could not
1669  *                                be loaded.
1670  *
1671  * Returns     :  JB_ERR_OK on success
1672  *                JB_ERR_MEMORY on out-of-memory error.  
1673  *
1674  *********************************************************************/
1675 jb_err cgi_error_no_template(const struct client_state *csp,
1676                              struct http_response *rsp,
1677                              const char *template_name)
1678 {
1679    static const char status[] =
1680       "500 Internal Privoxy Error";
1681    static const char body_prefix[] =
1682       "<html>\r\n"
1683       "<head>\r\n"
1684       " <title>500 Internal Privoxy Error</title>\r\n"
1685       " <link rel=\"shortcut icon\" href=\"" CGI_PREFIX "error-favicon.ico\" type=\"image/x-icon\">"
1686       "</head>\r\n"
1687       "<body>\r\n"
1688       "<h1>500 Internal Privoxy Error</h1>\r\n"
1689       "<p>Privoxy encountered an error while processing your request:</p>\r\n"
1690       "<p><b>Could not load template file <code>";
1691    static const char body_suffix[] =
1692       "</code> or one of its included components.</b></p>\r\n"
1693       "<p>Please contact your proxy administrator.</p>\r\n"
1694       "<p>If you are the proxy administrator, please put the required file(s)"
1695       "in the <code><i>(confdir)</i>/templates</code> directory.  The "
1696       "location of the <code><i>(confdir)</i></code> directory "
1697       "is specified in the main Privoxy <code>config</code> "
1698       "file.  (It's typically the Privoxy install directory"
1699 #ifndef _WIN32
1700       ", or <code>/etc/privoxy/</code>"
1701 #endif /* ndef _WIN32 */
1702       ").</p>\r\n"
1703       "</body>\r\n"
1704       "</html>\r\n";
1705    const size_t body_size = strlen(body_prefix) + strlen(template_name) + strlen(body_suffix) + 1;
1706
1707    assert(csp);
1708    assert(rsp);
1709    assert(template_name);
1710
1711    /* Reset rsp, if needed */
1712    freez(rsp->status);
1713    freez(rsp->head);
1714    freez(rsp->body);
1715    rsp->content_length = 0;
1716    rsp->head_length = 0;
1717    rsp->is_static = 0;
1718
1719    rsp->body = malloc(body_size);
1720    if (rsp->body == NULL)
1721    {
1722       return JB_ERR_MEMORY;
1723    }
1724    strlcpy(rsp->body, body_prefix, body_size);
1725    strlcat(rsp->body, template_name, body_size);
1726    strlcat(rsp->body, body_suffix, body_size);
1727
1728    rsp->status = strdup(status);
1729    if (rsp->status == NULL)
1730    {
1731       return JB_ERR_MEMORY;
1732    }
1733
1734    return JB_ERR_OK;
1735 }
1736
1737
1738 /*********************************************************************
1739  *
1740  * Function    :  cgi_error_unknown
1741  *
1742  * Description :  Almost-CGI function that is called if an unexpected
1743  *                error occurs in the top-level CGI dispatcher.
1744  *                In this context, "unexpected" means "anything other
1745  *                than JB_ERR_MEMORY or JB_ERR_CGI_PARAMS" - CGIs are
1746  *                expected to handle all other errors internally,
1747  *                since they can give more relavent error messages
1748  *                that way.
1749  *
1750  *                Note this is not a true CGI, it takes an error
1751  *                code rather than a map of parameters.
1752  *
1753  * Parameters  :
1754  *          1  :  csp = Current client state (buffers, headers, etc...)
1755  *          2  :  rsp = http_response data structure for output
1756  *          3  :  error_to_report = Error code to report.
1757  *
1758  * Returns     :  JB_ERR_OK on success
1759  *                JB_ERR_MEMORY on out-of-memory error.  
1760  *
1761  *********************************************************************/
1762 jb_err cgi_error_unknown(const struct client_state *csp,
1763                          struct http_response *rsp,
1764                          jb_err error_to_report)
1765 {
1766    static const char status[] =
1767       "500 Internal Privoxy Error";
1768    static const char body_prefix[] =
1769       "<html>\r\n"
1770       "<head>\r\n"
1771       " <title>500 Internal Privoxy Error</title>\r\n"
1772       " <link rel=\"shortcut icon\" href=\"" CGI_PREFIX "error-favicon.ico\" type=\"image/x-icon\">"
1773       "</head>\r\n"
1774       "<body>\r\n"
1775       "<h1>500 Internal Privoxy Error</h1>\r\n"
1776       "<p>Privoxy encountered an error while processing your request:</p>\r\n"
1777       "<p><b>Unexpected internal error: ";
1778    static const char body_suffix[] =
1779       "</b></p>\r\n"
1780       "<p>Please "
1781       "<a href=\"http://sourceforge.net/tracker/?group_id=11118&amp;atid=111118\">"
1782       "file a bug report</a>.</p>\r\n"
1783       "</body>\r\n"
1784       "</html>\r\n";
1785    char errnumbuf[30];
1786    /*
1787     * Due to sizeof(errnumbuf), body_size will be slightly
1788     * bigger than necessary but it doesn't really matter.
1789     */
1790    const size_t body_size = strlen(body_prefix) + sizeof(errnumbuf) + strlen(body_suffix) + 1;
1791    assert(csp);
1792    assert(rsp);
1793
1794    /* Reset rsp, if needed */
1795    freez(rsp->status);
1796    freez(rsp->head);
1797    freez(rsp->body);
1798    rsp->content_length = 0;
1799    rsp->head_length = 0;
1800    rsp->is_static = 0;
1801    rsp->reason = RSP_REASON_INTERNAL_ERROR;
1802
1803    snprintf(errnumbuf, sizeof(errnumbuf), "%d", error_to_report);
1804
1805    rsp->body = malloc(body_size);
1806    if (rsp->body == NULL)
1807    {
1808       return JB_ERR_MEMORY;
1809    }
1810    strlcpy(rsp->body, body_prefix, body_size);
1811    strlcat(rsp->body, errnumbuf,   body_size);
1812    strlcat(rsp->body, body_suffix, body_size);
1813
1814    rsp->status = strdup(status);
1815    if (rsp->status == NULL)
1816    {
1817       return JB_ERR_MEMORY;
1818    }
1819
1820    return JB_ERR_OK;
1821 }
1822
1823
1824 /*********************************************************************
1825  *
1826  * Function    :  cgi_error_bad_param
1827  *
1828  * Description :  CGI function that is called if the parameters
1829  *                (query string) for a CGI were wrong.
1830  *               
1831  * Parameters  :
1832  *          1  :  csp = Current client state (buffers, headers, etc...)
1833  *          2  :  rsp = http_response data structure for output
1834  *
1835  * CGI Parameters : none
1836  *
1837  * Returns     :  JB_ERR_OK on success
1838  *                JB_ERR_MEMORY on out-of-memory error.  
1839  *
1840  *********************************************************************/
1841 jb_err cgi_error_bad_param(const struct client_state *csp,
1842                            struct http_response *rsp)
1843 {
1844    struct map *exports;
1845
1846    assert(csp);
1847    assert(rsp);
1848
1849    if (NULL == (exports = default_exports(csp, NULL)))
1850    {
1851       return JB_ERR_MEMORY;
1852    }
1853
1854    return template_fill_for_cgi(csp, "cgi-error-bad-param", exports, rsp);
1855 }
1856
1857
1858 /*********************************************************************
1859  *
1860  * Function    :  cgi_redirect 
1861  *
1862  * Description :  CGI support function to generate a HTTP redirect
1863  *                message
1864  *
1865  * Parameters  :
1866  *          1  :  rsp = http_response data structure for output
1867  *          2  :  target = string with the target URL
1868  *
1869  * CGI Parameters : None
1870  *
1871  * Returns     :  JB_ERR_OK on success
1872  *                JB_ERR_MEMORY on out-of-memory error.  
1873  *
1874  *********************************************************************/
1875 jb_err cgi_redirect (struct http_response * rsp, const char *target)
1876 {
1877    jb_err err;
1878
1879    assert(rsp);
1880    assert(target);
1881
1882    err = enlist_unique_header(rsp->headers, "Location", target);
1883
1884    rsp->status = strdup("302 Local Redirect from Privoxy");
1885    if (rsp->status == NULL)
1886    {
1887       return JB_ERR_MEMORY;
1888    }
1889
1890    return err;
1891 }
1892
1893
1894 /*********************************************************************
1895  *
1896  * Function    :  add_help_link
1897  *
1898  * Description :  Produce a copy of the string given as item,
1899  *                embedded in an HTML link to its corresponding
1900  *                section (item name in uppercase) in the actions
1901  *                chapter of the user manual, (whose URL is given in
1902  *                the config and defaults to our web site).
1903  *
1904  *                FIXME: I currently only work for actions, and would
1905  *                       like to be generalized for other topics.
1906  *
1907  * Parameters  :  
1908  *          1  :  item = item (will NOT be free()d.) 
1909  *                       It is assumed to be HTML-safe.
1910  *          2  :  config = The current configuration.
1911  *
1912  * Returns     :  String with item embedded in link, or NULL on
1913  *                out-of-memory
1914  *
1915  *********************************************************************/
1916 char *add_help_link(const char *item,
1917                     struct configuration_spec *config)
1918 {
1919    char *result;
1920
1921    if (!item) return NULL;
1922
1923    result = strdup("<a href=\"");
1924    if (!strncmpic(config->usermanual, "file://", 7) ||
1925        !strncmpic(config->usermanual, "http", 4))
1926    {
1927       string_append(&result, config->usermanual);
1928    }
1929    else
1930    {
1931       string_append(&result, "http://");
1932       string_append(&result, CGI_SITE_2_HOST);
1933       string_append(&result, "/user-manual/");
1934    }
1935    string_append(&result, ACTIONS_HELP_PREFIX);
1936    string_join  (&result, string_toupper(item));
1937    string_append(&result, "\">");
1938    string_append(&result, item);
1939    string_append(&result, "</a> ");
1940
1941    return result;
1942 }
1943
1944
1945 /*********************************************************************
1946  *
1947  * Function    :  get_http_time
1948  *
1949  * Description :  Get the time in a format suitable for use in a
1950  *                HTTP header - e.g.:
1951  *                "Sun, 06 Nov 1994 08:49:37 GMT"
1952  *
1953  * Parameters  :  
1954  *          1  :  time_offset = Time returned will be current time
1955  *                              plus this number of seconds.
1956  *          2  :  buf = Destination for result.
1957  *          3  :  buffer_size = Size of the buffer above. Must be big
1958  *                              enough to hold 29 characters plus a
1959  *                              trailing zero.
1960  *
1961  * Returns     :  N/A
1962  *
1963  *********************************************************************/
1964 void get_http_time(int time_offset, char *buf, size_t buffer_size)
1965 {
1966    static const char day_names[7][4] =
1967       { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
1968    static const char month_names[12][4] =
1969       { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1970         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1971
1972    struct tm *t;
1973    time_t current_time;
1974 #if defined(HAVE_GMTIME_R)
1975    struct tm dummy;
1976 #endif
1977
1978    assert(buf);
1979    assert(buffer_size > 29);
1980
1981    time(&current_time);
1982
1983    current_time += time_offset;
1984
1985    /* get and save the gmt */
1986 #if HAVE_GMTIME_R
1987    t = gmtime_r(&current_time, &dummy);
1988 #elif FEATURE_PTHREAD
1989    pthread_mutex_lock(&gmtime_mutex);
1990    t = gmtime(&current_time);
1991    pthread_mutex_unlock(&gmtime_mutex);
1992 #else
1993    t = gmtime(&current_time);
1994 #endif
1995
1996    /* Format: "Sun, 06 Nov 1994 08:49:37 GMT" */
1997    snprintf(buf, buffer_size,
1998       "%s, %02d %s %4d %02d:%02d:%02d GMT",
1999       day_names[t->tm_wday],
2000       t->tm_mday,
2001       month_names[t->tm_mon],
2002       t->tm_year + 1900,
2003       t->tm_hour,
2004       t->tm_min,
2005       t->tm_sec
2006       );
2007
2008 }
2009
2010
2011 /*********************************************************************
2012  *
2013  * Function    :  finish_http_response
2014  *
2015  * Description :  Fill in the missing headers in an http response,
2016  *                and flatten the headers to an http head.
2017  *                For HEAD requests the body is freed once
2018  *                the Content-Length header is set.
2019  *
2020  * Parameters  :
2021  *          1  :  rsp = pointer to http_response to be processed
2022  *
2023  * Returns     :  A http_response, usually the rsp parameter.
2024  *                On error, free()s rsp and returns cgi_error_memory()
2025  *
2026  *********************************************************************/
2027 struct http_response *finish_http_response(const struct client_state *csp, struct http_response *rsp)
2028 {
2029    char buf[BUFFER_SIZE];
2030    jb_err err;
2031
2032    /* Special case - do NOT change this statically allocated response,
2033     * which is ready for output anyway.
2034     */
2035    if (rsp == cgi_error_memory_response)
2036    {
2037       return rsp;
2038    }
2039
2040    /* 
2041     * Fill in the HTTP Status, using HTTP/1.1
2042     * unless the client asked for HTTP/1.0.
2043     */
2044    snprintf(buf, sizeof(buf), "%s %s",
2045       strcmpic(csp->http->ver, "HTTP/1.0") ? "HTTP/1.1" : "HTTP/1.0",
2046       rsp->status ? rsp->status : "200 OK");
2047    err = enlist_first(rsp->headers, buf);
2048
2049    /* 
2050     * Set the Content-Length
2051     */
2052    if (rsp->content_length == 0)
2053    {
2054       rsp->content_length = rsp->body ? strlen(rsp->body) : 0;
2055    }
2056    if (!err)
2057    {
2058       snprintf(buf, sizeof(buf), "Content-Length: %d", (int)rsp->content_length);
2059       err = enlist(rsp->headers, buf);
2060    }
2061
2062    if (0 == strcmpic(csp->http->gpc, "head"))
2063    {
2064       /*
2065        * The client only asked for the head. Dispose
2066        * the body and log an offensive message.
2067        *
2068        * While it may seem to be a bit inefficient to
2069        * prepare the body if it isn't needed, it's the
2070        * only way to get the Content-Length right for
2071        * dynamic pages. We could have disposed the body
2072        * earlier, but not without duplicating the
2073        * Content-Length setting code above.
2074        */
2075       log_error(LOG_LEVEL_CGI, "Preparing to give head to %s.", csp->ip_addr_str);
2076       freez(rsp->body);
2077       rsp->content_length = 0;
2078    }
2079
2080    if (strncmpic(rsp->status, "302", 3))
2081    {
2082       /*
2083        * If it's not a redirect without any content,
2084        * set the Content-Type to text/html if it's
2085        * not already specified.
2086        */
2087       if (!err) err = enlist_unique(rsp->headers, "Content-Type: text/html", 13);
2088    }
2089
2090    /*
2091     * Fill in the rest of the default headers:
2092     *
2093     * Date: set to current date/time.
2094     * Last-Modified: set to date/time the page was last changed.
2095     * Expires: set to date/time page next needs reloading.
2096     * Cache-Control: set to "no-cache" if applicable.
2097     * 
2098     * See http://www.w3.org/Protocols/rfc2068/rfc2068
2099     */
2100    if (rsp->is_static)
2101    {
2102       /*
2103        * Set Expires to about 10 min into the future so it'll get reloaded
2104        * occasionally, e.g. if Privoxy gets upgraded.
2105        */
2106
2107       if (!err)
2108       {
2109          get_http_time(0, buf, sizeof(buf));
2110          err = enlist_unique_header(rsp->headers, "Date", buf);
2111       }
2112
2113       /* Some date in the past. */
2114       if (!err) err = enlist_unique_header(rsp->headers, "Last-Modified", "Sat, 17 Jun 2000 12:00:00 GMT");
2115
2116       if (!err)
2117       {
2118          get_http_time(10 * 60, buf, sizeof(buf)); /* 10 * 60sec = 10 minutes */
2119          err = enlist_unique_header(rsp->headers, "Expires", buf);
2120       }
2121    }
2122    else if (!strncmpic(rsp->status, "302", 3))
2123    {
2124       get_http_time(0, buf, sizeof(buf));
2125       if (!err) err = enlist_unique_header(rsp->headers, "Date", buf);
2126    }
2127    else
2128    {
2129       /*
2130        * Setting "Cache-Control" to "no-cache" and  "Expires" to
2131        * the current time doesn't exactly forbid caching, it just
2132        * requires the client to revalidate the cached copy.
2133        *
2134        * If a temporary problem occurs and the user tries again after
2135        * getting Privoxy's error message, a compliant browser may set the
2136        * If-Modified-Since header with the content of the error page's
2137        * Last-Modified header. More often than not, the document on the server
2138        * is older than Privoxy's error message, the server would send status code
2139        * 304 and the browser would display the outdated error message again and again.
2140        *
2141        * For documents delivered with status code 403, 404 and 503 we set "Last-Modified"
2142        * to Tim Berners-Lee's birthday, which predates the age of any page on the web
2143        * and can be safely used to "revalidate" without getting a status code 304.
2144        *
2145        * There is no need to let the useless If-Modified-Since header reach the
2146        * server, it is therefore stripped by client_if_modified_since in parsers.c.
2147        */
2148       if (!err) err = enlist_unique_header(rsp->headers, "Cache-Control", "no-cache");
2149
2150       get_http_time(0, buf, sizeof(buf));
2151       if (!err) err = enlist_unique_header(rsp->headers, "Date", buf);
2152       if (!strncmpic(rsp->status, "403", 3)
2153        || !strncmpic(rsp->status, "404", 3)
2154        || !strncmpic(rsp->status, "503", 3))
2155       {
2156          if (!err) err = enlist_unique_header(rsp->headers, "Last-Modified", "Wed, 08 Jun 1955 12:00:00 GMT");
2157       }
2158       else
2159       {
2160          if (!err) err = enlist_unique_header(rsp->headers, "Last-Modified", buf);
2161       }
2162       if (!err) err = enlist_unique_header(rsp->headers, "Expires", "Sat, 17 Jun 2000 12:00:00 GMT");
2163       if (!err) err = enlist_unique_header(rsp->headers, "Pragma", "no-cache");
2164    }
2165
2166    /*
2167     * Quoting RFC 2616:
2168     *
2169     * HTTP/1.1 applications that do not support persistent connections MUST
2170     * include the "close" connection option in every message.
2171     */
2172    if (!err) err = enlist_unique_header(rsp->headers, "Connection", "close");
2173
2174    /* 
2175     * Write the head
2176     */
2177    if (err || (NULL == (rsp->head = list_to_text(rsp->headers))))
2178    {
2179       free_http_response(rsp);
2180       return cgi_error_memory();
2181    }
2182    rsp->head_length = strlen(rsp->head);
2183
2184    return rsp;
2185
2186 }
2187
2188
2189 /*********************************************************************
2190  *
2191  * Function    :  alloc_http_response
2192  *
2193  * Description :  Allocates a new http_response structure.
2194  *
2195  * Parameters  :  N/A
2196  *
2197  * Returns     :  pointer to a new http_response, or NULL.
2198  *
2199  *********************************************************************/
2200 struct http_response *alloc_http_response(void)
2201 {
2202    return (struct http_response *) zalloc(sizeof(struct http_response));
2203
2204 }
2205
2206
2207 /*********************************************************************
2208  *
2209  * Function    :  free_http_response
2210  *
2211  * Description :  Free the memory occupied by an http_response
2212  *                and its depandant structures.
2213  *
2214  * Parameters  :
2215  *          1  :  rsp = pointer to http_response to be freed
2216  *
2217  * Returns     :  N/A
2218  *
2219  *********************************************************************/
2220 void free_http_response(struct http_response *rsp)
2221 {
2222    /*
2223     * Must special case cgi_error_memory_response, which is never freed.
2224     */
2225    if (rsp && (rsp != cgi_error_memory_response))
2226    {
2227       freez(rsp->status);
2228       freez(rsp->head);
2229       freez(rsp->body);
2230       destroy_list(rsp->headers);
2231       free(rsp);
2232    }
2233
2234 }
2235
2236
2237 /*********************************************************************
2238  *
2239  * Function    :  template_load
2240  *
2241  * Description :  CGI support function that loads a given HTML
2242  *                template, ignoring comment lines and following
2243  *                #include statements up to a depth of 1.
2244  *
2245  * Parameters  :
2246  *          1  :  csp = Current client state (buffers, headers, etc...)
2247  *          2  :  template_ptr = Destination for pointer to loaded
2248  *                               template text.
2249  *          3  :  templatename = name of the HTML template to be used
2250  *          4  :  recursive = Flag set if this function calls itself
2251  *                            following an #include statament
2252  *
2253  * Returns     :  JB_ERR_OK on success
2254  *                JB_ERR_MEMORY on out-of-memory error.  
2255  *                JB_ERR_FILE if the template file cannot be read
2256  *
2257  *********************************************************************/
2258 jb_err template_load(const struct client_state *csp, char **template_ptr, 
2259                      const char *templatename, int recursive)
2260 {
2261    jb_err err;
2262    char *templates_dir_path;
2263    char *full_path;
2264    char *file_buffer;
2265    char *included_module;
2266    const char *p;
2267    FILE *fp;
2268    char buf[BUFFER_SIZE];
2269
2270    assert(csp);
2271    assert(template_ptr);
2272    assert(templatename);
2273
2274    *template_ptr = NULL;
2275
2276    /* Validate template name.  Paranoia. */
2277    for (p = templatename; *p != 0; p++)
2278    {
2279       if ( ((*p < 'a') || (*p > 'z'))
2280         && ((*p < 'A') || (*p > 'Z'))
2281         && ((*p < '0') || (*p > '9'))
2282         && (*p != '-')
2283         && (*p != '.'))
2284       {
2285          /* Illegal character */
2286          return JB_ERR_FILE;
2287       }
2288    }
2289
2290    /*
2291     * Generate full path using either templdir
2292     * or confdir/templates as base directory.
2293     */
2294    if (NULL != csp->config->templdir)
2295    {
2296       templates_dir_path = strdup(csp->config->templdir);
2297    }
2298    else
2299    {
2300       templates_dir_path = make_path(csp->config->confdir, "templates");
2301    }
2302
2303    if (templates_dir_path == NULL)
2304    {
2305       log_error(LOG_LEVEL_ERROR, "Out of memory while generating template path for %s.",
2306          templatename);
2307       return JB_ERR_MEMORY;
2308    }
2309
2310    full_path = make_path(templates_dir_path, templatename);
2311    free(templates_dir_path);
2312    if (full_path == NULL)
2313    {
2314       log_error(LOG_LEVEL_ERROR, "Out of memory while generating full template path for %s.",
2315          templatename);
2316       return JB_ERR_MEMORY;
2317    }
2318
2319    /* Allocate buffer */
2320
2321    file_buffer = strdup("");
2322    if (file_buffer == NULL)
2323    {
2324       log_error(LOG_LEVEL_ERROR, "Not enough free memory to buffer %s.", full_path);
2325       free(full_path);
2326       return JB_ERR_MEMORY;
2327    }
2328
2329    /* Open template file */
2330
2331    if (NULL == (fp = fopen(full_path, "r")))
2332    {
2333       log_error(LOG_LEVEL_ERROR, "Cannot open template file %s: %E", full_path);
2334       free(full_path);
2335       free(file_buffer);
2336       return JB_ERR_FILE;
2337    }
2338    free(full_path);
2339
2340    /* 
2341     * Read the file, ignoring comments, and honoring #include
2342     * statements, unless we're already called recursively.
2343     *
2344     * FIXME: The comment handling could break with lines >BUFFER_SIZE long.
2345     *        This is unlikely in practise.
2346     */
2347    while (fgets(buf, BUFFER_SIZE, fp))
2348    {
2349       if (!recursive && !strncmp(buf, "#include ", 9))
2350       {
2351          if (JB_ERR_OK != (err = template_load(csp, &included_module, chomp(buf + 9), 1)))
2352          {
2353             free(file_buffer);
2354             fclose(fp);
2355             return err;
2356          }
2357
2358          if (string_join(&file_buffer, included_module))
2359          {
2360             fclose(fp);
2361             return JB_ERR_MEMORY;
2362          }
2363
2364          continue;
2365       }
2366
2367       /* skip lines starting with '#' */
2368       if (*buf == '#')
2369       {
2370          continue;
2371       }
2372
2373       if (string_append(&file_buffer, buf))
2374       {
2375          fclose(fp);
2376          return JB_ERR_MEMORY;
2377       }
2378    }
2379    fclose(fp);
2380
2381    *template_ptr = file_buffer;
2382
2383    return JB_ERR_OK;
2384 }
2385
2386
2387 /*********************************************************************
2388  *
2389  * Function    :  template_fill
2390  *
2391  * Description :  CGI support function that fills in a pre-loaded
2392  *                HTML template by replacing @name@ with value using
2393  *                pcrs, for each item in the output map.
2394  *
2395  *                Note that a leading '$' charachter in the export map's
2396  *                values will be stripped and toggle on backreference
2397  *                interpretation.
2398  *
2399  * Parameters  :
2400  *          1  :  template_ptr = IN: Template to be filled out.
2401  *                                   Will be free()d.
2402  *                               OUT: Filled out template.
2403  *                                    Caller must free().
2404  *          2  :  exports = map with fill in symbol -> name pairs
2405  *
2406  * Returns     :  JB_ERR_OK on success (and for uncritical errors)
2407  *                JB_ERR_MEMORY on out-of-memory error
2408  *
2409  *********************************************************************/
2410 jb_err template_fill(char **template_ptr, const struct map *exports)
2411 {
2412    struct map_entry *m;
2413    pcrs_job *job;
2414    char buf[BUFFER_SIZE];
2415    char *tmp_out_buffer;
2416    char *file_buffer;
2417    size_t  size;
2418    int error;
2419    const char *flags;
2420
2421    assert(template_ptr);
2422    assert(*template_ptr);
2423    assert(exports);
2424
2425    file_buffer = *template_ptr;
2426    size = strlen(file_buffer) + 1;
2427
2428    /* 
2429     * Assemble pcrs joblist from exports map
2430     */
2431    for (m = exports->first; m != NULL; m = m->next)
2432    {
2433       if (*m->name == '$')
2434       {
2435          /*
2436           * First character of name is '$', so remove this flag
2437           * character and allow backreferences ($1 etc) in the
2438           * "replace with" text.
2439           */
2440          snprintf(buf, BUFFER_SIZE, "%s", m->name + 1);
2441          flags = "sigU";
2442       }
2443       else
2444       {
2445          /*
2446           * Treat the "replace with" text as a literal string - 
2447           * no quoting needed, no backreferences allowed.
2448           * ("Trivial" ['T'] flag).
2449           */
2450          flags = "sigTU";
2451
2452          /* Enclose name in @@ */
2453          snprintf(buf, BUFFER_SIZE, "@%s@", m->name);
2454       }
2455
2456
2457       log_error(LOG_LEVEL_CGI, "Substituting: s/%s/%s/%s", buf, m->value, flags);
2458
2459       /* Make and run job. */
2460       job = pcrs_compile(buf, m->value, flags,  &error);
2461       if (job == NULL) 
2462       {
2463          if (error == PCRS_ERR_NOMEM)
2464          {
2465             free(file_buffer);
2466             *template_ptr = NULL;
2467             return JB_ERR_MEMORY;
2468          }
2469          else
2470          {
2471             log_error(LOG_LEVEL_ERROR, "Error compiling template fill job %s: %d", m->name, error);
2472             /* Hope it wasn't important and silently ignore the invalid job */
2473          }
2474       }
2475       else
2476       {
2477          error = pcrs_execute(job, file_buffer, size, &tmp_out_buffer, &size);
2478
2479          pcrs_free_job(job);
2480          if (NULL == tmp_out_buffer)
2481          {
2482             *template_ptr = NULL;
2483             return JB_ERR_MEMORY;
2484          }
2485
2486          if (error < 0)
2487          {
2488             /* 
2489              * Substitution failed, keep the original buffer,
2490              * log the problem and ignore it.
2491              * 
2492              * The user might see some unresolved @CGI_VARIABLES@,
2493              * but returning a special CGI error page seems unreasonable
2494              * and could mask more important error messages.
2495              */
2496             free(tmp_out_buffer);
2497             log_error(LOG_LEVEL_ERROR, "Failed to execute s/%s/%s/%s. %s",
2498                buf, m->value, flags, pcrs_strerror(error));
2499          }
2500          else
2501          {
2502             /* Substitution succeeded, use modified buffer. */
2503             free(file_buffer);
2504             file_buffer = tmp_out_buffer;
2505          }
2506       }
2507    }
2508
2509    /*
2510     * Return
2511     */
2512    *template_ptr = file_buffer;
2513    return JB_ERR_OK;
2514 }
2515
2516
2517 /*********************************************************************
2518  *
2519  * Function    :  template_fill_for_cgi
2520  *
2521  * Description :  CGI support function that loads a HTML template
2522  *                and fills it in.  Handles file-not-found errors
2523  *                by sending a HTML error message.  For convenience,
2524  *                this function also frees the passed "exports" map.
2525  *
2526  * Parameters  :
2527  *          1  :  csp = Client state
2528  *          2  :  templatename = name of the HTML template to be used
2529  *          3  :  exports = map with fill in symbol -> name pairs.
2530  *                          Will be freed by this function.
2531  *          4  :  rsp = Response structure to fill in.
2532  *
2533  * Returns     :  JB_ERR_OK on success
2534  *                JB_ERR_MEMORY on out-of-memory error
2535  *
2536  *********************************************************************/
2537 jb_err template_fill_for_cgi(const struct client_state *csp,
2538                              const char *templatename,
2539                              struct map *exports,
2540                              struct http_response *rsp)
2541 {
2542    jb_err err;
2543    
2544    assert(csp);
2545    assert(templatename);
2546    assert(exports);
2547    assert(rsp);
2548
2549    err = template_load(csp, &rsp->body, templatename, 0);
2550    if (err == JB_ERR_FILE)
2551    {
2552       free_map(exports);
2553       return cgi_error_no_template(csp, rsp, templatename);
2554    }
2555    else if (err)
2556    {
2557       free_map(exports);
2558       return err; /* JB_ERR_MEMORY */
2559    }
2560    err = template_fill(&rsp->body, exports);
2561    free_map(exports);
2562    return err;
2563 }
2564
2565
2566 /*********************************************************************
2567  *
2568  * Function    :  default_exports
2569  *
2570  * Description :  returns a struct map list that contains exports
2571  *                which are common to all CGI functions.
2572  *
2573  * Parameters  :
2574  *          1  :  csp = Current client state (buffers, headers, etc...)
2575  *          2  :  caller = name of CGI who calls us and which should
2576  *                         be excluded from the generated menu. May be
2577  *                         NULL.
2578  * Returns     :  NULL if no memory, else a new map.  Caller frees.
2579  *
2580  *********************************************************************/
2581 struct map *default_exports(const struct client_state *csp, const char *caller)
2582 {
2583    char buf[20];
2584    jb_err err;
2585    struct map * exports;
2586    int local_help_exists = 0;
2587    char *ip_address = NULL;
2588    char *hostname = NULL;
2589
2590    assert(csp);
2591
2592    exports = new_map();
2593    if (exports == NULL)
2594    {
2595       return NULL;
2596    }
2597
2598    if (csp->config->hostname)
2599    {
2600       get_host_information(csp->cfd, &ip_address, NULL);
2601       hostname = strdup(csp->config->hostname);
2602    }
2603    else
2604    {
2605       get_host_information(csp->cfd, &ip_address, &hostname);
2606    }
2607
2608    err = map(exports, "version", 1, html_encode(VERSION), 0);
2609    if (!err) err = map(exports, "my-ip-address", 1, html_encode(ip_address ? ip_address : "unknown"), 0);
2610    freez(ip_address);
2611    if (!err) err = map(exports, "my-hostname",   1, html_encode(hostname ? hostname : "unknown"), 0);
2612    freez(hostname);
2613    if (!err) err = map(exports, "homepage",      1, html_encode(HOME_PAGE_URL), 0);
2614    if (!err) err = map(exports, "default-cgi",   1, html_encode(CGI_PREFIX), 0);
2615    if (!err) err = map(exports, "menu",          1, make_menu(caller, csp->config->feature_flags), 0);
2616    if (!err) err = map(exports, "code-status",   1, CODE_STATUS, 1);
2617    if (!strncmpic(csp->config->usermanual, "file://", 7) ||
2618        !strncmpic(csp->config->usermanual, "http", 4))
2619    {
2620       /* Manual is located somewhere else, just link to it. */
2621       if (!err) err = map(exports, "user-manual", 1, html_encode(csp->config->usermanual), 0);
2622    }
2623    else
2624    {
2625       /* Manual is delivered by Privoxy. */
2626       if (!err) err = map(exports, "user-manual", 1, html_encode(CGI_PREFIX"user-manual/"), 0);
2627    }
2628    if (!err) err = map(exports, "actions-help-prefix", 1, ACTIONS_HELP_PREFIX ,1);
2629 #ifdef FEATURE_TOGGLE
2630    if (!err) err = map_conditional(exports, "enabled-display", global_toggle_state);
2631 #else
2632    if (!err) err = map_block_killer(exports, "can-toggle");
2633 #endif
2634
2635    snprintf(buf, sizeof(buf), "%d", csp->config->hport);
2636    if (!err) err = map(exports, "my-port", 1, buf, 1);
2637
2638    if(!strcmp(CODE_STATUS, "stable"))
2639    {
2640       if (!err) err = map_block_killer(exports, "unstable");
2641    }
2642
2643    if (csp->config->admin_address != NULL)
2644    {
2645       if (!err) err = map(exports, "admin-address", 1, html_encode(csp->config->admin_address), 0);
2646       local_help_exists = 1;
2647    }
2648    else
2649    {
2650       if (!err) err = map_block_killer(exports, "have-adminaddr-info");
2651    }
2652
2653    if (csp->config->proxy_info_url != NULL)
2654    {
2655       if (!err) err = map(exports, "proxy-info-url", 1, html_encode(csp->config->proxy_info_url), 0);
2656       local_help_exists = 1;
2657    }
2658    else
2659    {
2660       if (!err) err = map_block_killer(exports, "have-proxy-info");
2661    }
2662
2663    if (local_help_exists == 0)
2664    {
2665       if (!err) err = map_block_killer(exports, "have-help-info");
2666    }
2667
2668    if (err)
2669    {
2670       free_map(exports);
2671       return NULL;
2672    }
2673
2674    return exports;
2675 }
2676
2677
2678 /*********************************************************************
2679  *
2680  * Function    :  map_block_killer
2681  *
2682  * Description :  Convenience function.
2683  *                Adds a "killer" for the conditional HTML-template
2684  *                block <name>, i.e. a substitution of the regex
2685  *                "if-<name>-start.*if-<name>-end" to the given
2686  *                export list.
2687  *
2688  * Parameters  :  
2689  *          1  :  exports = map to extend
2690  *          2  :  name = name of conditional block
2691  *
2692  * Returns     :  JB_ERR_OK on success
2693  *                JB_ERR_MEMORY on out-of-memory error.  
2694  *
2695  *********************************************************************/
2696 jb_err map_block_killer(struct map *exports, const char *name)
2697 {
2698    char buf[1000]; /* Will do, since the names are hardwired */
2699
2700    assert(exports);
2701    assert(name);
2702    assert(strlen(name) < 490);
2703
2704    snprintf(buf, sizeof(buf), "if-%s-start.*if-%s-end", name, name);
2705    return map(exports, buf, 1, "", 1);
2706 }
2707
2708
2709 /*********************************************************************
2710  *
2711  * Function    :  map_block_keep
2712  *
2713  * Description :  Convenience function.  Removes the markers used
2714  *                by map-block-killer, to save a few bytes.
2715  *                i.e. removes "@if-<name>-start@" and "@if-<name>-end@"
2716  *
2717  * Parameters  :  
2718  *          1  :  exports = map to extend
2719  *          2  :  name = name of conditional block
2720  *
2721  * Returns     :  JB_ERR_OK on success
2722  *                JB_ERR_MEMORY on out-of-memory error.  
2723  *
2724  *********************************************************************/
2725 jb_err map_block_keep(struct map *exports, const char *name)
2726 {
2727    jb_err err;
2728    char buf[500]; /* Will do, since the names are hardwired */
2729
2730    assert(exports);
2731    assert(name);
2732    assert(strlen(name) < 490);
2733
2734    snprintf(buf, sizeof(buf), "if-%s-start", name);
2735    err = map(exports, buf, 1, "", 1);
2736
2737    if (err)
2738    {
2739       return err;
2740    }
2741
2742    snprintf(buf, sizeof(buf), "if-%s-end", name);
2743    return map(exports, buf, 1, "", 1);
2744 }
2745
2746
2747 /*********************************************************************
2748  *
2749  * Function    :  map_conditional
2750  *
2751  * Description :  Convenience function.
2752  *                Adds an "if-then-else" for the conditional HTML-template
2753  *                block <name>, i.e. a substitution of the form:
2754  *                @if-<name>-then@
2755  *                   True text
2756  *                @else-not-<name>@
2757  *                   False text
2758  *                @endif-<name>@
2759  *
2760  *                The control structure and one of the alternatives
2761  *                will be hidden.
2762  *
2763  * Parameters  :  
2764  *          1  :  exports = map to extend
2765  *          2  :  name = name of conditional block
2766  *          3  :  choose_first = nonzero for first, zero for second.
2767  *
2768  * Returns     :  JB_ERR_OK on success
2769  *                JB_ERR_MEMORY on out-of-memory error.  
2770  *
2771  *********************************************************************/
2772 jb_err map_conditional(struct map *exports, const char *name, int choose_first)
2773 {
2774    char buf[1000]; /* Will do, since the names are hardwired */
2775    jb_err err;
2776
2777    assert(exports);
2778    assert(name);
2779    assert(strlen(name) < 480);
2780
2781    snprintf(buf, sizeof(buf), (choose_first
2782       ? "else-not-%s@.*@endif-%s"
2783       : "if-%s-then@.*@else-not-%s"),
2784       name, name);
2785
2786    err = map(exports, buf, 1, "", 1);
2787    if (err)
2788    {
2789       return err;
2790    }
2791
2792    snprintf(buf, sizeof(buf), (choose_first ? "if-%s-then" : "endif-%s"), name);
2793    return map(exports, buf, 1, "", 1);
2794 }
2795
2796
2797 /*********************************************************************
2798  *
2799  * Function    :  make_menu
2800  *
2801  * Description :  Returns an HTML-formatted menu of the available 
2802  *                unhidden CGIs, excluding the one given in <self>
2803  *                and the toggle CGI if toggling is disabled.
2804  *
2805  * Parameters  :
2806  *          1  :  self = name of CGI to leave out, can be NULL for
2807  *                complete listing.
2808  *          2  :  feature_flags = feature bitmap from csp->config
2809  *                
2810  *
2811  * Returns     :  menu string, or NULL on out-of-memory error.
2812  *
2813  *********************************************************************/
2814 char *make_menu(const char *self, const unsigned feature_flags)
2815 {
2816    const struct cgi_dispatcher *d;
2817    char *result = strdup("");
2818
2819    if (self == NULL)
2820    {
2821       self = "NO-SUCH-CGI!";
2822    }
2823
2824    /* List available unhidden CGI's and export as "other-cgis" */
2825    for (d = cgi_dispatchers; d->name; d++)
2826    {
2827
2828 #ifdef FEATURE_TOGGLE
2829       if (!(feature_flags & RUNTIME_FEATURE_CGI_TOGGLE) && !strcmp(d->name, "toggle"))
2830       {
2831          /*
2832           * Suppress the toggle link if remote toggling is disabled.
2833           */
2834          continue;
2835       }
2836 #endif /* def FEATURE_TOGGLE */
2837
2838       if (d->description && strcmp(d->name, self))
2839       {
2840          char *html_encoded_prefix;
2841
2842          /*
2843           * Line breaks would be great, but break
2844           * the "blocked" template's JavaScript.
2845           */
2846          string_append(&result, "<li><a href=\"");
2847          html_encoded_prefix = html_encode(CGI_PREFIX);
2848          if (html_encoded_prefix == NULL)
2849          {
2850             return NULL;  
2851          }
2852          else
2853          {
2854             string_append(&result, html_encoded_prefix);
2855             free(html_encoded_prefix);
2856          }
2857          string_append(&result, d->name);
2858          string_append(&result, "\">");
2859          string_append(&result, d->description);
2860          string_append(&result, "</a></li>");
2861       }
2862    }
2863
2864    return result;
2865 }
2866
2867
2868 /*********************************************************************
2869  *
2870  * Function    :  dump_map
2871  *
2872  * Description :  HTML-dump a map for debugging (as table)
2873  *
2874  * Parameters  :
2875  *          1  :  the_map = map to dump
2876  *
2877  * Returns     :  string with HTML
2878  *
2879  *********************************************************************/
2880 char *dump_map(const struct map *the_map)
2881 {
2882    struct map_entry *cur_entry;
2883    char *ret = strdup("");
2884
2885    string_append(&ret, "<table>\n");
2886
2887    for (cur_entry = the_map->first;
2888         (cur_entry != NULL) && (ret != NULL);
2889         cur_entry = cur_entry->next)
2890    {
2891       string_append(&ret, "<tr><td><b>");
2892       string_join  (&ret, html_encode(cur_entry->name));
2893       string_append(&ret, "</b></td><td>");
2894       string_join  (&ret, html_encode(cur_entry->value));
2895       string_append(&ret, "</td></tr>\n");
2896    }
2897
2898    string_append(&ret, "</table>\n");
2899    return ret;
2900 }
2901
2902
2903 /*
2904   Local Variables:
2905   tab-width: 3
2906   end:
2907 */