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