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