receive_and_send_encrypted_post_data(): Change two more log messages
[privoxy.git] / cgi.c
diff --git a/cgi.c b/cgi.c
index d39e4a0..96ce16f 100644 (file)
--- a/cgi.c
+++ b/cgi.c
@@ -1,15 +1,14 @@
-const char cgi_rcs[] = "$Id: cgi.c,v 1.154 2012/07/23 12:42:53 fabiankeil Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/cgi.c,v $
  *
  * Purpose     :  Declares functions to intercept request, generate
- *                html or gif answers, and to compose HTTP resonses.
+ *                html or gif answers, and to compose HTTP responses.
  *                This only contains the framework functions, the
  *                actual handler functions are declared elsewhere.
  *
- * Copyright   :  Written by and Copyright (C) 2001-2004, 2006-2008
- *                the SourceForge Privoxy team. http://www.privoxy.org/
+ * Copyright   :  Written by and Copyright (C) 2001-2017
+ *                members of the Privoxy team. https://www.privoxy.org/
  *
  *                Based on the Internet Junkbuster originally written
  *                by and Copyright (C) 1997 Anonymous Coders and
@@ -69,8 +68,6 @@ const char cgi_rcs[] = "$Id: cgi.c,v 1.154 2012/07/23 12:42:53 fabiankeil Exp $"
 /* jcc.h is for mutex semaphore globals only */
 #include "jcc.h"
 
-const char cgi_h_rcs[] = CGI_H_VERSION;
-
 /*
  * List of CGI functions: name, handler, description
  * Note: Do NOT use single quotes in the description;
@@ -96,10 +93,17 @@ static const struct cgi_dispatcher cgi_dispatchers[] = {
         "View the current configuration",
 #endif
          TRUE },
-   { "show-version",
-         cgi_show_version,
-         "View the source code version numbers",
-          TRUE },
+#ifdef FEATURE_CLIENT_TAGS
+   /*
+    * This is marked as harmless because despite the description
+    * used in the menu the actual toggling is done through another
+    * path ("/toggle-client-tag").
+    */
+   { "client-tags",
+         cgi_show_client_tags,
+         "View or toggle the tags that can be set based on the clients address",
+         TRUE },
+#endif
    { "show-request",
          cgi_show_request,
          "View the request headers",
@@ -114,6 +118,12 @@ static const struct cgi_dispatcher cgi_dispatchers[] = {
          "Toggle Privoxy on or off",
          FALSE },
 #endif /* def FEATURE_TOGGLE */
+#ifdef FEATURE_CLIENT_TAGS
+   { "toggle-client-tag",
+         cgi_toggle_client_tag,
+         NULL,
+         FALSE },
+#endif
 #ifdef FEATURE_CGI_EDIT_ACTIONS
    { "edit-actions", /* Edit the actions list */
          cgi_edit_actions,
@@ -234,7 +244,7 @@ const char image_pattern_data[] =
    "\000\000\000\000\111\105\116\104\256\102\140\202";
 
 /*
- * 1x1 transparant PNG.
+ * 1x1 transparent PNG.
  */
 const char image_blank_data[] =
  "\211\120\116\107\015\012\032\012\000\000\000\015\111\110\104\122"
@@ -257,7 +267,7 @@ const char image_pattern_data[] =
    "\270\005\000\073";
 
 /*
- * 1x1 transparant GIF.
+ * 1x1 transparent GIF.
  */
 const char image_blank_data[] =
    "GIF89a\001\000\001\000\200\000\000\377\377\377\000\000"
@@ -346,6 +356,21 @@ struct http_response *dispatch_cgi(struct client_state *csp)
       return NULL;
    }
 
+   if (strcmpic(csp->http->gpc, "GET")
+    && strcmpic(csp->http->gpc, "HEAD"))
+   {
+      log_error(LOG_LEVEL_ERROR,
+         "CGI request with unsupported method received: %s", csp->http->gpc);
+      /*
+       * The CGI pages currently only support GET and HEAD requests.
+       *
+       * If the client used a different method, ditch any data following
+       * the current headers to reduce the likelihood of parse errors
+       * with the following request.
+       */
+      csp->client_iob->eod = csp->client_iob->cur;
+   }
+
    /*
     * This is a CGI call.
     */
@@ -409,6 +434,7 @@ static int referrer_is_safe(const struct client_state *csp)
 {
    char *referrer;
    static const char alternative_prefix[] = "http://" CGI_SITE_1_HOST "/";
+   const char *trusted_cgi_referrer = csp->config->trusted_cgi_referrer;
 
    referrer = grep_cgi_referrer(csp);
 
@@ -427,6 +453,18 @@ static int referrer_is_safe(const struct client_state *csp)
 
       return TRUE;
    }
+   else if ((trusted_cgi_referrer != NULL) && (0 == strncmp(referrer,
+            trusted_cgi_referrer, strlen(trusted_cgi_referrer))))
+   {
+      /*
+       * After some more testing this block should be merged with
+       * the previous one or the log level should bedowngraded.
+       */
+      log_error(LOG_LEVEL_INFO, "Granting access to %s based on trusted referrer %s",
+         csp->http->url, referrer);
+
+      return TRUE;
+   }
    else
    {
       /* Untrustworthy referrer */
@@ -480,9 +518,12 @@ static struct http_response *dispatch_known_cgi(struct client_state * csp,
    if (*query_args_start == '/')
    {
       *query_args_start++ = '\0';
-      if ((param_list = new_map()))
-      {
-         map(param_list, "file", 1, url_decode(query_args_start), 0);
+      param_list = new_map();
+      err = map(param_list, "file", 1, url_decode(query_args_start), 0);
+      if (JB_ERR_OK != err) {
+         free(param_list);
+         free(path_copy);
+         return cgi_error_memory();
       }
    }
    else
@@ -616,11 +657,7 @@ static struct map *parse_cgi_parameters(char *argstring)
    }
    vector = malloc_or_die(max_segments * sizeof(char *));
 
-   if (NULL == (cgi_params = new_map()))
-   {
-      freez(vector);
-      return NULL;
-   }
+   cgi_params = new_map();
 
    /*
     * IE 5 does, of course, violate RFC 2316 Sect 4.1 and sends
@@ -698,22 +735,22 @@ char get_char_param(const struct map *parameters,
  *
  * Function    :  get_string_param
  *
- * Description :  Get a string paramater, to be used as an
- *                ACTION_STRING or ACTION_MULTI paramater.
+ * Description :  Get a string parameter, to be used as an
+ *                ACTION_STRING or ACTION_MULTI parameter.
  *                Validates the input to prevent stupid/malicious
  *                users from corrupting their action file.
  *
  * Parameters  :
  *          1  :  parameters = map of cgi parameters
  *          2  :  param_name = The name of the parameter to read
- *          3  :  pparam = destination for paramater.  Allocated as
+ *          3  :  pparam = destination for parameter.  Allocated as
  *                part of the map "parameters", so don't free it.
  *                Set to NULL if not specified.
  *
- * Returns     :  JB_ERR_OK         on success, or if the paramater
+ * Returns     :  JB_ERR_OK         on success, or if the parameter
  *                                  was not specified.
  *                JB_ERR_MEMORY     on out-of-memory.
- *                JB_ERR_CGI_PARAMS if the paramater is not valid.
+ *                JB_ERR_CGI_PARAMS if the parameter is not valid.
  *
  *********************************************************************/
 jb_err get_string_param(const struct map *parameters,
@@ -793,8 +830,7 @@ jb_err get_number_param(struct client_state *csp,
                         unsigned *pvalue)
 {
    const char *param;
-   char ch;
-   unsigned value;
+   char *endptr;
 
    assert(csp);
    assert(parameters);
@@ -809,36 +845,12 @@ jb_err get_number_param(struct client_state *csp,
       return JB_ERR_CGI_PARAMS;
    }
 
-   /* We don't use atoi because I want to check this carefully... */
-
-   value = 0;
-   while ((ch = *param++) != '\0')
+   *pvalue = (unsigned int)strtol(param, &endptr, 0);
+   if (*endptr != '\0')
    {
-      if ((ch < '0') || (ch > '9'))
-      {
-         return JB_ERR_CGI_PARAMS;
-      }
-
-      ch = (char)(ch - '0');
-
-      /* Note:
-       *
-       * <limits.h> defines UINT_MAX
-       *
-       * (UINT_MAX - ch) / 10 is the largest number that
-       *     can be safely multiplied by 10 then have ch added.
-       */
-      if (value > ((UINT_MAX - (unsigned)ch) / 10U))
-      {
-         return JB_ERR_CGI_PARAMS;
-      }
-
-      value = value * 10 + (unsigned)ch;
+      return JB_ERR_CGI_PARAMS;
    }
 
-   /* Success */
-   *pvalue = value;
-
    return JB_ERR_OK;
 
 }
@@ -963,6 +975,12 @@ struct http_response *error_response(struct client_state *csp,
          case SOCKS_5:
             socks_type = "socks5-";
             break;
+         case SOCKS_5T:
+            socks_type = "socks5t-";
+            break;
+         case FORWARD_WEBSERVER:
+            socks_type = "webserver-";
+            break;
          default:
             log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
       }
@@ -1042,6 +1060,8 @@ jb_err cgi_error_disabled(const struct client_state *csp,
    assert(csp);
    assert(rsp);
 
+   rsp->status = strdup_or_die("403 Request not trusted or feature disabled");
+
    if (NULL == (exports = default_exports(csp, "cgi-error-disabled")))
    {
       return JB_ERR_MEMORY;
@@ -1205,7 +1225,7 @@ jb_err cgi_error_no_template(const struct client_state *csp,
  *                In this context, "unexpected" means "anything other
  *                than JB_ERR_MEMORY or JB_ERR_CGI_PARAMS" - CGIs are
  *                expected to handle all other errors internally,
- *                since they can give more relavent error messages
+ *                since they can give more relevant error messages
  *                that way.
  *
  *                Note this is not a true CGI, it takes an error
@@ -1555,7 +1575,7 @@ char *compress_buffer(char *buffer, size_t *buffer_length, int compression_level
  *                On error, free()s rsp and returns cgi_error_memory()
  *
  *********************************************************************/
-struct http_response *finish_http_response(const struct client_state *csp, struct http_response *rsp)
+struct http_response *finish_http_response(struct client_state *csp, struct http_response *rsp)
 {
    char buf[BUFFER_SIZE];
    jb_err err;
@@ -1568,12 +1588,24 @@ struct http_response *finish_http_response(const struct client_state *csp, struc
       return rsp;
    }
 
+   /*
+    * Add "Cross-origin resource sharing" (CORS) headers if enabled
+    */
+   if (NULL != csp->config->cors_allowed_origin)
+   {
+      enlist_unique_header(rsp->headers, "Access-Control-Allow-Origin",
+         csp->config->cors_allowed_origin);
+      enlist_unique_header(rsp->headers, "Access-Control-Allow-Methods", "GET,POST");
+      enlist_unique_header(rsp->headers, "Access-Control-Allow-Headers", "X-Requested-With");
+      enlist_unique_header(rsp->headers, "Access-Control-Max-Age", "86400");
+   }
+
    /*
     * Fill in the HTTP Status, using HTTP/1.1
     * unless the client asked for HTTP/1.0.
     */
    snprintf(buf, sizeof(buf), "%s %s",
-      strcmpic(csp->http->ver, "HTTP/1.0") ? "HTTP/1.1" : "HTTP/1.0",
+      strcmpic(csp->http->version, "HTTP/1.0") ? "HTTP/1.1" : "HTTP/1.0",
       rsp->status ? rsp->status : "200 OK");
    err = enlist_first(rsp->headers, buf);
 
@@ -1605,6 +1637,11 @@ struct http_response *finish_http_response(const struct client_state *csp, struc
    if (!err)
    {
       snprintf(buf, sizeof(buf), "Content-Length: %d", (int)rsp->content_length);
+      /*
+       * Signal serve() that the client will be able to figure out
+       * the end of the response without having to close the connection.
+       */
+      csp->flags |= CSP_FLAG_SERVER_CONTENT_LENGTH_SET;
       err = enlist(rsp->headers, buf);
    }
 
@@ -2097,15 +2134,12 @@ jb_err template_fill_for_cgi(const struct client_state *csp,
    err = template_load(csp, &rsp->body, templatename, 0);
    if (err == JB_ERR_FILE)
    {
-      free_map(exports);
-      return cgi_error_no_template(csp, rsp, templatename);
+      err = cgi_error_no_template(csp, rsp, templatename);
    }
-   else if (err)
+   else if (err == JB_ERR_OK)
    {
-      free_map(exports);
-      return err; /* JB_ERR_MEMORY */
+      err = template_fill(&rsp->body, exports);
    }
-   err = template_fill(&rsp->body, exports);
    free_map(exports);
    return err;
 }
@@ -2139,10 +2173,6 @@ struct map *default_exports(const struct client_state *csp, const char *caller)
    assert(csp);
 
    exports = new_map();
-   if (exports == NULL)
-   {
-      return NULL;
-   }
 
    if (csp->config->hostname)
    {