-const char cgi_rcs[] = "$Id: cgi.c,v 1.96 2007/03/08 17:41:05 fabiankeil Exp $";
+const char cgi_rcs[] = "$Id: cgi.c,v 1.113 2008/09/04 08:13:58 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/cgi.c,v $
* Functions declared include:
*
*
- * Copyright : Written by and Copyright (C) 2001-2004, 2006-2007
+ * Copyright : Written by and Copyright (C) 2001-2004, 2006-2008
* the SourceForge Privoxy team. http://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
*
* Revisions :
* $Log: cgi.c,v $
+ * Revision 1.113 2008/09/04 08:13:58 fabiankeil
+ * Prepare for critical sections on Windows by adding a
+ * layer of indirection before the pthread mutex functions.
+ *
+ * Revision 1.112 2008/08/31 16:08:12 fabiankeil
+ * "View the request headers" isn't more equal than the other
+ * menu items and thus doesn't need a trailing dot either.
+ *
+ * Revision 1.111 2008/08/31 15:59:02 fabiankeil
+ * There's no reason to let remote toggling support depend
+ * on FEATURE_CGI_EDIT_ACTIONS, so make sure it doesn't.
+ *
+ * Revision 1.110 2008/08/31 14:55:43 fabiankeil
+ * Add a @date@ symbol to include a date(1)-like time string
+ * in templates. Modified version of the patch Endre Szabo
+ * submitted in #2026468.
+ *
+ * Revision 1.109 2008/07/26 09:40:27 fabiankeil
+ * Remove the unconditional block in get_http_time().
+ * It's pointless now that it's no longer used to limit
+ * dummy's scope. While at it, remove obvious comments
+ * and a trailing space.
+ *
+ * Revision 1.108 2008/05/26 17:30:53 fabiankeil
+ * Provide an OpenSearch Description to access the
+ * show-url-info page through "search engine plugins".
+ *
+ * Revision 1.107 2008/05/26 16:23:19 fabiankeil
+ * - Fix spelling in template-not-found message.
+ * - Declare referrer_is_safe()'s alternative_prefix[] static.
+ *
+ * Revision 1.106 2008/05/21 15:24:38 fabiankeil
+ * Mark csp as immutable for a bunch of functions.
+ *
+ * Revision 1.105 2008/04/17 14:40:47 fabiankeil
+ * Provide get_http_time() with the buffer size so it doesn't
+ * have to blindly assume that the buffer is big enough.
+ *
+ * Revision 1.104 2008/03/26 18:07:06 fabiankeil
+ * Add hostname directive. Closes PR#1918189.
+ *
+ * Revision 1.103 2008/03/21 11:13:57 fabiankeil
+ * Only gather host information if it's actually needed.
+ * Also move the code out of accept_connection() so it's less likely
+ * to delay other incoming connections if the host is misconfigured.
+ *
+ * Revision 1.102 2008/02/23 16:33:43 fabiankeil
+ * Let forward_url() use the standard parameter ordering
+ * and mark its second parameter immutable.
+ *
+ * Revision 1.101 2008/02/03 15:45:06 fabiankeil
+ * Add SOCKS5 support for "Forwarding failure" CGI page.
+ *
+ * Revision 1.100 2007/10/17 18:40:53 fabiankeil
+ * - Send CGI pages as HTTP/1.1 unless the client asked for HTTP/1.0.
+ * - White space fix.
+ *
+ * Revision 1.99 2007/08/05 13:42:22 fabiankeil
+ * #1763173 from Stefan Huehner: declare some more functions static.
+ *
+ * Revision 1.98 2007/05/14 10:33:51 fabiankeil
+ * - Use strlcpy() and strlcat() instead of strcpy() and strcat().
+ *
+ * Revision 1.97 2007/04/09 18:11:35 fabiankeil
+ * Don't mistake VC++'s _snprintf() for a snprintf() replacement.
+ *
* Revision 1.96 2007/03/08 17:41:05 fabiankeil
* Use sizeof() more often.
*
#include "filters.h"
#include "miscutil.h"
#include "cgisimple.h"
-#ifdef FEATURE_CGI_EDIT_ACTIONS
+#include "jbsockets.h"
+#if defined(FEATURE_CGI_EDIT_ACTIONS) || defined(FEATURE_TOGGLE)
#include "cgiedit.h"
-#endif /* def FEATURE_CGI_EDIT_ACTIONS */
+#endif /* defined(FEATURE_CGI_EDIT_ACTIONS) || defined (FEATURE_TOGGLE) */
#include "loadcfg.h"
/* loadcfg.h is for global_toggle_state only */
#ifdef FEATURE_PTHREAD
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",
TRUE },
-#ifdef FEATURE_CGI_EDIT_ACTIONS
#ifdef FEATURE_TOGGLE
{ "toggle",
cgi_toggle,
"Toggle Privoxy on or off",
FALSE },
#endif /* def FEATURE_TOGGLE */
+#ifdef FEATURE_CGI_EDIT_ACTIONS
{ "edit-actions", /* Edit the actions list */
cgi_edit_actions,
NULL, FALSE },
{ "t",
cgi_transparent_image,
NULL, TRUE /* Send a transparent image (short name) */ },
+ { "url-info-osd.xml",
+ cgi_send_url_info_osd,
+ NULL, TRUE /* Send templates/url-info-osd.xml */ },
{ "user-manual",
cgi_send_user_manual,
NULL, TRUE /* Send user-manual */ },
* Returns : pointer to value (no copy!), or NULL if none found.
*
*********************************************************************/
-char *grep_cgi_referrer(const struct client_state *csp)
+static char *grep_cgi_referrer(const struct client_state *csp)
{
struct list_entry *p;
* FALSE if the referrer is unsafe or not set.
*
*********************************************************************/
-int referrer_is_safe (const struct client_state *csp)
+static int referrer_is_safe(const struct client_state *csp)
{
char *referrer;
- const char alternative_prefix[] = "http://" CGI_SITE_1_HOST "/";
+ static const char alternative_prefix[] = "http://" CGI_SITE_1_HOST "/";
referrer = grep_cgi_referrer(csp);
}
else if (!strcmp(templatename, "forwarding-failed"))
{
- const struct forward_spec * fwd = forward_url(csp->http, csp);
+ const struct forward_spec *fwd = forward_url(csp, csp->http);
+ char *socks_type = NULL;
if (fwd == NULL)
{
log_error(LOG_LEVEL_FATAL, "gateway spec is NULL. This shouldn't happen!");
csp->error_message = strdup("Failure reason missing. Check the log file for details.");
}
if (!err) err = map(exports, "gateway", 1, fwd->gateway_host, 1);
- if (!err) err = map(exports, "forwarding-type", 1, (fwd->type == SOCKS_4) ?
- "socks4-" : "socks4a-", 1);
+
+ /*
+ * XXX: this is almost the same code as in cgi_show_url_info()
+ * and thus should be factored out and shared.
+ */
+ switch (fwd->type)
+ {
+ case SOCKS_4:
+ socks_type = "socks4-";
+ break;
+ case SOCKS_4A:
+ socks_type = "socks4a-";
+ break;
+ case SOCKS_5:
+ socks_type = "socks5-";
+ break;
+ default:
+ log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
+ }
+
+ if (!err) err = map(exports, "forwarding-type", 1, socks_type, 1);
if (!err) err = map(exports, "error-message", 1, html_encode(csp->error_message), 0);
if (!err) rsp->status = strdup("503 Forwarding failure");
* JB_ERR_MEMORY on out-of-memory error.
*
*********************************************************************/
-jb_err cgi_error_disabled(struct client_state *csp,
+jb_err cgi_error_disabled(const struct client_state *csp,
struct http_response *rsp)
{
struct map *exports;
* JB_ERR_MEMORY on out-of-memory error.
*
*********************************************************************/
-jb_err cgi_error_no_template(struct client_state *csp,
+jb_err cgi_error_no_template(const struct client_state *csp,
struct http_response *rsp,
const char *template_name)
{
"<p>Privoxy encountered an error while processing your request:</p>\r\n"
"<p><b>Could not load template file <code>";
static const char body_suffix[] =
- "</code> or one of it's included components.</b></p>\r\n"
+ "</code> or one of its included components.</b></p>\r\n"
"<p>Please contact your proxy administrator.</p>\r\n"
"<p>If you are the proxy administrator, please put the required file(s)"
"in the <code><i>(confdir)</i>/templates</code> directory. The "
").</p>\r\n"
"</body>\r\n"
"</html>\r\n";
+ const size_t body_size = strlen(body_prefix) + strlen(template_name) + strlen(body_suffix) + 1;
assert(csp);
assert(rsp);
rsp->head_length = 0;
rsp->is_static = 0;
- rsp->body = malloc(strlen(body_prefix) + strlen(template_name) + strlen(body_suffix) + 1);
+ rsp->body = malloc(body_size);
if (rsp->body == NULL)
{
return JB_ERR_MEMORY;
}
- strcpy(rsp->body, body_prefix);
- strcat(rsp->body, template_name);
- strcat(rsp->body, body_suffix);
+ strlcpy(rsp->body, body_prefix, body_size);
+ strlcat(rsp->body, template_name, body_size);
+ strlcat(rsp->body, body_suffix, body_size);
rsp->status = strdup(status);
if (rsp->status == NULL)
* JB_ERR_MEMORY on out-of-memory error.
*
*********************************************************************/
-jb_err cgi_error_unknown(struct client_state *csp,
+jb_err cgi_error_unknown(const struct client_state *csp,
struct http_response *rsp,
jb_err error_to_report)
{
"</body>\r\n"
"</html>\r\n";
char errnumbuf[30];
+ /*
+ * Due to sizeof(errnumbuf), body_size will be slightly
+ * bigger than necessary but it doesn't really matter.
+ */
+ const size_t body_size = strlen(body_prefix) + sizeof(errnumbuf) + strlen(body_suffix) + 1;
assert(csp);
assert(rsp);
snprintf(errnumbuf, sizeof(errnumbuf), "%d", error_to_report);
- rsp->body = malloc(strlen(body_prefix) + strlen(errnumbuf) + strlen(body_suffix) + 1);
+ rsp->body = malloc(body_size);
if (rsp->body == NULL)
{
return JB_ERR_MEMORY;
}
- strcpy(rsp->body, body_prefix);
- strcat(rsp->body, errnumbuf);
- strcat(rsp->body, body_suffix);
+ strlcpy(rsp->body, body_prefix, body_size);
+ strlcat(rsp->body, errnumbuf, body_size);
+ strlcat(rsp->body, body_suffix, body_size);
rsp->status = strdup(status);
if (rsp->status == NULL)
* JB_ERR_MEMORY on out-of-memory error.
*
*********************************************************************/
-jb_err cgi_error_bad_param(struct client_state *csp,
+jb_err cgi_error_bad_param(const struct client_state *csp,
struct http_response *rsp)
{
struct map *exports;
* HTTP header - e.g.:
* "Sun, 06 Nov 1994 08:49:37 GMT"
*
- * XXX: Should probably get a third parameter for
- * the buffer size.
- *
* Parameters :
* 1 : time_offset = Time returned will be current time
* plus this number of seconds.
- * 2 : buf = Destination for result. Must be long enough
- * to hold 29 characters plus a trailing zero.
+ * 2 : buf = Destination for result.
+ * 3 : buffer_size = Size of the buffer above. Must be big
+ * enough to hold 29 characters plus a
+ * trailing zero.
*
* Returns : N/A
*
*********************************************************************/
-void get_http_time(int time_offset, char *buf)
+void get_http_time(int time_offset, char *buf, size_t buffer_size)
{
static const char day_names[7][4] =
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
struct tm *t;
time_t current_time;
#if defined(HAVE_GMTIME_R)
- /*
- * 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;
+ struct tm dummy;
#endif
assert(buf);
+ assert(buffer_size > (size_t)29);
- time(¤t_time); /* get current time */
+ time(¤t_time);
current_time += time_offset;
/* get and save the gmt */
- {
#if HAVE_GMTIME_R
- t = gmtime_r(¤t_time, &dummy);
+ t = gmtime_r(¤t_time, &dummy);
#elif FEATURE_PTHREAD
- pthread_mutex_lock(&gmtime_mutex);
- t = gmtime(¤t_time);
- pthread_mutex_unlock(&gmtime_mutex);
+ privoxy_mutex_lock(&gmtime_mutex);
+ t = gmtime(¤t_time);
+ privoxy_mutex_unlock(&gmtime_mutex);
#else
- t = gmtime(¤t_time);
+ t = gmtime(¤t_time);
#endif
- }
/* Format: "Sun, 06 Nov 1994 08:49:37 GMT" */
- snprintf(buf, 30,
+ snprintf(buf, buffer_size,
"%s, %02d %s %4d %02d:%02d:%02d GMT",
day_names[t->tm_wday],
t->tm_mday,
}
+/*********************************************************************
+ *
+ * Function : get_locale_time
+ *
+ * Description : Get the time in a date(1)-like format
+ * according to the current locale - e.g.:
+ * "Fri Aug 29 19:37:12 CEST 2008"
+ *
+ * XXX: Should we allow the user to change the format?
+ *
+ * Parameters :
+ * 1 : buf = Destination for result.
+ * 2 : buffer_size = Size of the buffer above. Must be big
+ * enough to hold 29 characters plus a
+ * trailing zero.
+ *
+ * Returns : N/A
+ *
+ *********************************************************************/
+static void get_locale_time(char *buf, size_t buffer_size)
+{
+ struct tm *timeptr;
+ time_t current_time;
+#if defined(HAVE_LOCALTIME_R)
+ struct tm dummy;
+#endif
+
+ assert(buf);
+ assert(buffer_size > (size_t)29);
+
+ time(¤t_time);
+
+#if HAVE_LOCALTIME_R
+ timeptr = localtime_r(¤t_time, &dummy);
+#elif FEATURE_PTHREAD
+ privoxy_mutex_lock(&localtime_mutex);
+ timeptr = localtime(¤t_time);
+ privoxy_mutex_unlock(&localtime_mutex);
+#else
+ timeptr = localtime(¤t_time);
+#endif
+
+ strftime(buf, buffer_size, "%a %b %d %X %Z %Y", timeptr);
+
+}
/*********************************************************************
*
}
/*
- * Fill in the HTTP Status
+ * Fill in the HTTP Status, using HTTP/1.1
+ * unless the client asked for HTTP/1.0.
*/
- snprintf(buf, sizeof(buf), "HTTP/1.0 %s", rsp->status ? rsp->status : "200 OK");
+ snprintf(buf, sizeof(buf), "%s %s",
+ strcmpic(csp->http->ver, "HTTP/1.0") ? "HTTP/1.1" : "HTTP/1.0",
+ rsp->status ? rsp->status : "200 OK");
err = enlist_first(rsp->headers, buf);
/*
if (strncmpic(rsp->status, "302", 3))
{
- /*
- * If it's not a redirect without any content,
- * set the Content-Type to text/html if it's
- * not already specified.
- */
- if (!err) err = enlist_unique(rsp->headers, "Content-Type: text/html", 13);
+ /*
+ * If it's not a redirect without any content,
+ * set the Content-Type to text/html if it's
+ * not already specified.
+ */
+ if (!err) err = enlist_unique(rsp->headers, "Content-Type: text/html", 13);
}
/*
if (!err)
{
- get_http_time(0, buf);
+ get_http_time(0, buf, sizeof(buf));
err = enlist_unique_header(rsp->headers, "Date", buf);
}
if (!err)
{
- get_http_time(10 * 60, buf); /* 10 * 60sec = 10 minutes */
+ get_http_time(10 * 60, buf, sizeof(buf)); /* 10 * 60sec = 10 minutes */
err = enlist_unique_header(rsp->headers, "Expires", buf);
}
}
else if (!strncmpic(rsp->status, "302", 3))
{
- get_http_time(0, buf);
+ get_http_time(0, buf, sizeof(buf));
if (!err) err = enlist_unique_header(rsp->headers, "Date", buf);
}
else
*/
if (!err) err = enlist_unique_header(rsp->headers, "Cache-Control", "no-cache");
- get_http_time(0, buf);
+ get_http_time(0, buf, sizeof(buf));
if (!err) err = enlist_unique_header(rsp->headers, "Date", buf);
if (!strncmpic(rsp->status, "403", 3)
|| !strncmpic(rsp->status, "404", 3)
* JB_ERR_FILE if the template file cannot be read
*
*********************************************************************/
-jb_err template_load(struct client_state *csp, char **template_ptr,
+jb_err template_load(const struct client_state *csp, char **template_ptr,
const char *templatename, int recursive)
{
jb_err err;
* JB_ERR_MEMORY on out-of-memory error
*
*********************************************************************/
-jb_err template_fill_for_cgi(struct client_state *csp,
+jb_err template_fill_for_cgi(const struct client_state *csp,
const char *templatename,
struct map *exports,
struct http_response *rsp)
*********************************************************************/
struct map *default_exports(const struct client_state *csp, const char *caller)
{
- char buf[20];
+ char buf[30];
jb_err err;
struct map * exports;
int local_help_exists = 0;
+ char *ip_address = NULL;
+ char *hostname = NULL;
assert(csp);
return NULL;
}
+ if (csp->config->hostname)
+ {
+ get_host_information(csp->cfd, &ip_address, NULL);
+ hostname = strdup(csp->config->hostname);
+ }
+ else
+ {
+ get_host_information(csp->cfd, &ip_address, &hostname);
+ }
+
err = map(exports, "version", 1, html_encode(VERSION), 0);
- if (!err) err = map(exports, "my-ip-address", 1, html_encode(csp->my_ip_addr_str ? csp->my_ip_addr_str : "unknown"), 0);
- if (!err) err = map(exports, "my-hostname", 1, html_encode(csp->my_hostname ? csp->my_hostname : "unknown"), 0);
+ get_locale_time(buf, sizeof(buf));
+ if (!err) err = map(exports, "time", 1, html_encode(buf), 0);
+ if (!err) err = map(exports, "my-ip-address", 1, html_encode(ip_address ? ip_address : "unknown"), 0);
+ freez(ip_address);
+ if (!err) err = map(exports, "my-hostname", 1, html_encode(hostname ? hostname : "unknown"), 0);
+ freez(hostname);
if (!err) err = map(exports, "homepage", 1, html_encode(HOME_PAGE_URL), 0);
if (!err) err = map(exports, "default-cgi", 1, html_encode(CGI_PREFIX), 0);
if (!err) err = map(exports, "menu", 1, make_menu(caller, csp->config->feature_flags), 0);
assert(exports);
assert(name);
- assert(strlen(name) < 490);
+ assert(strlen(name) < (size_t)490);
snprintf(buf, sizeof(buf), "if-%s-start.*if-%s-end", name, name);
return map(exports, buf, 1, "", 1);
assert(exports);
assert(name);
- assert(strlen(name) < 490);
+ assert(strlen(name) < (size_t)490);
snprintf(buf, sizeof(buf), "if-%s-start", name);
err = map(exports, buf, 1, "", 1);
assert(exports);
assert(name);
- assert(strlen(name) < 480);
+ assert(strlen(name) < (size_t)480);
snprintf(buf, sizeof(buf), (choose_first
? "else-not-%s@.*@endif-%s"