LCOV - code coverage report
Current view: top level - fuzz - cgisimple.c (source / functions) Hit Total Coverage
Test: trace.lcov_info_final Lines: 419 589 71.1 %
Date: 2021-02-22 04:51:02 Functions: 21 22 95.5 %

          Line data    Source code
       1             : /*********************************************************************
       2             :  *
       3             :  * File        :  $Source: /cvsroot/ijbswa/current/cgisimple.c,v $
       4             :  *
       5             :  * Purpose     :  Simple CGIs to get information about Privoxy's
       6             :  *                status.
       7             :  *
       8             :  * Copyright   :  Written by and Copyright (C) 2001-2020 the
       9             :  *                Privoxy team. https://www.privoxy.org/
      10             :  *
      11             :  *                Based on the Internet Junkbuster originally written
      12             :  *                by and Copyright (C) 1997 Anonymous Coders and
      13             :  *                Junkbusters Corporation.  http://www.junkbusters.com
      14             :  *
      15             :  *                This program is free software; you can redistribute it
      16             :  *                and/or modify it under the terms of the GNU General
      17             :  *                Public License as published by the Free Software
      18             :  *                Foundation; either version 2 of the License, or (at
      19             :  *                your option) any later version.
      20             :  *
      21             :  *                This program is distributed in the hope that it will
      22             :  *                be useful, but WITHOUT ANY WARRANTY; without even the
      23             :  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
      24             :  *                PARTICULAR PURPOSE.  See the GNU General Public
      25             :  *                License for more details.
      26             :  *
      27             :  *                The GNU General Public License should be included with
      28             :  *                this file.  If not, you can view it at
      29             :  *                http://www.gnu.org/copyleft/gpl.html
      30             :  *                or write to the Free Software Foundation, Inc., 59
      31             :  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
      32             :  *
      33             :  **********************************************************************/
      34             : 
      35             : 
      36             : #include "config.h"
      37             : 
      38             : #include <stdio.h>
      39             : #include <sys/types.h>
      40             : #include <stdlib.h>
      41             : #include <ctype.h>
      42             : #include <string.h>
      43             : #include <assert.h>
      44             : 
      45             : #if defined (HAVE_ACCESS) && defined (HAVE_UNISTD_H)
      46             : #include <unistd.h>
      47             : #endif /* def HAVE_ACCESS && HAVE_UNISTD_H */
      48             : 
      49             : #include "project.h"
      50             : #include "cgi.h"
      51             : #include "cgisimple.h"
      52             : #include "list.h"
      53             : #include "encode.h"
      54             : #include "jcc.h"
      55             : #include "filters.h"
      56             : #include "actions.h"
      57             : #include "miscutil.h"
      58             : #include "loadcfg.h"
      59             : #include "parsers.h"
      60             : #include "urlmatch.h"
      61             : #include "errlog.h"
      62             : #ifdef FEATURE_CLIENT_TAGS
      63             : #include "client-tags.h"
      64             : #endif
      65             : 
      66             : static jb_err show_defines(struct map *exports);
      67             : static jb_err cgi_show_file(struct client_state *csp,
      68             :                             struct http_response *rsp,
      69             :                             const struct map *parameters);
      70             : static jb_err load_file(const char *filename, char **buffer, size_t *length);
      71             : 
      72             : /*********************************************************************
      73             :  *
      74             :  * Function    :  cgi_default
      75             :  *
      76             :  * Description :  CGI function that is called for the CGI_SITE_1_HOST
      77             :  *                and CGI_SITE_2_HOST/CGI_SITE_2_PATH base URLs.
      78             :  *                Boring - only exports the default exports.
      79             :  *
      80             :  * Parameters  :
      81             :  *          1  :  csp = Current client state (buffers, headers, etc...)
      82             :  *          2  :  rsp = http_response data structure for output
      83             :  *          3  :  parameters = map of cgi parameters
      84             :  *
      85             :  * CGI Parameters : none
      86             :  *
      87             :  * Returns     :  JB_ERR_OK on success
      88             :  *                JB_ERR_MEMORY on out-of-memory
      89             :  *
      90             :  *********************************************************************/
      91        4320 : jb_err cgi_default(struct client_state *csp,
      92             :                    struct http_response *rsp,
      93             :                    const struct map *parameters)
      94             : {
      95             :    struct map *exports;
      96             : 
      97             :    (void)parameters;
      98             : 
      99        4320 :    assert(csp);
     100        4320 :    assert(rsp);
     101             : 
     102        4320 :    if (NULL == (exports = default_exports(csp, "")))
     103             :    {
     104           0 :       return JB_ERR_MEMORY;
     105             :    }
     106             : 
     107        4320 :    return template_fill_for_cgi(csp, "default", exports, rsp);
     108             : }
     109             : 
     110             : 
     111             : /*********************************************************************
     112             :  *
     113             :  * Function    :  cgi_error_404
     114             :  *
     115             :  * Description :  CGI function that is called if an unknown action was
     116             :  *                given.
     117             :  *
     118             :  * Parameters  :
     119             :  *          1  :  csp = Current client state (buffers, headers, etc...)
     120             :  *          2  :  rsp = http_response data structure for output
     121             :  *          3  :  parameters = map of cgi parameters
     122             :  *
     123             :  * CGI Parameters : none
     124             :  *
     125             :  * Returns     :  JB_ERR_OK on success
     126             :  *                JB_ERR_MEMORY on out-of-memory error.
     127             :  *
     128             :  *********************************************************************/
     129        2108 : jb_err cgi_error_404(struct client_state *csp,
     130             :                      struct http_response *rsp,
     131             :                      const struct map *parameters)
     132             : {
     133             :    struct map *exports;
     134             : 
     135        2108 :    assert(csp);
     136        2108 :    assert(rsp);
     137        2108 :    assert(parameters);
     138             : 
     139        2108 :    if (NULL == (exports = default_exports(csp, NULL)))
     140             :    {
     141           0 :       return JB_ERR_MEMORY;
     142             :    }
     143             : 
     144        2108 :    rsp->status = strdup_or_die("404 Privoxy configuration page not found");
     145             : 
     146        2108 :    return template_fill_for_cgi(csp, "cgi-error-404", exports, rsp);
     147             : }
     148             : 
     149             : 
     150             : #ifdef FEATURE_GRACEFUL_TERMINATION
     151             : /*********************************************************************
     152             :  *
     153             :  * Function    :  cgi_die
     154             :  *
     155             :  * Description :  CGI function to shut down Privoxy.
     156             :  *                NOTE: Turning this on in a production build
     157             :  *                would be a BAD idea.  An EXTREMELY BAD idea.
     158             :  *                In short, don't do it.
     159             :  *
     160             :  * Parameters  :
     161             :  *          1  :  csp = Current client state (buffers, headers, etc...)
     162             :  *          2  :  rsp = http_response data structure for output
     163             :  *          3  :  parameters = map of cgi parameters
     164             :  *
     165             :  * CGI Parameters : none
     166             :  *
     167             :  * Returns     :  JB_ERR_OK on success
     168             :  *
     169             :  *********************************************************************/
     170             : jb_err cgi_die (struct client_state *csp,
     171             :                 struct http_response *rsp,
     172             :                 const struct map *parameters)
     173             : {
     174             :    static const char status[] = "200 OK Privoxy shutdown request received";
     175             :    static const char body[] =
     176             :       "<html>\n"
     177             :       "<head>\n"
     178             :       " <title>Privoxy shutdown request received</title>\n"
     179             :       " <link rel=\"shortcut icon\" href=\"" CGI_PREFIX "error-favicon.ico\" type=\"image/x-icon\">\n"
     180             :       " <link rel=\"stylesheet\" type=\"text/css\" href=\"" CGI_PREFIX "send-stylesheet\">\n"
     181             :       "</head>\n"
     182             :       "<body>\n"
     183             :       "<h1>Privoxy shutdown request received</h1>\n"
     184             :       "<p>Privoxy is going to shut down after the next request.</p>\n"
     185             :       "</body>\n"
     186             :       "</html>\n";
     187             : 
     188             :    assert(csp);
     189             :    assert(rsp);
     190             :    assert(parameters);
     191             : 
     192             :    /* quit */
     193             :    g_terminate = 1;
     194             : 
     195             :    csp->flags &= ~CSP_FLAG_CLIENT_CONNECTION_KEEP_ALIVE;
     196             : 
     197             :    rsp->content_length = 0;
     198             :    rsp->head_length = 0;
     199             :    rsp->is_static = 0;
     200             : 
     201             :    rsp->body = strdup_or_die(body);
     202             :    rsp->status = strdup_or_die(status);
     203             : 
     204             :    return JB_ERR_OK;
     205             : }
     206             : #endif /* def FEATURE_GRACEFUL_TERMINATION */
     207             : 
     208             : 
     209             : /*********************************************************************
     210             :  *
     211             :  * Function    :  cgi_show_request
     212             :  *
     213             :  * Description :  Show the client's request and what sed() would have
     214             :  *                made of it.
     215             :  *
     216             :  * Parameters  :
     217             :  *          1  :  csp = Current client state (buffers, headers, etc...)
     218             :  *          2  :  rsp = http_response data structure for output
     219             :  *          3  :  parameters = map of cgi parameters
     220             :  *
     221             :  * CGI Parameters : none
     222             :  *
     223             :  * Returns     :  JB_ERR_OK on success
     224             :  *                JB_ERR_MEMORY on out-of-memory error.
     225             :  *
     226             :  *********************************************************************/
     227         134 : jb_err cgi_show_request(struct client_state *csp,
     228             :                         struct http_response *rsp,
     229             :                         const struct map *parameters)
     230             : {
     231             :    char *p;
     232             :    struct map *exports;
     233             : 
     234         134 :    assert(csp);
     235         134 :    assert(rsp);
     236         134 :    assert(parameters);
     237             : 
     238         134 :    if (NULL == (exports = default_exports(csp, "show-request")))
     239             :    {
     240           0 :       return JB_ERR_MEMORY;
     241             :    }
     242             : 
     243             :    /*
     244             :     * Repair the damage done to the IOB by get_header()
     245             :     */
     246       89557 :    for (p = csp->client_iob->buf; p < csp->client_iob->cur; p++)
     247             :    {
     248       89423 :       if (*p == '\0') *p = '\n';
     249             :    }
     250             : 
     251             :    /*
     252             :     * Export the original client's request and the one we would
     253             :     * be sending to the server if this wasn't a CGI call
     254             :     */
     255             : 
     256         134 :    if (map(exports, "client-request", 1, html_encode(csp->client_iob->buf), 0))
     257             :    {
     258           0 :       free_map(exports);
     259           0 :       return JB_ERR_MEMORY;
     260             :    }
     261             : 
     262         134 :    if (map(exports, "processed-request", 1,
     263         268 :          html_encode_and_free_original(
     264             : #ifdef FEATURE_HTTPS_INSPECTION
     265         134 :                                        csp->http->ssl ?
     266           3 :                                        list_to_text(csp->https_headers) :
     267             : #endif
     268         131 :                                        list_to_text(csp->headers)
     269             :                                        ), 0))
     270             :    {
     271           0 :       free_map(exports);
     272           0 :       return JB_ERR_MEMORY;
     273             :    }
     274             : 
     275         134 :    return template_fill_for_cgi(csp, "show-request", exports, rsp);
     276             : }
     277             : 
     278             : 
     279             : #ifdef FEATURE_CLIENT_TAGS
     280             : /*********************************************************************
     281             :  *
     282             :  * Function    :  cgi_create_client_tag_form
     283             :  *
     284             :  * Description :  Creates a HTML form to enable or disable a given
     285             :  *                client tag.
     286             :  *                XXX: Could use a template.
     287             :  *
     288             :  * Parameters  :
     289             :  *          1  :  form = Buffer to fill with the generated form
     290             :  *          2  :  size = Size of the form buffer
     291             :  *          3  :  tag = Name of the tag this form should affect
     292             :  *          4  :  toggle_state = Desired state after the button pressed 0
     293             :  *          5  :  expires = Whether or not the tag should be enabled.
     294             :  *                          Only checked if toggle_state is 1.
     295             :  *
     296             :  * Returns     :  void
     297             :  *
     298             :  *********************************************************************/
     299        1781 : static void cgi_create_client_tag_form(char *form, size_t size,
     300             :    const char *tag, int toggle_state, int expires)
     301             : {
     302             :    char *button_name;
     303             : 
     304        1781 :    if (toggle_state == 1)
     305             :    {
     306        1698 :       button_name = (expires == 1) ? "Enable" : "Enable temporarily";
     307             :    }
     308             :    else
     309             :    {
     310          83 :       assert(toggle_state == 0);
     311          83 :       button_name = "Disable";
     312             :    }
     313             : 
     314        1781 :    snprintf(form, size,
     315             :       "<form method=\"GET\" action=\""CGI_PREFIX"toggle-client-tag\" style=\"display: inline\">\n"
     316             :       " <input type=\"hidden\" name=\"tag\" value=\"%s\">\n"
     317             :       " <input type=\"hidden\" name=\"toggle-state\" value=\"%i\">\n"
     318             :       " <input type=\"hidden\" name=\"expires\" value=\"%u\">\n"
     319             :       " <input type=\"submit\" value=\"%s\">\n"
     320             :       "</form>", tag, toggle_state, !expires, button_name);
     321        1781 : }
     322             : 
     323             : /*********************************************************************
     324             :  *
     325             :  * Function    :  cgi_show_client_tags
     326             :  *
     327             :  * Description :  Shows the tags that can be set based on the client
     328             :  *                address (opt-in).
     329             :  *
     330             :  * Parameters  :
     331             :  *          1  :  csp = Current client state (buffers, headers, etc...)
     332             :  *          2  :  rsp = http_response data structure for output
     333             :  *          3  :  parameters = map of cgi parameters
     334             :  *
     335             :  * CGI Parameters : none
     336             :  *
     337             :  * Returns     :  JB_ERR_OK on success
     338             :  *                JB_ERR_MEMORY on out-of-memory error.
     339             :  *
     340             :  *********************************************************************/
     341         233 : jb_err cgi_show_client_tags(struct client_state *csp,
     342             :                         struct http_response *rsp,
     343             :                         const struct map *parameters)
     344             : {
     345             :    struct map *exports;
     346             :    struct client_tag_spec *this_tag;
     347         233 :    jb_err err = JB_ERR_OK;
     348             :    char *client_tag_status;
     349             :    char buf[1000];
     350             :    time_t refresh_delay;
     351             : 
     352         233 :    assert(csp);
     353         233 :    assert(rsp);
     354         233 :    assert(parameters);
     355             : 
     356         233 :    if (NULL == (exports = default_exports(csp, "client-tags")))
     357             :    {
     358           0 :       return JB_ERR_MEMORY;
     359             :    }
     360         233 :    assert(csp->client_address != NULL);
     361             : 
     362         233 :    this_tag = csp->config->client_tags;
     363         233 :    if (this_tag->name == NULL)
     364             :    {
     365           0 :       client_tag_status = strdup_or_die("<p>No tags have been configured.</p>\n");
     366             :    }
     367             :    else
     368             :    {
     369         233 :       client_tag_status = strdup_or_die("<table border=\"1\">\n"
     370             :          "<tr><th>Tag name</th>\n"
     371             :          "<th>Current state</th><th>Change state</th><th>Description</th></tr>\n");
     372        1165 :       while ((this_tag != NULL) && (this_tag->name != NULL))
     373             :       {
     374             :          int tag_state;
     375             : 
     376         932 :          privoxy_mutex_lock(&client_tags_mutex);
     377         932 :          tag_state = client_has_requested_tag(csp->client_address, this_tag->name);
     378         932 :          privoxy_mutex_unlock(&client_tags_mutex);
     379         932 :          if (!err) err = string_append(&client_tag_status, "<tr><td>");
     380         932 :          if (!err) err = string_append(&client_tag_status, this_tag->name);
     381         932 :          if (!err) err = string_append(&client_tag_status, "</td><td>");
     382         932 :          if (!err) err = string_append(&client_tag_status, tag_state == 1 ? "Enabled" : "Disabled");
     383         932 :          if (!err) err = string_append(&client_tag_status, "</td><td>");
     384         932 :          cgi_create_client_tag_form(buf, sizeof(buf), this_tag->name, !tag_state, 1);
     385         932 :          if (!err) err = string_append(&client_tag_status, buf);
     386         932 :          if (tag_state == 0)
     387             :          {
     388         849 :             cgi_create_client_tag_form(buf, sizeof(buf), this_tag->name, !tag_state, 0);
     389         849 :             if (!err) err = string_append(&client_tag_status, buf);
     390             :          }
     391         932 :          if (!err) err = string_append(&client_tag_status, "</td><td>");
     392         932 :          if (!err) err = string_append(&client_tag_status, this_tag->description);
     393         932 :          if (!err) err = string_append(&client_tag_status, "</td></tr>\n");
     394         932 :          if (err)
     395             :          {
     396           0 :             break;
     397             :          }
     398         932 :          this_tag = this_tag->next;
     399             :       }
     400         233 :       if (!err) err = string_append(&client_tag_status, "</table>\n");
     401         233 :       if (err)
     402             :       {
     403           0 :          free_map(exports);
     404           0 :          return JB_ERR_MEMORY;
     405             :       }
     406             :    }
     407         233 :    refresh_delay = get_next_tag_timeout_for_client(csp->client_address);
     408         233 :    if (refresh_delay != 0)
     409             :    {
     410          47 :       snprintf(buf, sizeof(buf), "%u", csp->config->client_tag_lifetime);
     411          47 :       if (map(exports, "refresh-delay", 1, buf, 1))
     412             :       {
     413           0 :          freez(client_tag_status);
     414           0 :          free_map(exports);
     415           0 :          return JB_ERR_MEMORY;
     416             :       }
     417             :    }
     418             :    else
     419             :    {
     420         186 :       err = map_block_killer(exports, "tags-expire");
     421         186 :       if (err != JB_ERR_OK)
     422             :       {
     423           0 :          freez(client_tag_status);
     424           0 :          return err;
     425             :       }
     426             :    }
     427             : 
     428         233 :    if (map(exports, "client-tags", 1, client_tag_status, 0))
     429             :    {
     430           0 :       free_map(exports);
     431           0 :       return JB_ERR_MEMORY;
     432             :    }
     433             : 
     434         233 :    if (map(exports, "client-ip-addr", 1, csp->client_address, 1))
     435             :    {
     436           0 :       free_map(exports);
     437           0 :       return JB_ERR_MEMORY;
     438             :    }
     439             : 
     440         233 :    return template_fill_for_cgi(csp, "client-tags", exports, rsp);
     441             : }
     442             : 
     443             : 
     444             : /*********************************************************************
     445             :  *
     446             :  * Function    :  cgi_toggle_client_tag
     447             :  *
     448             :  * Description :  Toggles a client tag and redirects to the show-tags
     449             :  *                page
     450             :  *
     451             :  * Parameters  :
     452             :  *          1  :  csp = Current client state (buffers, headers, etc...)
     453             :  *          2  :  rsp = http_response data structure for output
     454             :  *          3  :  parameters = map of cgi parameters
     455             :  *
     456             :  * CGI Parameters : none
     457             :  *          1  :  tag = Name of the tag to enable or disable
     458             :  *          2  :  toggle-state = How to toggle the tag (0/1)
     459             :  *          3  :  expires = Set to 1 if the tag should be enabled
     460             :  *                          temporarily, otherwise set to 0
     461             :  *
     462             :  * Returns     :  JB_ERR_OK on success
     463             :  *                JB_ERR_MEMORY on out-of-memory error.
     464             :  *
     465             :  *********************************************************************/
     466         909 : jb_err cgi_toggle_client_tag(struct client_state *csp,
     467             :                              struct http_response *rsp,
     468             :                              const struct map *parameters)
     469             : {
     470             :    const char *toggled_tag;
     471             :    const char *toggle_state;
     472             :    const char *tag_expires;
     473             :    time_t time_to_live;
     474             : 
     475         909 :    assert(csp);
     476         909 :    assert(rsp);
     477         909 :    assert(parameters);
     478             : 
     479         909 :    toggled_tag = lookup(parameters, "tag");
     480         909 :    if (*toggled_tag == '\0')
     481             :    {
     482         104 :       log_error(LOG_LEVEL_ERROR, "Received tag toggle request without tag");
     483             :    }
     484             :    else
     485             :    {
     486         805 :       tag_expires = lookup(parameters, "expires");
     487         805 :       if (*tag_expires == '0')
     488             :       {
     489          79 :          time_to_live = 0;
     490             :       }
     491             :       else
     492             :       {
     493         726 :          time_to_live = csp->config->client_tag_lifetime;
     494             :       }
     495         805 :       toggle_state = lookup(parameters, "toggle-state");
     496         805 :       if (*toggle_state == '1')
     497             :       {
     498         511 :          enable_client_specific_tag(csp, toggled_tag, time_to_live);
     499             :       }
     500             :       else
     501             :       {
     502         294 :          disable_client_specific_tag(csp, toggled_tag);
     503             :       }
     504             :    }
     505         909 :    rsp->status = strdup_or_die("302 Done dealing with toggle request");
     506         909 :    if (enlist_unique_header(rsp->headers,
     507             :          "Location", CGI_PREFIX "client-tags"))
     508             :    {
     509           0 :          return JB_ERR_MEMORY;
     510             :    }
     511         909 :    return JB_ERR_OK;
     512             : 
     513             : }
     514             : #endif /* def FEATURE_CLIENT_TAGS */
     515             : 
     516             : 
     517             : /*********************************************************************
     518             :  *
     519             :  * Function    :  cgi_send_banner
     520             :  *
     521             :  * Description :  CGI function that returns a banner.
     522             :  *
     523             :  * Parameters  :
     524             :  *          1  :  csp = Current client state (buffers, headers, etc...)
     525             :  *          2  :  rsp = http_response data structure for output
     526             :  *          3  :  parameters = map of cgi parameters
     527             :  *
     528             :  * CGI Parameters :
     529             :  *           type : Selects the type of banner between "trans", "logo",
     530             :  *                  and "auto". Defaults to "logo" if absent or invalid.
     531             :  *                  "auto" means to select as if we were image-blocking.
     532             :  *                  (Only the first character really counts; b and t are
     533             :  *                  equivalent).
     534             :  *
     535             :  * Returns     :  JB_ERR_OK on success
     536             :  *                JB_ERR_MEMORY on out-of-memory error.
     537             :  *
     538             :  *********************************************************************/
     539         733 : jb_err cgi_send_banner(struct client_state *csp,
     540             :                        struct http_response *rsp,
     541             :                        const struct map *parameters)
     542             : {
     543         733 :    char imagetype = lookup(parameters, "type")[0];
     544             : 
     545         733 :    if (imagetype != 'a' && imagetype != 'b' &&
     546         594 :        imagetype != 'p' && imagetype != 't')
     547             :    {
     548         555 :       log_error(LOG_LEVEL_ERROR, "Overruling invalid image type '%c'.",
     549             :          imagetype);
     550         555 :       imagetype = 'p';
     551             :    }
     552             : 
     553             :    /*
     554             :     * If type is auto, then determine the right thing
     555             :     * to do from the set-image-blocker action
     556             :     */
     557         733 :    if (imagetype == 'a')
     558             :    {
     559             :       /*
     560             :        * Default to pattern
     561             :        */
     562          82 :       imagetype = 'p';
     563             : 
     564             : #ifdef FEATURE_IMAGE_BLOCKING
     565          82 :       if ((csp->action->flags & ACTION_IMAGE_BLOCKER) != 0)
     566             :       {
     567             :          static const char prefix1[] = CGI_PREFIX "send-banner?type=";
     568             :          static const char prefix2[] = "http://" CGI_SITE_1_HOST "/send-banner?type=";
     569           0 :          const char *p = csp->action->string[ACTION_STRING_IMAGE_BLOCKER];
     570             : 
     571           0 :          if (p == NULL)
     572             :          {
     573             :             /* Use default - nothing to do here. */
     574             :          }
     575           0 :          else if (0 == strcmpic(p, "blank"))
     576             :          {
     577           0 :             imagetype = 'b';
     578             :          }
     579           0 :          else if (0 == strcmpic(p, "pattern"))
     580             :          {
     581           0 :             imagetype = 'p';
     582             :          }
     583             : 
     584             :          /*
     585             :           * If the action is to call this CGI, determine
     586             :           * the argument:
     587             :           */
     588           0 :          else if (0 == strncmpic(p, prefix1, sizeof(prefix1) - 1))
     589             :          {
     590           0 :             imagetype = p[sizeof(prefix1) - 1];
     591             :          }
     592           0 :          else if (0 == strncmpic(p, prefix2, sizeof(prefix2) - 1))
     593             :          {
     594           0 :             imagetype = p[sizeof(prefix2) - 1];
     595             :          }
     596             : 
     597             :          /*
     598             :           * Everything else must (should) be a URL to
     599             :           * redirect to.
     600             :           */
     601             :          else
     602             :          {
     603           0 :             imagetype = 'r';
     604             :          }
     605             :       }
     606             : #endif /* def FEATURE_IMAGE_BLOCKING */
     607             :    }
     608             : 
     609             :    /*
     610             :     * Now imagetype is either the non-auto type we were called with,
     611             :     * or it was auto and has since been determined. In any case, we
     612             :     * can proceed to actually answering the request by sending a redirect
     613             :     * or an image as appropriate:
     614             :     */
     615         733 :    if (imagetype == 'r')
     616             :    {
     617           0 :       rsp->status = strdup_or_die("302 Local Redirect from Privoxy");
     618           0 :       if (enlist_unique_header(rsp->headers, "Location",
     619           0 :                                csp->action->string[ACTION_STRING_IMAGE_BLOCKER]))
     620             :       {
     621           0 :          return JB_ERR_MEMORY;
     622             :       }
     623             :    }
     624             :    else
     625             :    {
     626         733 :       if ((imagetype == 'b') || (imagetype == 't'))
     627             :       {
     628          73 :          rsp->body = bindup(image_blank_data, image_blank_length);
     629          73 :          rsp->content_length = image_blank_length;
     630             :       }
     631             :       else
     632             :       {
     633         660 :          rsp->body = bindup(image_pattern_data, image_pattern_length);
     634         660 :          rsp->content_length = image_pattern_length;
     635             :       }
     636             : 
     637         733 :       if (rsp->body == NULL)
     638             :       {
     639           0 :          return JB_ERR_MEMORY;
     640             :       }
     641         733 :       if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE))
     642             :       {
     643           0 :          return JB_ERR_MEMORY;
     644             :       }
     645             : 
     646         733 :       rsp->is_static = 1;
     647             :    }
     648             : 
     649         733 :    return JB_ERR_OK;
     650             : 
     651             : }
     652             : 
     653             : 
     654             : /*********************************************************************
     655             :  *
     656             :  * Function    :  cgi_transparent_image
     657             :  *
     658             :  * Description :  CGI function that sends a 1x1 transparent image.
     659             :  *
     660             :  * Parameters  :
     661             :  *          1  :  csp = Current client state (buffers, headers, etc...)
     662             :  *          2  :  rsp = http_response data structure for output
     663             :  *          3  :  parameters = map of cgi parameters
     664             :  *
     665             :  * CGI Parameters : None
     666             :  *
     667             :  * Returns     :  JB_ERR_OK on success
     668             :  *                JB_ERR_MEMORY on out-of-memory error.
     669             :  *
     670             :  *********************************************************************/
     671          80 : jb_err cgi_transparent_image(struct client_state *csp,
     672             :                              struct http_response *rsp,
     673             :                              const struct map *parameters)
     674             : {
     675             :    (void)csp;
     676             :    (void)parameters;
     677             : 
     678          80 :    rsp->body = bindup(image_blank_data, image_blank_length);
     679          80 :    rsp->content_length = image_blank_length;
     680             : 
     681          80 :    if (rsp->body == NULL)
     682             :    {
     683           0 :       return JB_ERR_MEMORY;
     684             :    }
     685             : 
     686          80 :    if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE))
     687             :    {
     688           0 :       return JB_ERR_MEMORY;
     689             :    }
     690             : 
     691          80 :    rsp->is_static = 1;
     692             : 
     693          80 :    return JB_ERR_OK;
     694             : 
     695             : }
     696             : 
     697             : 
     698             : /*********************************************************************
     699             :  *
     700             :  * Function    :  cgi_send_default_favicon
     701             :  *
     702             :  * Description :  CGI function that sends the standard favicon.
     703             :  *
     704             :  * Parameters  :
     705             :  *          1  :  csp = Current client state (buffers, headers, etc...)
     706             :  *          2  :  rsp = http_response data structure for output
     707             :  *          3  :  parameters = map of cgi parameters
     708             :  *
     709             :  * CGI Parameters : None
     710             :  *
     711             :  * Returns     :  JB_ERR_OK on success
     712             :  *                JB_ERR_MEMORY on out-of-memory error.
     713             :  *
     714             :  *********************************************************************/
     715         496 : jb_err cgi_send_default_favicon(struct client_state *csp,
     716             :                                 struct http_response *rsp,
     717             :                                 const struct map *parameters)
     718             : {
     719             :    static const char default_favicon_data[] =
     720             :       "\000\000\001\000\001\000\020\020\002\000\000\000\000\000\260"
     721             :       "\000\000\000\026\000\000\000\050\000\000\000\020\000\000\000"
     722             :       "\040\000\000\000\001\000\001\000\000\000\000\000\100\000\000"
     723             :       "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000"
     724             :       "\000\000\377\377\377\000\377\000\052\000\017\360\000\000\077"
     725             :       "\374\000\000\161\376\000\000\161\376\000\000\361\377\000\000"
     726             :       "\361\377\000\000\360\017\000\000\360\007\000\000\361\307\000"
     727             :       "\000\361\307\000\000\361\307\000\000\360\007\000\000\160\036"
     728             :       "\000\000\177\376\000\000\077\374\000\000\017\360\000\000\360"
     729             :       "\017\000\000\300\003\000\000\200\001\000\000\200\001\000\000"
     730             :       "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
     731             :       "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
     732             :       "\000\000\200\001\000\000\200\001\000\000\300\003\000\000\360"
     733             :       "\017\000\000";
     734             :    static const size_t favicon_length = sizeof(default_favicon_data) - 1;
     735             : 
     736             :    (void)csp;
     737             :    (void)parameters;
     738             : 
     739         496 :    rsp->body = bindup(default_favicon_data, favicon_length);
     740         496 :    rsp->content_length = favicon_length;
     741             : 
     742         496 :    if (rsp->body == NULL)
     743             :    {
     744           0 :       return JB_ERR_MEMORY;
     745             :    }
     746             : 
     747         496 :    if (enlist(rsp->headers, "Content-Type: image/x-icon"))
     748             :    {
     749           0 :       return JB_ERR_MEMORY;
     750             :    }
     751             : 
     752         496 :    rsp->is_static = 1;
     753             : 
     754         496 :    return JB_ERR_OK;
     755             : 
     756             : }
     757             : 
     758             : 
     759             : /*********************************************************************
     760             :  *
     761             :  * Function    :  cgi_send_error_favicon
     762             :  *
     763             :  * Description :  CGI function that sends the favicon for error pages.
     764             :  *
     765             :  * Parameters  :
     766             :  *          1  :  csp = Current client state (buffers, headers, etc...)
     767             :  *          2  :  rsp = http_response data structure for output
     768             :  *          3  :  parameters = map of cgi parameters
     769             :  *
     770             :  * CGI Parameters : None
     771             :  *
     772             :  * Returns     :  JB_ERR_OK on success
     773             :  *                JB_ERR_MEMORY on out-of-memory error.
     774             :  *
     775             :  *********************************************************************/
     776          68 : jb_err cgi_send_error_favicon(struct client_state *csp,
     777             :                               struct http_response *rsp,
     778             :                               const struct map *parameters)
     779             : {
     780             :    static const char error_favicon_data[] =
     781             :       "\000\000\001\000\001\000\020\020\002\000\000\000\000\000\260"
     782             :       "\000\000\000\026\000\000\000\050\000\000\000\020\000\000\000"
     783             :       "\040\000\000\000\001\000\001\000\000\000\000\000\100\000\000"
     784             :       "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000"
     785             :       "\000\000\377\377\377\000\000\000\377\000\017\360\000\000\077"
     786             :       "\374\000\000\161\376\000\000\161\376\000\000\361\377\000\000"
     787             :       "\361\377\000\000\360\017\000\000\360\007\000\000\361\307\000"
     788             :       "\000\361\307\000\000\361\307\000\000\360\007\000\000\160\036"
     789             :       "\000\000\177\376\000\000\077\374\000\000\017\360\000\000\360"
     790             :       "\017\000\000\300\003\000\000\200\001\000\000\200\001\000\000"
     791             :       "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
     792             :       "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
     793             :       "\000\000\200\001\000\000\200\001\000\000\300\003\000\000\360"
     794             :       "\017\000\000";
     795             :    static const size_t favicon_length = sizeof(error_favicon_data) - 1;
     796             : 
     797             :    (void)csp;
     798             :    (void)parameters;
     799             : 
     800          68 :    rsp->body = bindup(error_favicon_data, favicon_length);
     801          68 :    rsp->content_length = favicon_length;
     802             : 
     803          68 :    if (rsp->body == NULL)
     804             :    {
     805           0 :       return JB_ERR_MEMORY;
     806             :    }
     807             : 
     808          68 :    if (enlist(rsp->headers, "Content-Type: image/x-icon"))
     809             :    {
     810           0 :       return JB_ERR_MEMORY;
     811             :    }
     812             : 
     813          68 :    rsp->is_static = 1;
     814             : 
     815          68 :    return JB_ERR_OK;
     816             : 
     817             : }
     818             : 
     819             : 
     820             : /*********************************************************************
     821             :  *
     822             :  * Function    :  cgi_send_stylesheet
     823             :  *
     824             :  * Description :  CGI function that sends a css stylesheet found
     825             :  *                in the cgi-style.css template
     826             :  *
     827             :  * Parameters  :
     828             :  *          1  :  csp = Current client state (buffers, headers, etc...)
     829             :  *          2  :  rsp = http_response data structure for output
     830             :  *          3  :  parameters = map of cgi parameters
     831             :  *
     832             :  * CGI Parameters : None
     833             :  *
     834             :  * Returns     :  JB_ERR_OK on success
     835             :  *                JB_ERR_MEMORY on out-of-memory error.
     836             :  *
     837             :  *********************************************************************/
     838          47 : jb_err cgi_send_stylesheet(struct client_state *csp,
     839             :                            struct http_response *rsp,
     840             :                            const struct map *parameters)
     841             : {
     842             :    jb_err err;
     843             : 
     844          47 :    assert(csp);
     845          47 :    assert(rsp);
     846             : 
     847             :    (void)parameters;
     848             : 
     849          47 :    err = template_load(csp, &rsp->body, "cgi-style.css", 0);
     850             : 
     851          47 :    if (err == JB_ERR_FILE)
     852             :    {
     853             :       /*
     854             :        * No way to tell user; send empty stylesheet
     855             :        */
     856           0 :       log_error(LOG_LEVEL_ERROR, "Could not find cgi-style.css template");
     857             :    }
     858          47 :    else if (err)
     859             :    {
     860           0 :       return err; /* JB_ERR_MEMORY */
     861             :    }
     862             : 
     863          47 :    if (enlist(rsp->headers, "Content-Type: text/css"))
     864             :    {
     865           0 :       return JB_ERR_MEMORY;
     866             :    }
     867             : 
     868          47 :    return JB_ERR_OK;
     869             : 
     870             : }
     871             : 
     872             : 
     873             : /*********************************************************************
     874             :  *
     875             :  * Function    :  cgi_send_url_info_osd
     876             :  *
     877             :  * Description :  CGI function that sends the OpenSearch Description
     878             :  *                template for the show-url-info page. It allows to
     879             :  *                access the page through "search engine plugins".
     880             :  *
     881             :  * Parameters  :
     882             :  *          1  :  csp = Current client state (buffers, headers, etc...)
     883             :  *          2  :  rsp = http_response data structure for output
     884             :  *          3  :  parameters = map of cgi parameters
     885             :  *
     886             :  * CGI Parameters : None
     887             :  *
     888             :  * Returns     :  JB_ERR_OK on success
     889             :  *                JB_ERR_MEMORY on out-of-memory error.
     890             :  *
     891             :  *********************************************************************/
     892          88 : jb_err cgi_send_url_info_osd(struct client_state *csp,
     893             :                                struct http_response *rsp,
     894             :                                const struct map *parameters)
     895             : {
     896          88 :    jb_err err = JB_ERR_MEMORY;
     897          88 :    struct map *exports = default_exports(csp, NULL);
     898             : 
     899             :    (void)csp;
     900             :    (void)parameters;
     901             : 
     902          88 :    if (NULL != exports)
     903             :    {
     904          88 :       err = template_fill_for_cgi(csp, "url-info-osd.xml", exports, rsp);
     905          88 :       if (JB_ERR_OK == err)
     906             :       {
     907          88 :          err = enlist(rsp->headers,
     908             :             "Content-Type: application/opensearchdescription+xml");
     909             :       }
     910             :    }
     911             : 
     912          88 :    return err;
     913             : 
     914             : }
     915             : 
     916             : 
     917             : /*********************************************************************
     918             :  *
     919             :  * Function    :  get_content_type
     920             :  *
     921             :  * Description :  Use the file extension to guess the content type
     922             :  *                header we should use to serve the file.
     923             :  *
     924             :  * Parameters  :
     925             :  *          1  :  filename = Name of the file whose content type
     926             :  *                           we care about
     927             :  *
     928             :  * Returns     :  The guessed content type.
     929             :  *
     930             :  *********************************************************************/
     931           0 : static const char *get_content_type(const char *filename)
     932             : {
     933             :    int i;
     934             :    struct content_type
     935             :    {
     936             :       const char extension[6];
     937             :       const char content_type[11];
     938             :    };
     939             :    static const struct content_type content_types[] =
     940             :    {
     941             :       {".css",  "text/css"},
     942             :       {".jpg",  "image/jpeg"},
     943             :       {".jpeg", "image/jpeg"},
     944             :       {".png",  "image/png"},
     945             :    };
     946             : 
     947           0 :    for (i = 0; i < SZ(content_types); i++)
     948             :    {
     949           0 :       if (strstr(filename, content_types[i].extension))
     950             :       {
     951           0 :          return content_types[i].content_type;
     952             :       }
     953             :    }
     954             : 
     955             :    /* No match by extension, default to html */
     956           0 :    return "text/html";
     957             : }
     958             : 
     959             : /*********************************************************************
     960             :  *
     961             :  * Function    :  cgi_send_user_manual
     962             :  *
     963             :  * Description :  CGI function that sends a file in the user
     964             :  *                manual directory.
     965             :  *
     966             :  * Parameters  :
     967             :  *          1  :  csp = Current client state (buffers, headers, etc...)
     968             :  *          2  :  rsp = http_response data structure for output
     969             :  *          3  :  parameters = map of cgi parameters
     970             :  *
     971             :  * CGI Parameters : file=name.html, the name of the HTML file
     972             :  *                  (relative to user-manual from config)
     973             :  *
     974             :  * Returns     :  JB_ERR_OK on success
     975             :  *                JB_ERR_MEMORY on out-of-memory error.
     976             :  *
     977             :  *********************************************************************/
     978        1904 : jb_err cgi_send_user_manual(struct client_state *csp,
     979             :                             struct http_response *rsp,
     980             :                             const struct map *parameters)
     981             : {
     982             :    const char *filename;
     983             :    char *full_path;
     984        1904 :    jb_err err = JB_ERR_OK;
     985             :    const char *content_type;
     986             : 
     987        1904 :    assert(csp);
     988        1904 :    assert(rsp);
     989        1904 :    assert(parameters);
     990             : 
     991        1904 :    if (0 == strncmpic(csp->config->usermanual, "http://", 7))
     992             :    {
     993           0 :       log_error(LOG_LEVEL_CGI, "Request for local user-manual "
     994             :          "received while user-manual delivery is disabled.");
     995           0 :       return cgi_error_404(csp, rsp, parameters);
     996             :    }
     997             : 
     998        1904 :    if (!parameters->first)
     999             :    {
    1000             :       /* requested http://p.p/user-manual (without trailing slash) */
    1001        1509 :       return cgi_redirect(rsp, CGI_PREFIX "user-manual/");
    1002             :    }
    1003             : 
    1004         395 :    get_string_param(parameters, "file", &filename);
    1005         395 :    if (filename == NULL)
    1006             :    {
    1007             :       /* It's '/' so serve the index.html if there is one.  */
    1008         263 :       filename = "index.html";
    1009             :    }
    1010         132 :    else if (NULL != strchr(filename, '/') || NULL != strstr(filename, ".."))
    1011             :    {
    1012             :       /*
    1013             :        * We currently only support a flat file
    1014             :        * hierarchy for the documentation.
    1015             :        */
    1016          60 :       log_error(LOG_LEVEL_ERROR,
    1017             :          "Rejecting the request to serve '%s' as it contains '/' or '..'",
    1018             :          filename);
    1019          60 :       return JB_ERR_CGI_PARAMS;
    1020             :    }
    1021             : 
    1022         335 :    full_path = make_path(csp->config->usermanual, filename);
    1023         335 :    if (full_path == NULL)
    1024             :    {
    1025           0 :       return JB_ERR_MEMORY;
    1026             :    }
    1027             : 
    1028         335 :    err = load_file(full_path, &rsp->body, &rsp->content_length);
    1029         335 :    if (JB_ERR_OK != err)
    1030             :    {
    1031         335 :       assert((JB_ERR_FILE == err) || (JB_ERR_MEMORY == err));
    1032         335 :       if (JB_ERR_FILE == err)
    1033             :       {
    1034         335 :          err = cgi_error_no_template(csp, rsp, full_path);
    1035             :       }
    1036         335 :       freez(full_path);
    1037         335 :       return err;
    1038             :    }
    1039           0 :    freez(full_path);
    1040             : 
    1041           0 :    content_type = get_content_type(filename);
    1042           0 :    log_error(LOG_LEVEL_CGI,
    1043             :       "Content-Type guessed for %s: %s", filename, content_type);
    1044             : 
    1045           0 :    return enlist_unique_header(rsp->headers, "Content-Type", content_type);
    1046             : 
    1047             : }
    1048             : 
    1049             : 
    1050             : #ifdef FEATURE_EXTENDED_STATISTICS
    1051             : /*********************************************************************
    1052             :  *
    1053             :  * Function    :  get_block_reason_statistics_table
    1054             :  *
    1055             :  * Description :  Produces the block reason statistic table content.
    1056             :  *
    1057             :  * Parameters  :
    1058             :  *          1  :  csp = Current client state (buffers, headers, etc...)
    1059             :  *
    1060             :  * Returns     :  Pointer to the HTML statistic table content or
    1061             :  *                NULL on out of memory
    1062             :  *
    1063             :  *********************************************************************/
    1064         500 : static char *get_block_reason_statistics_table(const struct client_state *csp)
    1065             : {
    1066             :    char buf[BUFFER_SIZE];
    1067             :    char *statistics;
    1068             :    int i;
    1069             :    struct file_list *fl;
    1070         500 :    jb_err err = JB_ERR_OK;
    1071             : 
    1072         500 :    statistics = strdup_or_die("");
    1073             : 
    1074             :    /* Run through all action files. */
    1075       50500 :    for (i = 0; i < MAX_AF_FILES; i++)
    1076             :    {
    1077             :       struct url_actions *b;
    1078       50000 :       struct action_spec *last_action = NULL;
    1079             : 
    1080       50000 :       if (((fl = csp->actions_list[i]) == NULL) || ((b = fl->f) == NULL))
    1081             :       {
    1082             :          /* Skip empty files */
    1083       49000 :          continue;
    1084             :       }
    1085             : 
    1086             :       /* Go through all the actions. */
    1087       11500 :       for (b = b->next; NULL != b; b = b->next)
    1088             :       {
    1089       10500 :          if (last_action == b->action)
    1090             :          {
    1091         500 :             continue;
    1092             :          }
    1093       10000 :          if ((b->action->add & ACTION_BLOCK))
    1094             :          {
    1095             :             unsigned long long count;
    1096        1500 :             const char *block_reason = b->action->string[ACTION_STRING_BLOCK];
    1097        1500 :             const char *encoded_block_reason = html_encode(block_reason);
    1098             : 
    1099        1500 :             if (encoded_block_reason == NULL)
    1100             :             {
    1101           0 :                freez(statistics);
    1102           0 :                return NULL;
    1103             :             }
    1104        1500 :             get_block_reason_count(block_reason, &count);
    1105        1500 :             snprintf(buf, sizeof(buf),
    1106             :                "<tr><td>%s</td><td style=\"text-align: right\">%llu</td>\n",
    1107             :                encoded_block_reason, count);
    1108        1500 :             freez(encoded_block_reason);
    1109             : 
    1110        1500 :             if (!err) err = string_append(&statistics, buf);
    1111             :          }
    1112       10000 :          last_action = b->action;
    1113             :       }
    1114             :    }
    1115             : 
    1116         500 :    return statistics;
    1117             : 
    1118             : }
    1119             : 
    1120             : 
    1121             : /*********************************************************************
    1122             :  *
    1123             :  * Function    :  get_filter_statistics_table
    1124             :  *
    1125             :  * Description :  Produces the filter statistic table content.
    1126             :  *
    1127             :  * Parameters  :
    1128             :  *          1  :  csp = Current client state (buffers, headers, etc...)
    1129             :  *
    1130             :  * Returns     :  Pointer to the HTML statistic table content or
    1131             :  *                NULL on out of memory
    1132             :  *
    1133             :  *********************************************************************/
    1134         500 : static char *get_filter_statistics_table(const struct client_state *csp)
    1135             : {
    1136             :    char buf[BUFFER_SIZE];
    1137             :    char *statistics;
    1138             :    int i;
    1139             :    struct file_list *fl;
    1140             :    struct re_filterfile_spec *b;
    1141         500 :    jb_err err = JB_ERR_OK;
    1142             : 
    1143         500 :    statistics = strdup_or_die("");
    1144             : 
    1145       50500 :    for (i = 0; i < MAX_AF_FILES; i++)
    1146             :    {
    1147       50000 :      fl = csp->rlist[i];
    1148       50000 :      if ((NULL == fl) || (NULL == fl->f))
    1149             :      {
    1150             :         /*
    1151             :          * Either there are no filter files left or this
    1152             :          * filter file just contains no valid filters.
    1153             :          *
    1154             :          * Continue to be sure we don't miss valid filter
    1155             :          * files that are chained after empty or invalid ones.
    1156             :          */
    1157       49500 :         continue;
    1158             :      }
    1159             : 
    1160        6500 :      for (b = fl->f; b != NULL; b = b->next)
    1161             :      {
    1162        6000 :         if (b->type == FT_CONTENT_FILTER)
    1163             :         {
    1164             :            unsigned long long executions;
    1165             :            unsigned long long response_bodies_modified;
    1166             :            unsigned long long hits;
    1167             : 
    1168        2000 :            get_filter_statistics(b->name, &executions, &response_bodies_modified, &hits);
    1169        2000 :            snprintf(buf, sizeof(buf),
    1170             :               "<tr><td>%s</td><td style=\"text-align: right\">%llu</td>"
    1171             :               "<td style=\"text-align: right\">%llu</td>"
    1172             :               "<td style=\"text-align: right\">%llu</td><tr>\n",
    1173             :               b->name, executions, response_bodies_modified, hits);
    1174             : 
    1175        2000 :            if (!err) err = string_append(&statistics, buf);
    1176             :         }
    1177             :      }
    1178             :    }
    1179             : 
    1180         500 :    return statistics;
    1181             : 
    1182             : }
    1183             : #endif /* def FEATURE_EXTENDED_STATISTICS */
    1184             : 
    1185             : 
    1186             : /*********************************************************************
    1187             :  *
    1188             :  * Function    :  cgi_show_status
    1189             :  *
    1190             :  * Description :  CGI function that returns a web page describing the
    1191             :  *                current status of Privoxy.
    1192             :  *
    1193             :  * Parameters  :
    1194             :  *          1  :  csp = Current client state (buffers, headers, etc...)
    1195             :  *          2  :  rsp = http_response data structure for output
    1196             :  *          3  :  parameters = map of cgi parameters
    1197             :  *
    1198             :  * CGI Parameters :
    1199             :  *        file :  Which file to show.  Only first letter is checked,
    1200             :  *                valid values are:
    1201             :  *                - "a"ction file
    1202             :  *                - "r"egex
    1203             :  *                - "t"rust
    1204             :  *                Default is to show menu and other information.
    1205             :  *
    1206             :  * Returns     :  JB_ERR_OK on success
    1207             :  *                JB_ERR_MEMORY on out-of-memory error.
    1208             :  *
    1209             :  *********************************************************************/
    1210         948 : jb_err cgi_show_status(struct client_state *csp,
    1211             :                        struct http_response *rsp,
    1212             :                        const struct map *parameters)
    1213             : {
    1214         948 :    char *s = NULL;
    1215             :    unsigned i;
    1216             :    int j;
    1217             : 
    1218             :    char buf[BUFFER_SIZE];
    1219             : #ifdef FEATURE_STATISTICS
    1220             :    float perc_rej;   /* Percentage of http requests rejected */
    1221             :    int local_urls_read;
    1222             :    int local_urls_rejected;
    1223             : #endif /* ndef FEATURE_STATISTICS */
    1224         948 :    jb_err err = JB_ERR_OK;
    1225             : 
    1226             :    struct map *exports;
    1227             : 
    1228         948 :    assert(csp);
    1229         948 :    assert(rsp);
    1230         948 :    assert(parameters);
    1231             : 
    1232         948 :    if ('\0' != *(lookup(parameters, "file")))
    1233             :    {
    1234         448 :       return cgi_show_file(csp, rsp, parameters);
    1235             :    }
    1236             : 
    1237         500 :    if (NULL == (exports = default_exports(csp, "show-status")))
    1238             :    {
    1239           0 :       return JB_ERR_MEMORY;
    1240             :    }
    1241             : 
    1242         500 :    s = strdup("");
    1243        3000 :    for (j = 0; (s != NULL) && (j < Argc); j++)
    1244             :    {
    1245        2500 :       if (!err) err = string_join  (&s, html_encode(Argv[j]));
    1246        2500 :       if (!err) err = string_append(&s, " ");
    1247             :    }
    1248         500 :    if (!err) err = map(exports, "invocation", 1, s, 0);
    1249             : 
    1250         500 :    if (!err) err = map(exports, "options", 1, csp->config->proxy_args, 1);
    1251         500 :    if (!err) err = show_defines(exports);
    1252             : 
    1253         500 :    if (err)
    1254             :    {
    1255           0 :       free_map(exports);
    1256           0 :       return JB_ERR_MEMORY;
    1257             :    }
    1258             : 
    1259             : #ifdef FEATURE_STATISTICS
    1260         500 :    local_urls_read     = urls_read;
    1261         500 :    local_urls_rejected = urls_rejected;
    1262             : 
    1263             :    /*
    1264             :     * Need to alter the stats not to include the fetch of this
    1265             :     * page.
    1266             :     *
    1267             :     * Can't do following thread safely! doh!
    1268             :     *
    1269             :     * urls_read--;
    1270             :     * urls_rejected--; * This will be incremented subsequently *
    1271             :     */
    1272             : 
    1273         500 :    if (local_urls_read == 0)
    1274             :    {
    1275         500 :       if (!err) err = map_block_killer(exports, "have-stats");
    1276             :    }
    1277             :    else
    1278             :    {
    1279           0 :       if (!err) err = map_block_killer(exports, "have-no-stats");
    1280             : 
    1281           0 :       perc_rej = (float)local_urls_rejected * 100.0F /
    1282           0 :             (float)local_urls_read;
    1283             : 
    1284           0 :       snprintf(buf, sizeof(buf), "%d", local_urls_read);
    1285           0 :       if (!err) err = map(exports, "requests-received", 1, buf, 1);
    1286             : 
    1287           0 :       snprintf(buf, sizeof(buf), "%d", local_urls_rejected);
    1288           0 :       if (!err) err = map(exports, "requests-blocked", 1, buf, 1);
    1289             : 
    1290           0 :       snprintf(buf, sizeof(buf), "%6.2f", perc_rej);
    1291           0 :       if (!err) err = map(exports, "percent-blocked", 1, buf, 1);
    1292             :    }
    1293             : 
    1294             : #else /* ndef FEATURE_STATISTICS */
    1295             :    if (!err) err = map_block_killer(exports, "statistics");
    1296             : #endif /* ndef FEATURE_STATISTICS */
    1297             : 
    1298             : #ifdef FEATURE_EXTENDED_STATISTICS
    1299         500 :    if (!err)
    1300             :    {
    1301         500 :       char *block_reason_statistics = get_block_reason_statistics_table(csp);
    1302         500 :       if (block_reason_statistics != NULL)
    1303             :       {
    1304         500 :          err = map(exports, "block-reason-statistics", 1, block_reason_statistics, 0);
    1305             :       }
    1306             :       else
    1307             :       {
    1308           0 :          err = map_block_killer(exports, "extended-statistics");
    1309             :       }
    1310             :    }
    1311         500 :    if (!err)
    1312             :    {
    1313         500 :       char *filter_statistics = get_filter_statistics_table(csp);
    1314         500 :       if (filter_statistics != NULL)
    1315             :       {
    1316         500 :          err = map(exports, "filter-statistics", 1, filter_statistics, 0);
    1317             :       }
    1318             :       else
    1319             :       {
    1320           0 :          err = map_block_killer(exports, "extended-statistics");
    1321             :       }
    1322             :    }
    1323             : #else /* ndef FEATURE_EXTENDED_STATISTICS */
    1324             :    if (!err) err = map_block_killer(exports, "extended-statistics");
    1325             : #endif /* def FEATURE_EXTENDED_STATISTICS */
    1326             : 
    1327             :    /*
    1328             :     * List all action files in use, together with view and edit links,
    1329             :     * except for standard.action, which should only be viewable. (Not
    1330             :     * enforced in the editor itself)
    1331             :     * FIXME: Shouldn't include hardwired HTML here, use line template instead!
    1332             :     */
    1333         500 :    s = strdup("");
    1334       50500 :    for (i = 0; i < MAX_AF_FILES; i++)
    1335             :    {
    1336       50000 :       if (csp->actions_list[i] != NULL)
    1337             :       {
    1338        1000 :          if (!err) err = string_append(&s, "<tr><td>");
    1339        1000 :          if (!err) err = string_join(&s, html_encode(csp->actions_list[i]->filename));
    1340        1000 :          snprintf(buf, sizeof(buf),
    1341             :             "</td><td class=\"buttons\"><a href=\"/show-status?file=actions&amp;index=%u\">View</a>", i);
    1342        1000 :          if (!err) err = string_append(&s, buf);
    1343             : 
    1344             : #ifdef FEATURE_CGI_EDIT_ACTIONS
    1345        1000 :          if ((csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)
    1346        1000 :             && (NULL != csp->config->actions_file_short[i]))
    1347             :          {
    1348             : #ifdef HAVE_ACCESS
    1349        1000 :             if (access(csp->config->actions_file[i], W_OK) == 0)
    1350             :             {
    1351             : #endif /* def HAVE_ACCESS */
    1352        1000 :                snprintf(buf, sizeof(buf), "&nbsp;&nbsp;<a href=\"/edit-actions-list?f=%u\">Edit</a>", i);
    1353        1000 :                if (!err) err = string_append(&s, buf);
    1354             : #ifdef HAVE_ACCESS
    1355             :             }
    1356             :             else
    1357             :             {
    1358           0 :                if (!err) err = string_append(&s, "&nbsp;&nbsp;<strong>No write access.</strong>");
    1359             :             }
    1360             : #endif /* def HAVE_ACCESS */
    1361             :          }
    1362             : #endif
    1363             : 
    1364        1000 :          if (!err) err = string_append(&s, "</td></tr>\n");
    1365             :       }
    1366             :    }
    1367         500 :    if (!err && *s != '\0')
    1368             :    {
    1369         500 :       err = map(exports, "actions-filenames", 1, s, 0);
    1370             :    }
    1371             :    else
    1372             :    {
    1373           0 :       if (!err) err = map(exports, "actions-filenames", 1, "<tr><td>None specified</td></tr>", 1);
    1374           0 :       freez(s);
    1375             :    }
    1376             : 
    1377             :    /*
    1378             :     * List all re_filterfiles in use, together with view options.
    1379             :     * FIXME: Shouldn't include hardwired HTML here, use line template instead!
    1380             :     */
    1381         500 :    s = strdup("");
    1382       50500 :    for (i = 0; i < MAX_AF_FILES; i++)
    1383             :    {
    1384       50000 :       if (csp->rlist[i] != NULL)
    1385             :       {
    1386        1000 :          if (!err) err = string_append(&s, "<tr><td>");
    1387        1000 :          if (!err) err = string_join(&s, html_encode(csp->rlist[i]->filename));
    1388        1000 :          snprintf(buf, sizeof(buf),
    1389             :             "</td><td class=\"buttons\"><a href=\"/show-status?file=filter&amp;index=%u\">View</a>", i);
    1390        1000 :          if (!err) err = string_append(&s, buf);
    1391        1000 :          if (!err) err = string_append(&s, "</td></tr>\n");
    1392             :       }
    1393             :    }
    1394         500 :    if (!err && *s != '\0')
    1395             :    {
    1396         500 :       err = map(exports, "re-filter-filenames", 1, s, 0);
    1397             :    }
    1398             :    else
    1399             :    {
    1400           0 :       if (!err) err = map(exports, "re-filter-filenames", 1, "<tr><td>None specified</td></tr>", 1);
    1401           0 :       if (!err) err = map_block_killer(exports, "have-filterfile");
    1402           0 :       freez(s);
    1403             :    }
    1404             : 
    1405             : #ifdef FEATURE_TRUST
    1406         500 :    if (csp->tlist)
    1407             :    {
    1408           0 :       if (!err) err = map(exports, "trust-filename", 1, html_encode(csp->tlist->filename), 0);
    1409             :    }
    1410             :    else
    1411             :    {
    1412         500 :       if (!err) err = map(exports, "trust-filename", 1, "None specified", 1);
    1413         500 :       if (!err) err = map_block_killer(exports, "have-trustfile");
    1414             :    }
    1415             : #else
    1416             :    if (!err) err = map_block_killer(exports, "trust-support");
    1417             : #endif /* ndef FEATURE_TRUST */
    1418             : 
    1419             : #ifdef FEATURE_CGI_EDIT_ACTIONS
    1420         500 :    if (!err && (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
    1421             :    {
    1422         500 :       err = map_block_killer(exports, "cgi-editor-is-disabled");
    1423             :    }
    1424             : #endif /* ndef CGI_EDIT_ACTIONS */
    1425             : 
    1426         500 :    if (!err) err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1);
    1427             : 
    1428         500 :    if (err)
    1429             :    {
    1430           0 :       free_map(exports);
    1431           0 :       return JB_ERR_MEMORY;
    1432             :    }
    1433             : 
    1434         500 :    return template_fill_for_cgi(csp, "show-status", exports, rsp);
    1435             : }
    1436             : 
    1437             : 
    1438             : /*********************************************************************
    1439             :  *
    1440             :  * Function    :  cgi_show_url_info
    1441             :  *
    1442             :  * Description :  CGI function that determines and shows which actions
    1443             :  *                Privoxy will perform for a given url, and which
    1444             :  *                matches starting from the defaults have lead to that.
    1445             :  *
    1446             :  * Parameters  :
    1447             :  *          1  :  csp = Current client state (buffers, headers, etc...)
    1448             :  *          2  :  rsp = http_response data structure for output
    1449             :  *          3  :  parameters = map of cgi parameters
    1450             :  *
    1451             :  * CGI Parameters :
    1452             :  *            url : The url whose actions are to be determined.
    1453             :  *                  If url is unset, the url-given conditional will be
    1454             :  *                  set, so that all but the form can be suppressed in
    1455             :  *                  the template.
    1456             :  *
    1457             :  * Returns     :  JB_ERR_OK on success
    1458             :  *                JB_ERR_MEMORY on out-of-memory error.
    1459             :  *
    1460             :  *********************************************************************/
    1461        1691 : jb_err cgi_show_url_info(struct client_state *csp,
    1462             :                          struct http_response *rsp,
    1463             :                          const struct map *parameters)
    1464             : {
    1465             :    char *url_param;
    1466             :    struct map *exports;
    1467             :    char buf[150];
    1468             : 
    1469        1691 :    assert(csp);
    1470        1691 :    assert(rsp);
    1471        1691 :    assert(parameters);
    1472             : 
    1473        1691 :    if (NULL == (exports = default_exports(csp, "show-url-info")))
    1474             :    {
    1475           0 :       return JB_ERR_MEMORY;
    1476             :    }
    1477             : 
    1478             :    /*
    1479             :     * Get the url= parameter (if present) and remove any leading/trailing spaces.
    1480             :     */
    1481        1691 :    url_param = strdup_or_die(lookup(parameters, "url"));
    1482        1691 :    chomp(url_param);
    1483             : 
    1484             :    /*
    1485             :     * Handle prefixes.  4 possibilities:
    1486             :     * 1) "http://" or "https://" prefix present and followed by URL - OK
    1487             :     * 2) Only the "http://" or "https://" part is present, no URL - change
    1488             :     *    to empty string so it will be detected later as "no URL".
    1489             :     * 3) Parameter specified but doesn't start with "http(s?)://" - add a
    1490             :     *    "http://" prefix.
    1491             :     * 4) Parameter not specified or is empty string - let this fall through
    1492             :     *    for now, next block of code will handle it.
    1493             :     */
    1494        1691 :    if (0 == strncmp(url_param, "http://", 7))
    1495             :    {
    1496          64 :       if (url_param[7] == '\0')
    1497             :       {
    1498             :          /*
    1499             :           * Empty URL (just prefix).
    1500             :           * Make it totally empty so it's caught by the next if ()
    1501             :           */
    1502          10 :          url_param[0] = '\0';
    1503             :       }
    1504             :    }
    1505        1627 :    else if (0 == strncmp(url_param, "https://", 8))
    1506             :    {
    1507          51 :       if (url_param[8] == '\0')
    1508             :       {
    1509             :          /*
    1510             :           * Empty URL (just prefix).
    1511             :           * Make it totally empty so it's caught by the next if ()
    1512             :           */
    1513           1 :          url_param[0] = '\0';
    1514             :       }
    1515             :    }
    1516        1576 :    else if ((url_param[0] != '\0')
    1517        1313 :       && ((NULL == strstr(url_param, "://")
    1518         105 :             || (strstr(url_param, "://") > strstr(url_param, "/")))))
    1519             :    {
    1520             :       /*
    1521             :        * No prefix or at least no prefix before
    1522             :        * the first slash - assume http://
    1523             :        */
    1524        1244 :       char *url_param_prefixed = strdup_or_die("http://");
    1525             : 
    1526        1244 :       if (JB_ERR_OK != string_join(&url_param_prefixed, url_param))
    1527             :       {
    1528           0 :          free_map(exports);
    1529           0 :          return JB_ERR_MEMORY;
    1530             :       }
    1531        1244 :       url_param = url_param_prefixed;
    1532             :    }
    1533             : 
    1534             :    /*
    1535             :     * Hide "toggle off" warning if Privoxy is toggled on.
    1536             :     */
    1537        1691 :    if (
    1538             : #ifdef FEATURE_TOGGLE
    1539        3344 :        (global_toggle_state == 1) &&
    1540             : #endif /* def FEATURE_TOGGLE */
    1541        1653 :        map_block_killer(exports, "privoxy-is-toggled-off")
    1542             :       )
    1543             :    {
    1544           0 :       freez(url_param);
    1545           0 :       free_map(exports);
    1546           0 :       return JB_ERR_MEMORY;
    1547             :    }
    1548             : 
    1549        1691 :    if (url_param[0] == '\0')
    1550             :    {
    1551             :       /* URL parameter not specified, display query form only. */
    1552         274 :       free(url_param);
    1553         274 :       if (map_block_killer(exports, "url-given")
    1554         274 :         || map(exports, "url", 1, "", 1))
    1555             :       {
    1556           0 :          free_map(exports);
    1557           0 :          return JB_ERR_MEMORY;
    1558             :       }
    1559             :    }
    1560             :    else
    1561             :    {
    1562             :       /* Given a URL, so query it. */
    1563             :       jb_err err;
    1564             :       char *matches;
    1565             :       char *s;
    1566        1417 :       int hits = 0;
    1567             :       struct file_list *fl;
    1568             :       struct url_actions *b;
    1569             :       struct http_request url_to_query[1];
    1570             :       struct current_action_spec action[1];
    1571             :       int i;
    1572             : 
    1573        1417 :       if (map(exports, "url", 1, html_encode(url_param), 0))
    1574             :       {
    1575           0 :          free(url_param);
    1576           0 :          free_map(exports);
    1577         156 :          return JB_ERR_MEMORY;
    1578             :       }
    1579             : 
    1580        1417 :       init_current_action(action);
    1581             : 
    1582        1417 :       if (map(exports, "default", 1, current_action_to_html(csp, action), 0))
    1583             :       {
    1584           0 :          free_current_action(action);
    1585           0 :          free(url_param);
    1586           0 :          free_map(exports);
    1587           0 :          return JB_ERR_MEMORY;
    1588             :       }
    1589             : 
    1590        1417 :       memset(url_to_query, '\0', sizeof(url_to_query));
    1591        1417 :       err = parse_http_url(url_param, url_to_query, REQUIRE_PROTOCOL);
    1592        1417 :       assert((err != JB_ERR_OK) || (url_to_query->ssl == !strncmpic(url_param, "https://", 8)));
    1593             : 
    1594        1417 :       free(url_param);
    1595             : 
    1596        1417 :       if (err == JB_ERR_MEMORY)
    1597             :       {
    1598           0 :          free_http_request(url_to_query);
    1599           0 :          free_current_action(action);
    1600           0 :          free_map(exports);
    1601           0 :          return JB_ERR_MEMORY;
    1602             :       }
    1603        1417 :       else if (err)
    1604             :       {
    1605             :          /* Invalid URL */
    1606             : 
    1607         156 :          err = map(exports, "matches", 1, "<b>[Invalid URL specified!]</b>" , 1);
    1608         156 :          if (!err) err = map(exports, "final", 1, lookup(exports, "default"), 1);
    1609         156 :          if (!err) err = map_block_killer(exports, "valid-url");
    1610             : 
    1611         156 :          free_current_action(action);
    1612         156 :          free_http_request(url_to_query);
    1613             : 
    1614         156 :          if (err)
    1615             :          {
    1616           0 :             free_map(exports);
    1617           0 :             return JB_ERR_MEMORY;
    1618             :          }
    1619             : 
    1620         156 :          return template_fill_for_cgi(csp, "show-url-info", exports, rsp);
    1621             :       }
    1622             : 
    1623             :       /*
    1624             :        * We have a warning about SSL paths. Hide it for unencrypted sites
    1625             :        * and unconditionally if https inspection is enabled.
    1626             :        */
    1627             : #ifndef FEATURE_HTTPS_INSPECTION
    1628             :       if (!url_to_query->ssl)
    1629             : #endif
    1630             :       {
    1631        1261 :          if (map_block_killer(exports, "https-and-no-https-inspection"))
    1632             :          {
    1633           0 :             free_current_action(action);
    1634           0 :             free_map(exports);
    1635           0 :             free_http_request(url_to_query);
    1636           0 :             return JB_ERR_MEMORY;
    1637             :          }
    1638             :       }
    1639             : 
    1640        1261 :       matches = strdup_or_die("<table summary=\"\" class=\"transparent\">");
    1641             : 
    1642      127361 :       for (i = 0; i < MAX_AF_FILES; i++)
    1643             :       {
    1644      126100 :          if (NULL == csp->config->actions_file_short[i]
    1645      126100 :              || !strcmp(csp->config->actions_file_short[i], "standard.action")) continue;
    1646             : 
    1647        2522 :          b = NULL;
    1648        2522 :          hits = 1;
    1649        2522 :          if ((fl = csp->actions_list[i]) != NULL)
    1650             :          {
    1651        2522 :             if ((b = fl->f) != NULL)
    1652             :             {
    1653             :                /* FIXME: Hardcoded HTML! */
    1654        2522 :                string_append(&matches, "<tr><th>In file: ");
    1655        2522 :                string_join  (&matches, html_encode(csp->config->actions_file_short[i]));
    1656        2522 :                snprintf(buf, sizeof(buf), " <a class=\"cmd\" href=\"/show-status?file=actions&amp;index=%d\">", i);
    1657        2522 :                string_append(&matches, buf);
    1658        2522 :                string_append(&matches, "View</a>");
    1659             : #ifdef FEATURE_CGI_EDIT_ACTIONS
    1660        2522 :                if (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)
    1661             :                {
    1662             : #ifdef HAVE_ACCESS
    1663        2522 :                   if (access(csp->config->actions_file[i], W_OK) == 0)
    1664             :                   {
    1665             : #endif /* def HAVE_ACCESS */
    1666        2522 :                      snprintf(buf, sizeof(buf),
    1667             :                         " <a class=\"cmd\" href=\"/edit-actions-list?f=%d\">", i);
    1668        2522 :                      string_append(&matches, buf);
    1669        2522 :                      string_append(&matches, "Edit</a>");
    1670             : #ifdef HAVE_ACCESS
    1671             :                   }
    1672             :                   else
    1673             :                   {
    1674           0 :                      string_append(&matches, " <strong>No write access.</strong>");
    1675             :                   }
    1676             : #endif /* def HAVE_ACCESS */
    1677             :                }
    1678             : #endif /* FEATURE_CGI_EDIT_ACTIONS */
    1679             : 
    1680        2522 :                string_append(&matches, "</th></tr>\n");
    1681             : 
    1682        2522 :                hits = 0;
    1683        2522 :                b = b->next;
    1684             :             }
    1685             :          }
    1686             : 
    1687       29003 :          for (; (b != NULL) && (matches != NULL); b = b->next)
    1688             :          {
    1689       26481 :             if (url_match(b->url, url_to_query))
    1690             :             {
    1691        2188 :                string_append(&matches, "<tr><td>{");
    1692        2188 :                string_join  (&matches, actions_to_html(csp, b->action));
    1693        2188 :                string_append(&matches, " }<br>\n<code>");
    1694        2188 :                string_join  (&matches, html_encode(b->url->spec));
    1695        2188 :                string_append(&matches, "</code></td></tr>\n");
    1696             : 
    1697        2188 :                if (merge_current_action(action, b->action))
    1698             :                {
    1699           0 :                   freez(matches);
    1700           0 :                   free_http_request(url_to_query);
    1701           0 :                   free_current_action(action);
    1702           0 :                   free_map(exports);
    1703           0 :                   return JB_ERR_MEMORY;
    1704             :                }
    1705        2188 :                hits++;
    1706             :             }
    1707             :          }
    1708             : 
    1709        2522 :          if (!hits)
    1710             :          {
    1711         766 :             string_append(&matches, "<tr><td>(no matches in this file)</td></tr>\n");
    1712             :          }
    1713             :       }
    1714        1261 :       string_append(&matches, "</table>\n");
    1715             : 
    1716             :       /*
    1717             :        * XXX: Kludge to make sure the "Forward settings" section
    1718             :        * shows what forward-override{} would do with the requested URL.
    1719             :        * No one really cares how the CGI request would be forwarded
    1720             :        * if it wasn't intercepted as CGI request in the first place.
    1721             :        *
    1722             :        * From here on the action bitmask will no longer reflect
    1723             :        * the real url (http://config.privoxy.org/show-url-info?url=.*),
    1724             :        * but luckily it's no longer required later on anyway.
    1725             :        */
    1726        1261 :       free_current_action(csp->action);
    1727        1261 :       get_url_actions(csp, url_to_query);
    1728             : 
    1729             :       /*
    1730             :        * Fill in forwarding settings.
    1731             :        *
    1732             :        * The possibilities are:
    1733             :        *  - no forwarding
    1734             :        *  - http forwarding only
    1735             :        *  - socks4(a) forwarding only
    1736             :        *  - socks4(a) and http forwarding.
    1737             :        *
    1738             :        * XXX: Parts of this code could be reused for the
    1739             :        * "forwarding-failed" template which currently doesn't
    1740             :        * display the proxy port and an eventual second forwarder.
    1741             :        */
    1742             :       {
    1743        1261 :          const struct forward_spec *fwd = forward_url(csp, url_to_query);
    1744             : 
    1745        1261 :          if ((fwd->gateway_host == NULL) && (fwd->forward_host == NULL))
    1746             :          {
    1747        1261 :             if (!err) err = map_block_killer(exports, "socks-forwarder");
    1748        1261 :             if (!err) err = map_block_killer(exports, "http-forwarder");
    1749             :          }
    1750             :          else
    1751             :          {
    1752             :             char port[10]; /* We save proxy ports as int but need a string here */
    1753             : 
    1754           0 :             if (!err) err = map_block_killer(exports, "no-forwarder");
    1755             : 
    1756           0 :             if (fwd->gateway_host != NULL)
    1757             :             {
    1758           0 :                char *socks_type = NULL;
    1759             : 
    1760           0 :                switch (fwd->type)
    1761             :                {
    1762           0 :                   case SOCKS_4:
    1763           0 :                      socks_type = "socks4";
    1764           0 :                      break;
    1765           0 :                   case SOCKS_4A:
    1766           0 :                      socks_type = "socks4a";
    1767           0 :                      break;
    1768           0 :                   case SOCKS_5:
    1769           0 :                      socks_type = "socks5";
    1770           0 :                      break;
    1771           0 :                   case SOCKS_5T:
    1772           0 :                      socks_type = "socks5t";
    1773           0 :                      break;
    1774           0 :                   default:
    1775           0 :                      log_error(LOG_LEVEL_FATAL, "Unknown socks type: %d.", fwd->type);
    1776             :                }
    1777             : 
    1778           0 :                if (!err) err = map(exports, "socks-type", 1, socks_type, 1);
    1779           0 :                if (!err) err = map(exports, "gateway-host", 1, fwd->gateway_host, 1);
    1780           0 :                snprintf(port, sizeof(port), "%d", fwd->gateway_port);
    1781           0 :                if (!err) err = map(exports, "gateway-port", 1, port, 1);
    1782             :             }
    1783             :             else
    1784             :             {
    1785           0 :                if (!err) err = map_block_killer(exports, "socks-forwarder");
    1786             :             }
    1787             : 
    1788           0 :             if (fwd->forward_host != NULL)
    1789             :             {
    1790           0 :                if (!err) err = map(exports, "forward-host", 1, fwd->forward_host, 1);
    1791           0 :                snprintf(port, sizeof(port), "%d", fwd->forward_port);
    1792           0 :                if (!err) err = map(exports, "forward-port", 1, port, 1);
    1793             :             }
    1794             :             else
    1795             :             {
    1796           0 :                if (!err) err = map_block_killer(exports, "http-forwarder");
    1797             :             }
    1798             :          }
    1799             :       }
    1800             : 
    1801        1261 :       free_http_request(url_to_query);
    1802             : 
    1803        1261 :       if (err || matches == NULL)
    1804             :       {
    1805           0 :          free_current_action(action);
    1806           0 :          free_map(exports);
    1807           0 :          return JB_ERR_MEMORY;
    1808             :       }
    1809             : 
    1810             : #ifdef FEATURE_CGI_EDIT_ACTIONS
    1811        1261 :       if ((csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
    1812             :       {
    1813        1261 :          err = map_block_killer(exports, "cgi-editor-is-disabled");
    1814             :       }
    1815             : #endif /* FEATURE_CGI_EDIT_ACTIONS */
    1816             : 
    1817             :       /*
    1818             :        * If zlib support is available, if no content filters
    1819             :        * are enabled or if the prevent-compression action is enabled,
    1820             :        * suppress the "compression could prevent filtering" warning.
    1821             :        */
    1822             : #ifndef FEATURE_ZLIB
    1823             :       if (!content_filters_enabled(action) ||
    1824             :          (action->flags & ACTION_NO_COMPRESSION))
    1825             : #endif
    1826             :       {
    1827        1261 :          if (!err) err = map_block_killer(exports, "filters-might-be-ineffective");
    1828             :       }
    1829             : 
    1830        1261 :       if (err || map(exports, "matches", 1, matches , 0))
    1831             :       {
    1832           0 :          free_current_action(action);
    1833           0 :          free_map(exports);
    1834           0 :          return JB_ERR_MEMORY;
    1835             :       }
    1836             : 
    1837        1261 :       s = current_action_to_html(csp, action);
    1838             : 
    1839        1261 :       free_current_action(action);
    1840             : 
    1841        1261 :       if (map(exports, "final", 1, s, 0))
    1842             :       {
    1843           0 :          free_map(exports);
    1844           0 :          return JB_ERR_MEMORY;
    1845             :       }
    1846             :    }
    1847             : 
    1848        1535 :    return template_fill_for_cgi(csp, "show-url-info", exports, rsp);
    1849             : }
    1850             : 
    1851             : 
    1852             : /*********************************************************************
    1853             :  *
    1854             :  * Function    :  cgi_robots_txt
    1855             :  *
    1856             :  * Description :  CGI function to return "/robots.txt".
    1857             :  *
    1858             :  * Parameters  :
    1859             :  *          1  :  csp = Current client state (buffers, headers, etc...)
    1860             :  *          2  :  rsp = http_response data structure for output
    1861             :  *          3  :  parameters = map of cgi parameters
    1862             :  *
    1863             :  * CGI Parameters : None
    1864             :  *
    1865             :  * Returns     :  JB_ERR_OK on success
    1866             :  *                JB_ERR_MEMORY on out-of-memory error.
    1867             :  *
    1868             :  *********************************************************************/
    1869          74 : jb_err cgi_robots_txt(struct client_state *csp,
    1870             :                       struct http_response *rsp,
    1871             :                       const struct map *parameters)
    1872             : {
    1873             :    char buf[100];
    1874             :    jb_err err;
    1875             : 
    1876             :    (void)csp;
    1877             :    (void)parameters;
    1878             : 
    1879          74 :    rsp->body = strdup_or_die(
    1880             :       "# This is the Privoxy control interface.\n"
    1881             :       "# It isn't very useful to index it, and you're likely to break stuff.\n"
    1882             :       "# So go away!\n"
    1883             :       "\n"
    1884             :       "User-agent: *\n"
    1885             :       "Disallow: /\n"
    1886             :       "\n");
    1887             : 
    1888          74 :    err = enlist_unique(rsp->headers, "Content-Type: text/plain", 13);
    1889             : 
    1890          74 :    rsp->is_static = 1;
    1891             : 
    1892          74 :    get_http_time(7 * 24 * 60 * 60, buf, sizeof(buf)); /* 7 days into future */
    1893          74 :    if (!err) err = enlist_unique_header(rsp->headers, "Expires", buf);
    1894             : 
    1895          74 :    return (err ? JB_ERR_MEMORY : JB_ERR_OK);
    1896             : }
    1897             : 
    1898             : 
    1899             : /*********************************************************************
    1900             :  *
    1901             :  * Function    :  show_defines
    1902             :  *
    1903             :  * Description :  Add to a map the state of all conditional #defines
    1904             :  *                used when building
    1905             :  *
    1906             :  * Parameters  :
    1907             :  *          1  :  exports = map to extend
    1908             :  *
    1909             :  * Returns     :  JB_ERR_OK on success
    1910             :  *                JB_ERR_MEMORY on out-of-memory error.
    1911             :  *
    1912             :  *********************************************************************/
    1913         500 : static jb_err show_defines(struct map *exports)
    1914             : {
    1915         500 :    jb_err err = JB_ERR_OK;
    1916             :    int i;
    1917             :    struct feature {
    1918             :       const char name[31];
    1919             :       const unsigned char is_available;
    1920             :    };
    1921             : 
    1922             :    static const struct feature features[] = {
    1923             :       {
    1924             :          "FEATURE_64_BIT_TIME_T",
    1925             : #if (SIZEOF_TIME_T == 8)
    1926             :          1,
    1927             : #else
    1928             :          0,
    1929             : #endif
    1930             :       },
    1931             :       {
    1932             :          "FEATURE_ACCEPT_FILTER",
    1933             : #ifdef FEATURE_ACCEPT_FILTER
    1934             :          1,
    1935             : #else
    1936             :          0,
    1937             : #endif
    1938             :       },
    1939             :       {
    1940             :          "FEATURE_ACL",
    1941             : #ifdef FEATURE_ACL
    1942             :          1,
    1943             : #else
    1944             :          0,
    1945             : #endif
    1946             :       },
    1947             :       {
    1948             :          "FEATURE_BROTLI",
    1949             : #ifdef FEATURE_BROTLI
    1950             :          1,
    1951             : #else
    1952             :          0,
    1953             : #endif
    1954             :       },
    1955             :       {
    1956             :          "FEATURE_CGI_EDIT_ACTIONS",
    1957             : #ifdef FEATURE_CGI_EDIT_ACTIONS
    1958             :          1,
    1959             : #else
    1960             :          0,
    1961             : #endif
    1962             :       },
    1963             :       {
    1964             :          "FEATURE_CLIENT_TAGS",
    1965             : #ifdef FEATURE_CLIENT_TAGS
    1966             :          1,
    1967             : #else
    1968             :          0,
    1969             : #endif
    1970             :       },
    1971             :       {
    1972             :          "FEATURE_COMPRESSION",
    1973             : #ifdef FEATURE_COMPRESSION
    1974             :          1,
    1975             : #else
    1976             :          0,
    1977             : #endif
    1978             :       },
    1979             :       {
    1980             :          "FEATURE_CONNECTION_KEEP_ALIVE",
    1981             : #ifdef FEATURE_CONNECTION_KEEP_ALIVE
    1982             :          1,
    1983             : #else
    1984             :          0,
    1985             : #endif
    1986             :       },
    1987             :       {
    1988             :          "FEATURE_CONNECTION_SHARING",
    1989             : #ifdef FEATURE_CONNECTION_SHARING
    1990             :          1,
    1991             : #else
    1992             :          0,
    1993             : #endif
    1994             :       },
    1995             :       {
    1996             :          "FEATURE_EXTERNAL_FILTERS",
    1997             : #ifdef FEATURE_EXTERNAL_FILTERS
    1998             :          1,
    1999             : #else
    2000             :          0,
    2001             : #endif
    2002             :       },
    2003             :       {
    2004             :          "FEATURE_FAST_REDIRECTS",
    2005             : #ifdef FEATURE_FAST_REDIRECTS
    2006             :          1,
    2007             : #else
    2008             :          0,
    2009             : #endif
    2010             :       },
    2011             :       {
    2012             :          "FEATURE_FORCE_LOAD",
    2013             : #ifdef FEATURE_FORCE_LOAD
    2014             :          1,
    2015             : #else
    2016             :          0,
    2017             : #endif
    2018             :       },
    2019             :       {
    2020             :          "FEATURE_GRACEFUL_TERMINATION",
    2021             : #ifdef FEATURE_GRACEFUL_TERMINATION
    2022             :          1,
    2023             : #else
    2024             :          0,
    2025             : #endif
    2026             :       },
    2027             :       {
    2028             :          "FEATURE_HTTPS_INSPECTION",
    2029             : #ifdef FEATURE_HTTPS_INSPECTION
    2030             :          1,
    2031             : #else
    2032             :          0,
    2033             : #endif
    2034             :       },
    2035             :       {
    2036             :          "FEATURE_IMAGE_BLOCKING",
    2037             : #ifdef FEATURE_IMAGE_BLOCKING
    2038             :          1,
    2039             : #else
    2040             :          0,
    2041             : #endif
    2042             :       },
    2043             :       {
    2044             :          "FEATURE_IPV6_SUPPORT",
    2045             : #ifdef HAVE_RFC2553
    2046             :          1,
    2047             : #else
    2048             :          0,
    2049             : #endif
    2050             :       },
    2051             :       {
    2052             :          "FEATURE_NO_GIFS",
    2053             : #ifdef FEATURE_NO_GIFS
    2054             :          1,
    2055             : #else
    2056             :          0,
    2057             : #endif
    2058             :       },
    2059             :       {
    2060             :          "FEATURE_PTHREAD",
    2061             : #ifdef FEATURE_PTHREAD
    2062             :          1,
    2063             : #else
    2064             :          0,
    2065             : #endif
    2066             :       },
    2067             :       {
    2068             :          "FEATURE_STATISTICS",
    2069             : #ifdef FEATURE_STATISTICS
    2070             :          1,
    2071             : #else
    2072             :          0,
    2073             : #endif
    2074             :       },
    2075             :       {
    2076             :          "FEATURE_STRPTIME_SANITY_CHECKS",
    2077             : #ifdef FEATURE_STRPTIME_SANITY_CHECKS
    2078             :          1,
    2079             : #else
    2080             :          0,
    2081             : #endif
    2082             :       },
    2083             :       {
    2084             :          "FEATURE_TOGGLE",
    2085             : #ifdef FEATURE_TOGGLE
    2086             :          1,
    2087             : #else
    2088             :          0,
    2089             : #endif
    2090             :       },
    2091             :       {
    2092             :          "FEATURE_TRUST",
    2093             : #ifdef FEATURE_TRUST
    2094             :          1,
    2095             : #else
    2096             :          0,
    2097             : #endif
    2098             :       },
    2099             :       {
    2100             :          "FEATURE_ZLIB",
    2101             : #ifdef FEATURE_ZLIB
    2102             :          1,
    2103             : #else
    2104             :          0,
    2105             : #endif
    2106             :       },
    2107             :       {
    2108             :          "FEATURE_DYNAMIC_PCRE",
    2109             : #ifdef FEATURE_DYNAMIC_PCRE
    2110             :          1,
    2111             : #else
    2112             :          0,
    2113             : #endif
    2114             :       },
    2115             :       {
    2116             :          "FEATURE_EXTENDED_STATISTICS",
    2117             : #ifdef FEATURE_EXTENDED_STATISTICS
    2118             :          1,
    2119             : #else
    2120             :          0,
    2121             : #endif
    2122             :       },
    2123             :       {
    2124             :          "FEATURE_PCRE_HOST_PATTERNS",
    2125             : #ifdef FEATURE_PCRE_HOST_PATTERNS
    2126             :          1,
    2127             : #else
    2128             :          0,
    2129             : #endif
    2130             :       }
    2131             :    };
    2132             : 
    2133       13500 :    for (i = 0; i < SZ(features); i++)
    2134             :    {
    2135       13000 :       err = map_conditional(exports, features[i].name, features[i].is_available);
    2136       13000 :       if (err)
    2137             :       {
    2138           0 :          break;
    2139             :       }
    2140             :    }
    2141             : 
    2142         500 :    return err;
    2143             : 
    2144             : }
    2145             : 
    2146             : 
    2147             : /*********************************************************************
    2148             :  *
    2149             :  * Function    :  cgi_show_file
    2150             :  *
    2151             :  * Description :  CGI function that shows the content of a
    2152             :  *                configuration file.
    2153             :  *
    2154             :  * Parameters  :
    2155             :  *          1  :  csp = Current client state (buffers, headers, etc...)
    2156             :  *          2  :  rsp = http_response data structure for output
    2157             :  *          3  :  parameters = map of cgi parameters
    2158             :  *
    2159             :  * CGI Parameters :
    2160             :  *        file :  Which file to show.  Only first letter is checked,
    2161             :  *                valid values are:
    2162             :  *                - "a"ction file
    2163             :  *                - "r"egex
    2164             :  *                - "t"rust
    2165             :  *                Default is to show menu and other information.
    2166             :  *
    2167             :  * Returns     :  JB_ERR_OK on success
    2168             :  *                JB_ERR_MEMORY on out-of-memory error.
    2169             :  *
    2170             :  *********************************************************************/
    2171         448 : static jb_err cgi_show_file(struct client_state *csp,
    2172             :                             struct http_response *rsp,
    2173             :                             const struct map *parameters)
    2174             : {
    2175             :    unsigned i;
    2176         448 :    const char * filename = NULL;
    2177         448 :    char * file_description = NULL;
    2178             : 
    2179         448 :    assert(csp);
    2180         448 :    assert(rsp);
    2181         448 :    assert(parameters);
    2182             : 
    2183         448 :    switch (*(lookup(parameters, "file")))
    2184             :    {
    2185         169 :    case 'a':
    2186         169 :       if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->actions_list[i])
    2187             :       {
    2188          44 :          filename = csp->actions_list[i]->filename;
    2189          44 :          file_description = "Actions File";
    2190             :       }
    2191         169 :       break;
    2192             : 
    2193         172 :    case 'f':
    2194         172 :       if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->rlist[i])
    2195             :       {
    2196          51 :          filename = csp->rlist[i]->filename;
    2197          51 :          file_description = "Filter File";
    2198             :       }
    2199         172 :       break;
    2200             : 
    2201             : #ifdef FEATURE_TRUST
    2202          65 :    case 't':
    2203          65 :       if (csp->tlist)
    2204             :       {
    2205           0 :          filename = csp->tlist->filename;
    2206           0 :          file_description = "Trust File";
    2207             :       }
    2208          65 :       break;
    2209             : #endif /* def FEATURE_TRUST */
    2210             :    }
    2211             : 
    2212         448 :    if (NULL != filename)
    2213             :    {
    2214             :       struct map *exports;
    2215             :       char *s;
    2216             :       jb_err err;
    2217             :       size_t length;
    2218             : 
    2219          95 :       exports = default_exports(csp, "show-status");
    2220          95 :       if (NULL == exports)
    2221             :       {
    2222           0 :          return JB_ERR_MEMORY;
    2223             :       }
    2224             : 
    2225          95 :       if (map(exports, "file-description", 1, file_description, 1)
    2226          95 :         || map(exports, "filepath", 1, html_encode(filename), 0))
    2227             :       {
    2228           0 :          free_map(exports);
    2229           0 :          return JB_ERR_MEMORY;
    2230             :       }
    2231             : 
    2232          95 :       err = load_file(filename, &s, &length);
    2233          95 :       if (JB_ERR_OK != err)
    2234             :       {
    2235           0 :          if (map(exports, "contents", 1, "<h1>ERROR OPENING FILE!</h1>", 1))
    2236             :          {
    2237           0 :             free_map(exports);
    2238           0 :             return JB_ERR_MEMORY;
    2239             :          }
    2240             :       }
    2241             :       else
    2242             :       {
    2243          95 :          s = html_encode_and_free_original(s);
    2244          95 :          if (NULL == s)
    2245             :          {
    2246           0 :             free_map(exports);
    2247           0 :             return JB_ERR_MEMORY;
    2248             :          }
    2249             : 
    2250          95 :          if (map(exports, "contents", 1, s, 0))
    2251             :          {
    2252           0 :             free_map(exports);
    2253           0 :             return JB_ERR_MEMORY;
    2254             :          }
    2255             :       }
    2256             : 
    2257          95 :       return template_fill_for_cgi(csp, "show-status-file", exports, rsp);
    2258             :    }
    2259             : 
    2260         353 :    return JB_ERR_CGI_PARAMS;
    2261             : }
    2262             : 
    2263             : 
    2264             : /*********************************************************************
    2265             :  *
    2266             :  * Function    :  load_file
    2267             :  *
    2268             :  * Description :  Loads a file into a buffer.
    2269             :  *
    2270             :  * Parameters  :
    2271             :  *          1  :  filename = Name of the file to be loaded.
    2272             :  *          2  :  buffer   = Used to return the file's content.
    2273             :  *          3  :  length   = Used to return the size of the file.
    2274             :  *
    2275             :  * Returns     :  JB_ERR_OK in case of success,
    2276             :  *                JB_ERR_FILE in case of ordinary file loading errors
    2277             :  *                            (fseek() and ftell() errors are fatal)
    2278             :  *                JB_ERR_MEMORY in case of out-of-memory.
    2279             :  *
    2280             :  *********************************************************************/
    2281         430 : static jb_err load_file(const char *filename, char **buffer, size_t *length)
    2282             : {
    2283             :    FILE *fp;
    2284             :    long ret;
    2285         430 :    jb_err err = JB_ERR_OK;
    2286             : 
    2287         430 :    fp = fopen(filename, "rb");
    2288         430 :    if (NULL == fp)
    2289             :    {
    2290         335 :       log_error(LOG_LEVEL_ERROR, "Failed to open %s: %E", filename);
    2291         335 :       return JB_ERR_FILE;
    2292             :    }
    2293             : 
    2294             :    /* Get file length */
    2295          95 :    if (fseek(fp, 0, SEEK_END))
    2296             :    {
    2297           0 :       log_error(LOG_LEVEL_FATAL,
    2298             :          "Unexpected error while fseek()ing to the end of %s: %E",
    2299             :          filename);
    2300             :    }
    2301          95 :    ret = ftell(fp);
    2302          95 :    if (-1 == ret)
    2303             :    {
    2304           0 :       log_error(LOG_LEVEL_FATAL,
    2305             :          "Unexpected ftell() error while loading %s: %E",
    2306             :          filename);
    2307             :    }
    2308          95 :    *length = (size_t)ret;
    2309             : 
    2310             :    /* Go back to the beginning. */
    2311          95 :    if (fseek(fp, 0, SEEK_SET))
    2312             :    {
    2313           0 :       log_error(LOG_LEVEL_FATAL,
    2314             :          "Unexpected error while fseek()ing to the beginning of %s: %E",
    2315             :          filename);
    2316             :    }
    2317             : 
    2318          95 :    *buffer = zalloc_or_die(*length + 1);
    2319             : 
    2320          95 :    if (1 != fread(*buffer, *length, 1, fp))
    2321             :    {
    2322             :       /*
    2323             :        * May theoretically happen if the file size changes between
    2324             :        * fseek() and fread() because it's edited in-place. Privoxy
    2325             :        * and common text editors don't do that, thus we just fail.
    2326             :        */
    2327           0 :       log_error(LOG_LEVEL_ERROR,
    2328             :          "Couldn't completely read file %s.", filename);
    2329           0 :       freez(*buffer);
    2330           0 :       err = JB_ERR_FILE;
    2331             :    }
    2332             : 
    2333          95 :    fclose(fp);
    2334             : 
    2335          95 :    return err;
    2336             : 
    2337             : }
    2338             : 
    2339             : 
    2340             : /*
    2341             :   Local Variables:
    2342             :   tab-width: 3
    2343             :   end:
    2344             : */

Generated by: LCOV version 1.14