-const char cgi_rcs[] = "$Id: cgi.c,v 1.69 2002/05/14 21:28:40 oes Exp $";
+const char cgi_rcs[] = "$Id: cgi.c,v 1.70.2.11 2003/10/23 12:29:26 oes Exp $";
/*********************************************************************
*
- * File : $Source: /cvsroot/ijbswa/current/cgi.c,v $
+ * File : $Source: /cvsroot/ijbswa/current/Attic/cgi.c,v $
*
* Purpose : Declares functions to intercept request, generate
* html or gif answers, and to compose HTTP resonses.
*
* Revisions :
* $Log: cgi.c,v $
+ * Revision 1.70.2.11 2003/10/23 12:29:26 oes
+ * Bugfix: Transparent PNG was not transparent. Thanks to
+ * Dan Razzell of Starfish Systems for notice and new PNG.
+ *
+ * Revision 1.70.2.10 2003/06/06 07:54:25 oes
+ * Security fix: dspatch_known_cgi no longer considers an empty
+ * referrer safe for critical CGIs, since malicious links could
+ * reside on https:// locations which browsers don't advertize as
+ * referrers. Closes bug #749916, thanks to Jeff Epler for the
+ * hint. Goodbye One-Click[tm] toggling :-(
+ *
+ * Revision 1.70.2.9 2003/05/08 15:11:31 oes
+ * Nit
+ *
+ * Revision 1.70.2.8 2003/04/29 13:33:51 oes
+ * Killed a compiler warning on OSX
+ *
+ * Revision 1.70.2.7 2003/04/03 13:50:58 oes
+ * - Don't call cgi_error_disabled ifndef FEATURE_CGI_EDIT_ACTIONS
+ * (fixes bug #710056)
+ * - Show toggle info only if we have it
+ *
+ * Revision 1.70.2.6 2003/03/12 01:26:25 david__schmidt
+ * Move declaration of struct tm dummy outside of a control block so it is
+ * accessible later on during snprintf in get_http_time.
+ *
+ * Revision 1.70.2.5 2003/03/11 11:53:58 oes
+ * Cosmetic: Renamed cryptic variable
+ *
+ * Revision 1.70.2.4 2003/03/07 03:41:03 david__schmidt
+ * 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.
+ *
+ * Revision 1.70.2.3 2002/11/28 18:14:32 oes
+ * Disable access to critical CGIs via untrusted referrers.
+ * This prevents users from being tricked by malicious websites
+ * into making unintentional configuration changes:
+ *
+ * - Added flag to each cgi_dispatcher that allows or denies
+ * external linking
+ * - Introduced proviorical function that greps for the
+ * referrer header before regular header parsing happens
+ * - Added safety check to dispatch_known_cgi. CGI is called
+ * if (cgi harmless || no referrer || we are referrer).
+ * Else a) toggle calls are modified not to change status and
+ * b) all other calls are denied.
+ *
+ * Revision 1.70.2.2 2002/11/12 16:20:37 oes
+ * Added missing #ifdef FEATURE_TOGGLE around g_bToggleIJB; fixes bug #636651
+ *
+ * Revision 1.70.2.1 2002/08/05 11:17:46 oes
+ * Fixed Bug #587820, i.e. added workaround for IE bug that includes fragment identifier in (cgi) query
+ *
+ * Revision 1.70 2002/05/19 11:33:20 jongfoster
+ * If a CGI error was not handled, and propogated back to
+ * dispatch_known_cgi(), then it was assumed to be "out of memory".
+ * This gave a very misleading error message.
+ *
+ * Now other errors will cause a simple message giving the error
+ * number and asking the user to report a bug.
+ *
+ * Bug report:
+ * http://sourceforge.net/tracker/index.php?func=detail
+ * &aid=557905&group_id=11118&atid=111118
+ *
* Revision 1.69 2002/05/14 21:28:40 oes
* - Fixed add_help_link to link to the (now split) actions
* part of the config chapter
#include "cgiedit.h"
#endif /* def FEATURE_CGI_EDIT_ACTIONS */
#include "loadcfg.h"
-/* loadcfg.h is for g_bToggleIJB only */
-
+/* loadcfg.h is for global_toggle_state only */
+#ifdef FEATURE_PTHREAD
+#include <pthread.h>
+#include "jcc.h"
+/* jcc.h is for mutex semaphore globals only */
+#endif /* def FEATURE_PTHREAD */
const char cgi_h_rcs[] = CGI_H_VERSION;
/*
static const struct cgi_dispatcher cgi_dispatchers[] = {
{ "",
cgi_default,
- "Privoxy main page" },
+ "Privoxy main page",
+ TRUE },
#ifdef FEATURE_GRACEFUL_TERMINATION
{ "die",
cgi_die,
"<b>Shut down</b> - <em class=\"warning\">Do not deploy this build in a production environment, "
- "this is a one click Denial Of Service attack!!!</em>" },
+ "this is a one click Denial Of Service attack!!!</em>",
+ FALSE },
#endif
{ "show-status",
cgi_show_status,
- "View & change the current configuration" },
+#ifdef FEATURE_CGI_EDIT_ACTIONS
+ "View & change the current configuration",
+#else
+ "View the current configuration",
+#endif
+ TRUE },
{ "show-version",
cgi_show_version,
- "View the source code version numbers" },
+ "View the source code version numbers",
+ TRUE },
{ "show-request",
cgi_show_request,
- "View the request headers." },
+ "View the request headers.",
+ TRUE },
{ "show-url-info",
cgi_show_url_info,
- "Look up which actions apply to a URL and why" },
+ "Look up which actions apply to a URL and why",
+ TRUE },
#ifdef FEATURE_CGI_EDIT_ACTIONS
{ "toggle",
cgi_toggle,
- "Toggle Privoxy on or off" },
-
+ "Toggle Privoxy on or off",
+ FALSE },
{ "edit-actions", /* Edit the actions list */
cgi_edit_actions,
- NULL },
+ NULL, FALSE },
{ "eaa", /* Shortcut for edit-actions-add-url-form */
cgi_edit_actions_add_url_form,
- NULL },
+ NULL, FALSE },
{ "eau", /* Shortcut for edit-actions-url-form */
cgi_edit_actions_url_form,
- NULL },
+ NULL, FALSE },
{ "ear", /* Shortcut for edit-actions-remove-url-form */
cgi_edit_actions_remove_url_form,
- NULL },
+ NULL, FALSE },
+ { "eal", /* Shortcut for edit-actions-list */
+ cgi_edit_actions_list,
+ NULL, FALSE },
{ "eafu", /* Shortcut for edit-actions-for-url */
cgi_edit_actions_for_url,
- NULL },
+ NULL, FALSE },
{ "eas", /* Shortcut for edit-actions-submit */
cgi_edit_actions_submit,
- NULL },
+ NULL, FALSE },
{ "easa", /* Shortcut for edit-actions-section-add */
cgi_edit_actions_section_add,
- NULL },
+ NULL, FALSE },
{ "easr", /* Shortcut for edit-actions-section-remove */
cgi_edit_actions_section_remove,
- NULL },
+ NULL, FALSE },
{ "eass", /* Shortcut for edit-actions-section-swap */
cgi_edit_actions_section_swap,
- NULL },
+ NULL, FALSE },
{ "edit-actions-for-url",
cgi_edit_actions_for_url,
- NULL /* Edit the actions for (a) specified URL(s) */ },
+ NULL, FALSE /* Edit the actions for (a) specified URL(s) */ },
{ "edit-actions-list",
cgi_edit_actions_list,
- NULL /* Edit the actions list */ },
+ NULL, TRUE /* Edit the actions list */ },
{ "edit-actions-submit",
cgi_edit_actions_submit,
- NULL /* Change the actions for (a) specified URL(s) */ },
+ NULL, FALSE /* Change the actions for (a) specified URL(s) */ },
{ "edit-actions-url",
cgi_edit_actions_url,
- NULL /* Change a URL pattern in the actionsfile */ },
+ NULL, FALSE /* Change a URL pattern in the actionsfile */ },
{ "edit-actions-url-form",
cgi_edit_actions_url_form,
- NULL /* Form to change a URL pattern in the actionsfile */ },
+ NULL, FALSE /* Form to change a URL pattern in the actionsfile */ },
{ "edit-actions-add-url",
cgi_edit_actions_add_url,
- NULL /* Add a URL pattern to the actionsfile */ },
+ NULL, FALSE /* Add a URL pattern to the actionsfile */ },
{ "edit-actions-add-url-form",
cgi_edit_actions_add_url_form,
- NULL /* Form to add a URL pattern to the actionsfile */ },
+ NULL, FALSE /* Form to add a URL pattern to the actionsfile */ },
{ "edit-actions-remove-url",
cgi_edit_actions_remove_url,
- NULL /* Remove a URL pattern from the actionsfile */ },
+ NULL, FALSE /* Remove a URL pattern from the actionsfile */ },
{ "edit-actions-remove-url-form",
cgi_edit_actions_remove_url_form,
- NULL /* Form to remove a URL pattern from the actionsfile */ },
+ NULL, FALSE /* Form to remove a URL pattern from the actionsfile */ },
{ "edit-actions-section-add",
cgi_edit_actions_section_add,
- NULL /* Remove a section from the actionsfile */ },
+ NULL, FALSE /* Remove a section from the actionsfile */ },
{ "edit-actions-section-remove",
cgi_edit_actions_section_remove,
- NULL /* Remove a section from the actionsfile */ },
+ NULL, FALSE /* Remove a section from the actionsfile */ },
{ "edit-actions-section-swap",
cgi_edit_actions_section_swap,
- NULL /* Swap two sections in the actionsfile */ },
+ NULL, FALSE /* Swap two sections in the actionsfile */ },
#endif /* def FEATURE_CGI_EDIT_ACTIONS */
{ "robots.txt",
cgi_robots_txt,
- NULL /* Sends a robots.txt file to tell robots to go away. */ },
+ NULL, TRUE /* Sends a robots.txt file to tell robots to go away. */ },
{ "send-banner",
cgi_send_banner,
- NULL /* Send a built-in image */ },
+ NULL, TRUE /* Send a built-in image */ },
{ "send-stylesheet",
cgi_send_stylesheet,
- NULL /* Send templates/cgi-style.css */ },
+ NULL, TRUE /* Send templates/cgi-style.css */ },
{ "t",
cgi_transparent_image,
- NULL /* Send a transparent image (short name) */ },
+ NULL, TRUE /* Send a transparent image (short name) */ },
{ NULL, /* NULL Indicates end of list and default page */
cgi_error_404,
- NULL /* Unknown CGI page */ }
+ NULL, TRUE /* Unknown CGI page */ }
};
/*
- * Bulit-in images for ad replacement
+ * Built-in images for ad replacement
*
* Hint: You can encode your own images like this:
* cat your-image | perl -e 'while (read STDIN, $c, 1) { printf("\\%.3o", unpack("C", $c)); }'
*/
const char image_blank_data[] =
"\211\120\116\107\015\012\032\012\000\000\000\015\111\110\104\122"
- "\000\000\000\004\000\000\000\004\010\006\000\000\000\251\361\236"
- "\176\000\000\000\007\164\111\115\105\007\322\003\013\020\073\070"
- "\013\025\036\203\000\000\000\011\160\110\131\163\000\000\013\022"
- "\000\000\013\022\001\322\335\176\374\000\000\000\004\147\101\115"
- "\101\000\000\261\217\013\374\141\005\000\000\000\033\111\104\101"
- "\124\170\332\143\070\161\342\304\207\377\377\377\347\302\150\006"
- "\144\016\210\146\040\250\002\000\042\305\065\221\270\027\131\110"
+ "\000\000\000\001\000\000\000\001\001\003\000\000\000\045\333\126"
+ "\312\000\000\000\003\120\114\124\105\377\377\377\247\304\033\310"
+ "\000\000\000\001\164\122\116\123\000\100\346\330\146\000\000\000"
+ "\001\142\113\107\104\000\210\005\035\110\000\000\000\012\111\104"
+ "\101\124\170\001\143\140\000\000\000\002\000\001\163\165\001\030"
"\000\000\000\000\111\105\116\104\256\102\140\202";
#else
else if (*path != '\0')
{
/*
- * wierdness: URL is /configXXX, where XXX is some string
+ * weirdness: URL is /configXXX, where XXX is some string
* Do *NOT* intercept.
*/
return NULL;
}
+/*********************************************************************
+ *
+ * Function : grep_cgi_referrer
+ *
+ * Description : Ugly provisorical fix that greps the value of the
+ * referer HTTP header field out of a linked list of
+ * strings like found at csp->headers. Will disappear
+ * in Privoxy 3.1.
+ *
+ * FIXME: csp->headers ought to be csp->http->headers
+ * FIXME: Parsing all client header lines should
+ * happen right after the request is received!
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns : pointer to value (no copy!), or NULL if none found.
+ *
+ *********************************************************************/
+char *grep_cgi_referrer(struct client_state *csp)
+{
+ struct list_entry *p;
+
+ for (p = csp->headers->first; p != NULL; p = p->next)
+ {
+ if (p->str == NULL) continue;
+ if (strncmpic(p->str, "Referer: ", 9) == 0)
+ {
+ return ((p->str) + 9);
+ }
+ }
+ return NULL;
+
+}
+
+
/*********************************************************************
*
* Function : dispatch_known_cgi
struct http_response *rsp;
char *query_args_start;
char *path_copy;
+ char *referrer;
jb_err err;
if (NULL == (path_copy = strdup(path)))
return cgi_error_memory();
}
-
/*
* At this point:
* path_copy = CGI call name
log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3",
csp->ip_addr_str, csp->http->cmd);
- /* Find and start the right CGI function*/
+ /*
+ * Find and start the right CGI function
+ */
d = cgi_dispatchers;
for (;;)
{
if ((d->name == NULL) || (strcmp(path_copy, d->name) == 0))
{
- err = (d->handler)(csp, rsp, param_list);
+ /*
+ * If the called CGI is either harmless, or referred
+ * from a trusted source, start it.
+ */
+ if (d->harmless
+ || ((NULL != (referrer = grep_cgi_referrer(csp)))
+ && (0 == strncmp(referrer, "http://config.privoxy.org/", 26)))
+ )
+ {
+ err = (d->handler)(csp, rsp, param_list);
+ }
+ else
+ {
+ /*
+ * Else, modify toggle calls so that they only display
+ * the status, and deny all other calls.
+ */
+ if (0 == strcmp(path_copy, "toggle"))
+ {
+ unmap(param_list, "set");
+ err = (d->handler)(csp, rsp, param_list);
+ }
+ else
+ {
+ err = cgi_error_disabled(csp, rsp);
+ }
+ }
+
free(path_copy);
free_map(param_list);
+
if (err == JB_ERR_CGI_PARAMS)
{
err = cgi_error_bad_param(csp, rsp);
d++;
}
}
-
-
+
+
/*********************************************************************
*
* Function : parse_cgi_parameters
return NULL;
}
+ /*
+ * IE 5 does, of course, violate RFC 2316 Sect 4.1 and sends
+ * the fragment identifier along with the request, so we must
+ * cut it off here, so it won't pollute the CGI params:
+ */
+ if (NULL != (p = strchr(argstring, '#')))
+ {
+ *p = '\0';
+ }
+
pairs = ssplit(argstring, "&", vector, SZ(vector), 1, 1);
for (i = 0; i < pairs; i++)
}
+/*********************************************************************
+ *
+ * Function : cgi_redirect
+ *
+ * Description : CGI support function to generate a HTTP redirect
+ * message
+ *
+ * Parameters :
+ * 1 : rsp = http_response data structure for output
+ * 2 : target = string with the target URL
+ *
+ * CGI Parameters : None
+ *
+ * Returns : JB_ERR_OK on success
+ * JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+jb_err cgi_redirect (struct http_response * rsp, const char *target)
+{
+ jb_err err;
+
+ assert(rsp);
+ assert(target);
+
+ err = enlist_unique_header(rsp->headers, "Location", target);
+
+ rsp->status = strdup("302 Local Redirect from Privoxy");
+ if (rsp->status == NULL)
+ {
+ return JB_ERR_MEMORY;
+ }
+
+ return err;
+}
+
+
/*********************************************************************
*
* Function : add_help_link
struct tm *t;
time_t current_time;
+#if defined(HAVE_GMTIME_R) && !defined(OSX_DARWIN)
+ /*
+ * Declare dummy up here (instead of inside get/set gmt block) so it
+ * doesn't go out of scope before it's potentially used in snprintf later.
+ * Wrapping declaration inside HAVE_GMTIME_R keeps the compiler quiet when
+ * !defined HAVE_GMTIME_R.
+ */
+ struct tm dummy;
+#endif
assert(buf);
/* get and save the gmt */
{
-#ifdef HAVE_GMTIME_R
- struct tm dummy;
+#ifdef OSX_DARWIN
+ pthread_mutex_lock(&gmtime_mutex);
+ t = gmtime(¤t_time);
+ pthread_mutex_unlock(&gmtime_mutex);
+#elif HAVE_GMTIME_R
t = gmtime_r(¤t_time, &dummy);
#else
t = gmtime(¤t_time);
get_http_time(0, buf);
if (!err) err = enlist_unique_header(rsp->headers, "Date", buf);
if (!err) err = enlist_unique_header(rsp->headers, "Last-Modified", buf);
- if (!err) err = enlist_unique_header(rsp->headers, "Expires", buf);
+ if (!err) err = enlist_unique_header(rsp->headers, "Expires", "Sat, 17 Jun 2000 12:00:00 GMT");
}
if (!err) err = map(exports, "code-status", 1, CODE_STATUS, 1);
if (!err) err = map(exports, "user-manual", 1, csp->config->usermanual ,1);
if (!err) err = map(exports, "actions-help-prefix", 1, ACTIONS_HELP_PREFIX ,1);
- if (!err) err = map_conditional(exports, "enabled-display", g_bToggleIJB);
+#ifdef FEATURE_TOGGLE
+ if (!err) err = map_conditional(exports, "enabled-display", global_toggle_state);
+#else
+ if (!err) err = map_block_killer(exports, "can-toggle");
+#endif
snprintf(buf, 20, "%d", csp->config->hport);
if (!err) err = map(exports, "my-port", 1, buf, 1);