Merge branch 'master' of ssh://git.privoxy.org:23/git/privoxy
[privoxy.git] / filters.c
1 /*********************************************************************
2  *
3  * File        :  $Source: /cvsroot/ijbswa/current/filters.c,v $
4  *
5  * Purpose     :  Declares functions to parse/crunch headers and pages.
6  *
7  * Copyright   :  Written by and Copyright (C) 2001-2020 the
8  *                Privoxy team. https://www.privoxy.org/
9  *
10  *                Based on the Internet Junkbuster originally written
11  *                by and Copyright (C) 1997 Anonymous Coders and
12  *                Junkbusters Corporation.  http://www.junkbusters.com
13  *
14  *                This program is free software; you can redistribute it
15  *                and/or modify it under the terms of the GNU General
16  *                Public License as published by the Free Software
17  *                Foundation; either version 2 of the License, or (at
18  *                your option) any later version.
19  *
20  *                This program is distributed in the hope that it will
21  *                be useful, but WITHOUT ANY WARRANTY; without even the
22  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
23  *                PARTICULAR PURPOSE.  See the GNU General Public
24  *                License for more details.
25  *
26  *                The GNU General Public License should be included with
27  *                this file.  If not, you can view it at
28  *                http://www.gnu.org/copyleft/gpl.html
29  *                or write to the Free Software Foundation, Inc., 59
30  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
31  *
32  *********************************************************************/
33
34
35 #include "config.h"
36
37 #include <stdio.h>
38 #include <sys/types.h>
39 #include <stdlib.h>
40 #include <ctype.h>
41 #include <string.h>
42 #include <assert.h>
43
44 #ifndef _WIN32
45 #include <unistd.h>
46 #include <netinet/in.h>
47 #else
48 #include <winsock2.h>
49 #endif /* ndef _WIN32 */
50
51 #include "project.h"
52 #include "filters.h"
53 #include "encode.h"
54 #include "parsers.h"
55 #include "ssplit.h"
56 #include "errlog.h"
57 #include "jbsockets.h"
58 #include "miscutil.h"
59 #include "actions.h"
60 #include "cgi.h"
61 #include "jcc.h"
62 #include "list.h"
63 #include "deanimate.h"
64 #include "urlmatch.h"
65 #include "loaders.h"
66 #ifdef FEATURE_CLIENT_TAGS
67 #include "client-tags.h"
68 #endif
69
70 #ifdef _WIN32
71 #include "win32.h"
72 #endif
73
74 typedef char *(*filter_function_ptr)();
75 static filter_function_ptr get_filter_function(const struct client_state *csp);
76 static jb_err prepare_for_filtering(struct client_state *csp);
77 static void apply_url_actions(struct current_action_spec *action,
78                               struct http_request *http,
79 #ifdef FEATURE_CLIENT_TAGS
80                               const struct list *client_tags,
81 #endif
82                               struct url_actions *b);
83
84 #ifdef FEATURE_EXTENDED_STATISTICS
85 static void increment_block_reason_counter(const char *block_reason);
86 #endif
87
88 #ifdef FEATURE_ACL
89 #ifdef HAVE_RFC2553
90 /*********************************************************************
91  *
92  * Function    :  sockaddr_storage_to_ip
93  *
94  * Description :  Access internal structure of sockaddr_storage
95  *
96  * Parameters  :
97  *          1  :  addr = socket address
98  *          2  :  ip   = IP address as array of octets in network order
99  *                       (it points into addr)
100  *          3  :  len  = length of IP address in octets
101  *          4  :  port = port number in network order;
102  *
103  * Returns     :  void
104  *
105  *********************************************************************/
106 static void sockaddr_storage_to_ip(const struct sockaddr_storage *addr,
107                                    uint8_t **ip, unsigned int *len,
108                                    in_port_t **port)
109 {
110    assert(NULL != addr);
111    assert(addr->ss_family == AF_INET || addr->ss_family == AF_INET6);
112
113    switch (addr->ss_family)
114    {
115       case AF_INET:
116          if (NULL != len)
117          {
118             *len = 4;
119          }
120          if (NULL != ip)
121          {
122             *ip = (uint8_t *)
123                &(((struct sockaddr_in *)addr)->sin_addr.s_addr);
124          }
125          if (NULL != port)
126          {
127             *port = &((struct sockaddr_in *)addr)->sin_port;
128          }
129          break;
130
131       case AF_INET6:
132          if (NULL != len)
133          {
134             *len = 16;
135          }
136          if (NULL != ip)
137          {
138             *ip = ((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr;
139          }
140          if (NULL != port)
141          {
142             *port = &((struct sockaddr_in6 *)addr)->sin6_port;
143          }
144          break;
145
146    }
147 }
148
149
150 /*********************************************************************
151  *
152  * Function    :  match_sockaddr
153  *
154  * Description :  Check whether address matches network (IP address and port)
155  *
156  * Parameters  :
157  *          1  :  network = socket address of subnework
158  *          2  :  netmask = network mask as socket address
159  *          3  :  address = checked socket address against given network
160  *
161  * Returns     :  0 = doesn't match; 1 = does match
162  *
163  *********************************************************************/
164 static int match_sockaddr(const struct sockaddr_storage *network,
165                           const struct sockaddr_storage *netmask,
166                           const struct sockaddr_storage *address)
167 {
168    uint8_t *network_addr, *netmask_addr, *address_addr;
169    unsigned int addr_len;
170    in_port_t *network_port, *netmask_port, *address_port;
171    int i;
172
173    if (network->ss_family != netmask->ss_family)
174    {
175       /* This should never happen */
176       assert(network->ss_family == netmask->ss_family);
177       log_error(LOG_LEVEL_FATAL, "Network and netmask differ in family.");
178    }
179
180    sockaddr_storage_to_ip(network, &network_addr, &addr_len, &network_port);
181    sockaddr_storage_to_ip(netmask, &netmask_addr, NULL, &netmask_port);
182    sockaddr_storage_to_ip(address, &address_addr, NULL, &address_port);
183
184    /* Check for family */
185    if ((network->ss_family == AF_INET) && (address->ss_family == AF_INET6)
186       && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)address_addr))
187    {
188       /* Map AF_INET6 V4MAPPED address into AF_INET */
189       address_addr += 12;
190       addr_len = 4;
191    }
192    else if ((network->ss_family == AF_INET6) && (address->ss_family == AF_INET)
193       && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)network_addr))
194    {
195       /* Map AF_INET6 V4MAPPED network into AF_INET */
196       network_addr += 12;
197       netmask_addr += 12;
198       addr_len = 4;
199    }
200
201    /* XXX: Port check is signaled in netmask */
202    if (*netmask_port && *network_port != *address_port)
203    {
204       return 0;
205    }
206
207    /* TODO: Optimize by checking by words instead of octets */
208    for (i = 0; (i < addr_len) && netmask_addr[i]; i++)
209    {
210       if ((network_addr[i] & netmask_addr[i]) !=
211           (address_addr[i] & netmask_addr[i]))
212       {
213          return 0;
214       }
215    }
216
217    return 1;
218 }
219 #endif /* def HAVE_RFC2553 */
220
221
222 /*********************************************************************
223  *
224  * Function    :  block_acl
225  *
226  * Description :  Block this request?
227  *                Decide yes or no based on ACL file.
228  *
229  * Parameters  :
230  *          1  :  dst = The proxy or gateway address this is going to.
231  *                      Or NULL to check all possible targets.
232  *          2  :  csp = Current client state (buffers, headers, etc...)
233  *                      Also includes the client IP address.
234  *
235  * Returns     : 0 = FALSE (don't block) and 1 = TRUE (do block)
236  *
237  *********************************************************************/
238 int block_acl(const struct access_control_addr *dst, const struct client_state *csp)
239 {
240    struct access_control_list *acl = csp->config->acl;
241
242    /* if not using an access control list, then permit the connection */
243    if (acl == NULL)
244    {
245       return(0);
246    }
247
248    /* search the list */
249    while (acl != NULL)
250    {
251       if (
252 #ifdef HAVE_RFC2553
253             match_sockaddr(&acl->src->addr, &acl->src->mask, &csp->tcp_addr)
254 #else
255             (csp->ip_addr_long & acl->src->mask) == acl->src->addr
256 #endif
257             )
258       {
259          if (dst == NULL)
260          {
261             /* Just want to check if they have any access */
262             if (acl->action == ACL_PERMIT)
263             {
264                return(0);
265             }
266             else
267             {
268                return(1);
269             }
270          }
271          else if (
272 #ifdef HAVE_RFC2553
273                /*
274                 * XXX: An undefined acl->dst is full of zeros and should be
275                 * considered a wildcard address. sockaddr_storage_to_ip()
276                 * fails on such destinations because of unknown sa_familly
277                 * (glibc only?). However this test is not portable.
278                 *
279                 * So, we signal the acl->dst is wildcard in wildcard_dst.
280                 */
281                acl->wildcard_dst ||
282                   match_sockaddr(&acl->dst->addr, &acl->dst->mask, &dst->addr)
283 #else
284                ((dst->addr & acl->dst->mask) == acl->dst->addr)
285            && ((dst->port == acl->dst->port) || (acl->dst->port == 0))
286 #endif
287            )
288          {
289             if (acl->action == ACL_PERMIT)
290             {
291                return(0);
292             }
293             else
294             {
295                return(1);
296             }
297          }
298       }
299       acl = acl->next;
300    }
301
302    return(1);
303
304 }
305
306
307 /*********************************************************************
308  *
309  * Function    :  acl_addr
310  *
311  * Description :  Called from `load_config' to parse an ACL address.
312  *
313  * Parameters  :
314  *          1  :  aspec = String specifying ACL address.
315  *          2  :  aca = struct access_control_addr to fill in.
316  *
317  * Returns     :  0 => Ok, everything else is an error.
318  *
319  *********************************************************************/
320 int acl_addr(const char *aspec, struct access_control_addr *aca)
321 {
322    int i, masklength;
323 #ifdef HAVE_RFC2553
324    struct addrinfo hints, *result;
325    uint8_t *mask_data;
326    in_port_t *mask_port;
327    unsigned int addr_len;
328 #else
329    long port;
330 #endif /* def HAVE_RFC2553 */
331    char *p;
332    char *acl_spec = NULL;
333
334 #ifdef HAVE_RFC2553
335    /* XXX: Depend on ai_family */
336    masklength = 128;
337 #else
338    masklength = 32;
339    port       =  0;
340 #endif
341
342    /*
343     * Use a temporary acl spec copy so we can log
344     * the unmodified original in case of parse errors.
345     */
346    acl_spec = strdup_or_die(aspec);
347
348    if ((p = strchr(acl_spec, '/')) != NULL)
349    {
350       *p++ = '\0';
351       if (privoxy_isdigit(*p) == 0)
352       {
353          freez(acl_spec);
354          return(-1);
355       }
356       masklength = atoi(p);
357    }
358
359    if ((masklength < 0) ||
360 #ifdef HAVE_RFC2553
361          (masklength > 128)
362 #else
363          (masklength > 32)
364 #endif
365          )
366    {
367       freez(acl_spec);
368       return(-1);
369    }
370
371    if ((*acl_spec == '[') && (NULL != (p = strchr(acl_spec, ']'))))
372    {
373       *p = '\0';
374       memmove(acl_spec, acl_spec + 1, (size_t)(p - acl_spec));
375
376       if (*++p != ':')
377       {
378          p = NULL;
379       }
380    }
381    else
382    {
383       p = strchr(acl_spec, ':');
384    }
385    if (p != NULL)
386    {
387       assert(*p == ':');
388       *p = '\0';
389       p++;
390    }
391
392 #ifdef HAVE_RFC2553
393    memset(&hints, 0, sizeof(struct addrinfo));
394    hints.ai_family = AF_UNSPEC;
395    hints.ai_socktype = SOCK_STREAM;
396
397    i = getaddrinfo(acl_spec, p, &hints, &result);
398
399    if (i != 0)
400    {
401       log_error(LOG_LEVEL_ERROR, "Can not resolve [%s]:%s: %s",
402          acl_spec, p, gai_strerror(i));
403       freez(acl_spec);
404       return(-1);
405    }
406    freez(acl_spec);
407
408    /* TODO: Allow multihomed hostnames */
409    memcpy(&(aca->addr), result->ai_addr, result->ai_addrlen);
410    freeaddrinfo(result);
411 #else
412    if (p != NULL)
413    {
414       char *endptr;
415
416       port = strtol(p, &endptr, 10);
417
418       if (port <= 0 || port > 65535 || *endptr != '\0')
419       {
420          freez(acl_spec);
421          return(-1);
422       }
423    }
424
425    aca->port = (unsigned long)port;
426
427    aca->addr = ntohl(resolve_hostname_to_ip(acl_spec));
428    freez(acl_spec);
429
430    if (aca->addr == INADDR_NONE)
431    {
432       /* XXX: This will be logged as parse error. */
433       return(-1);
434    }
435 #endif /* def HAVE_RFC2553 */
436
437    /* build the netmask */
438 #ifdef HAVE_RFC2553
439    /* Clip masklength according to current family. */
440    if ((aca->addr.ss_family == AF_INET) && (masklength > 32))
441    {
442       masklength = 32;
443    }
444
445    aca->mask.ss_family = aca->addr.ss_family;
446    sockaddr_storage_to_ip(&aca->mask, &mask_data, &addr_len, &mask_port);
447
448    if (p)
449    {
450       /* ACL contains a port number, check ports in the future. */
451       *mask_port = 1;
452    }
453
454    /*
455     * XXX: This could be optimized to operate on whole words instead
456     * of octets (128-bit CPU could do it in one iteration).
457     */
458    /*
459     * Octets after prefix can be omitted because of
460     * previous initialization to zeros.
461     */
462    for (i = 0; (i < addr_len) && masklength; i++)
463    {
464       if (masklength >= 8)
465       {
466          mask_data[i] = 0xFF;
467          masklength -= 8;
468       }
469       else
470       {
471          /*
472           * XXX: This assumes MSB of octet is on the left side.
473           * This should be true for all architectures or solved
474           * by the link layer.
475           */
476          mask_data[i] = (uint8_t)~((1 << (8 - masklength)) - 1);
477          masklength = 0;
478       }
479    }
480
481 #else
482    aca->mask = 0;
483    for (i=1; i <= masklength ; i++)
484    {
485       aca->mask |= (1U << (32 - i));
486    }
487
488    /* now mask off the host portion of the ip address
489     * (i.e. save on the network portion of the address).
490     */
491    aca->addr = aca->addr & aca->mask;
492 #endif /* def HAVE_RFC2553 */
493
494    return(0);
495
496 }
497 #endif /* def FEATURE_ACL */
498
499
500 /*********************************************************************
501  *
502  * Function    :  connect_port_is_forbidden
503  *
504  * Description :  Check to see if CONNECT requests to the destination
505  *                port of this request are forbidden. The check is
506  *                independent of the actual request method.
507  *
508  * Parameters  :
509  *          1  :  csp = Current client state (buffers, headers, etc...)
510  *
511  * Returns     :  True if yes, false otherwise.
512  *
513  *********************************************************************/
514 int connect_port_is_forbidden(const struct client_state *csp)
515 {
516    return ((csp->action->flags & ACTION_LIMIT_CONNECT) &&
517      !match_portlist(csp->action->string[ACTION_STRING_LIMIT_CONNECT],
518         csp->http->port));
519 }
520
521
522 /*********************************************************************
523  *
524  * Function    :  block_url
525  *
526  * Description :  Called from `chat'.  Check to see if we need to block this.
527  *
528  * Parameters  :
529  *          1  :  csp = Current client state (buffers, headers, etc...)
530  *
531  * Returns     :  NULL => unblocked, else HTTP block response
532  *
533  *********************************************************************/
534 struct http_response *block_url(struct client_state *csp)
535 {
536    struct http_response *rsp;
537    const char *new_content_type = NULL;
538
539    /*
540     * If it's not blocked, don't block it ;-)
541     */
542    if ((csp->action->flags & ACTION_BLOCK) == 0)
543    {
544       return NULL;
545    }
546    if (csp->action->flags & ACTION_REDIRECT)
547    {
548       log_error(LOG_LEVEL_ERROR, "redirect{} overruled by block.");
549    }
550    /*
551     * Else, prepare a response
552     */
553    if (NULL == (rsp = alloc_http_response()))
554    {
555       return cgi_error_memory();
556    }
557
558 #ifdef FEATURE_EXTENDED_STATISTICS
559    if (csp->action->string[ACTION_STRING_BLOCK] != NULL)
560    {
561       increment_block_reason_counter(csp->action->string[ACTION_STRING_BLOCK]);
562    }
563 #endif
564
565    /*
566     * If it's an image-url, send back an image or redirect
567     * as specified by the relevant +image action
568     */
569 #ifdef FEATURE_IMAGE_BLOCKING
570    if (((csp->action->flags & ACTION_IMAGE_BLOCKER) != 0)
571         && is_imageurl(csp))
572    {
573       char *p;
574       /* determine HOW images should be blocked */
575       p = csp->action->string[ACTION_STRING_IMAGE_BLOCKER];
576
577       if (csp->action->flags & ACTION_HANDLE_AS_EMPTY_DOCUMENT)
578       {
579          log_error(LOG_LEVEL_ERROR, "handle-as-empty-document overruled by handle-as-image.");
580       }
581
582       /* and handle accordingly: */
583       if ((p == NULL) || (0 == strcmpic(p, "pattern")))
584       {
585          rsp->status = strdup_or_die("403 Request blocked by Privoxy");
586          rsp->body = bindup(image_pattern_data, image_pattern_length);
587          if (rsp->body == NULL)
588          {
589             free_http_response(rsp);
590             return cgi_error_memory();
591          }
592          rsp->content_length = image_pattern_length;
593
594          if (enlist_unique_header(rsp->headers, "Content-Type", BUILTIN_IMAGE_MIMETYPE))
595          {
596             free_http_response(rsp);
597             return cgi_error_memory();
598          }
599       }
600       else if (0 == strcmpic(p, "blank"))
601       {
602          rsp->status = strdup_or_die("403 Request blocked by Privoxy");
603          rsp->body = bindup(image_blank_data, image_blank_length);
604          if (rsp->body == NULL)
605          {
606             free_http_response(rsp);
607             return cgi_error_memory();
608          }
609          rsp->content_length = image_blank_length;
610
611          if (enlist_unique_header(rsp->headers, "Content-Type", BUILTIN_IMAGE_MIMETYPE))
612          {
613             free_http_response(rsp);
614             return cgi_error_memory();
615          }
616       }
617       else
618       {
619          rsp->status = strdup_or_die("302 Local Redirect from Privoxy");
620
621          if (enlist_unique_header(rsp->headers, "Location", p))
622          {
623             free_http_response(rsp);
624             return cgi_error_memory();
625          }
626       }
627
628    }
629    else
630 #endif /* def FEATURE_IMAGE_BLOCKING */
631    if (csp->action->flags & ACTION_HANDLE_AS_EMPTY_DOCUMENT)
632    {
633      /*
634       *  Send empty document.
635       */
636       new_content_type = csp->action->string[ACTION_STRING_CONTENT_TYPE];
637
638       freez(rsp->body);
639       rsp->body = strdup_or_die(" ");
640       rsp->content_length = 1;
641
642       if (csp->config->feature_flags & RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK)
643       {
644          /*
645           * Workaround for firefox bug 492459
646           *   https://bugzilla.mozilla.org/show_bug.cgi?id=492459
647           * Return a 200 OK status for pages blocked with +handle-as-empty-document
648           * if the "handle-as-empty-doc-returns-ok" runtime config option is set.
649           */
650          rsp->status = strdup_or_die("200 Request blocked by Privoxy");
651       }
652       else
653       {
654          rsp->status = strdup_or_die("403 Request blocked by Privoxy");
655       }
656
657       if (new_content_type != 0)
658       {
659          log_error(LOG_LEVEL_HEADER, "Overwriting Content-Type with %s", new_content_type);
660          if (enlist_unique_header(rsp->headers, "Content-Type", new_content_type))
661          {
662             free_http_response(rsp);
663             return cgi_error_memory();
664          }
665       }
666    }
667    else
668
669    /*
670     * Else, generate an HTML "blocked" message:
671     */
672    {
673       jb_err err;
674       struct map * exports;
675
676       rsp->status = strdup_or_die("403 Request blocked by Privoxy");
677
678       exports = default_exports(csp, NULL);
679       if (exports == NULL)
680       {
681          free_http_response(rsp);
682          return cgi_error_memory();
683       }
684
685 #ifdef FEATURE_FORCE_LOAD
686       err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1);
687       /*
688        * Export the force conditional block killer if
689        *
690        * - Privoxy was compiled without FEATURE_FORCE_LOAD, or
691        * - Privoxy is configured to enforce blocks, or
692        * - it's a CONNECT request and enforcing wouldn't work anyway.
693        */
694       if ((csp->config->feature_flags & RUNTIME_FEATURE_ENFORCE_BLOCKS)
695        || (0 == strcmpic(csp->http->gpc, "connect")))
696 #endif /* ndef FEATURE_FORCE_LOAD */
697       {
698          err = map_block_killer(exports, "force-support");
699       }
700
701       if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1);
702       if (!err) err = map(exports, "hostport", 1, html_encode(csp->http->hostport), 0);
703       if (!err) err = map(exports, "path", 1, html_encode(csp->http->path), 0);
704       if (!err) err = map(exports, "path-ue", 1, url_encode(csp->http->path), 0);
705       if (!err)
706       {
707          const char *block_reason;
708          if (csp->action->string[ACTION_STRING_BLOCK] != NULL)
709          {
710             block_reason = csp->action->string[ACTION_STRING_BLOCK];
711          }
712          else
713          {
714             assert(connect_port_is_forbidden(csp));
715             block_reason = "Forbidden CONNECT port.";
716          }
717          err = map(exports, "block-reason", 1, html_encode(block_reason), 0);
718       }
719       if (err)
720       {
721          free_map(exports);
722          free_http_response(rsp);
723          return cgi_error_memory();
724       }
725
726       err = template_fill_for_cgi(csp, "blocked", exports, rsp);
727       if (err)
728       {
729          free_http_response(rsp);
730          return cgi_error_memory();
731       }
732    }
733    rsp->crunch_reason = BLOCKED;
734
735    return finish_http_response(csp, rsp);
736
737 }
738
739
740 #ifdef FEATURE_TRUST
741 /*********************************************************************
742  *
743  * Function    :  trust_url FIXME: I should be called distrust_url
744  *
745  * Description :  Calls is_untrusted_url to determine if the URL is trusted
746  *                and if not, returns a HTTP 403 response with a reject message.
747  *
748  * Parameters  :
749  *          1  :  csp = Current client state (buffers, headers, etc...)
750  *
751  * Returns     :  NULL => trusted, else http_response.
752  *
753  *********************************************************************/
754 struct http_response *trust_url(struct client_state *csp)
755 {
756    struct http_response *rsp;
757    struct map * exports;
758    char buf[BUFFER_SIZE];
759    char *p;
760    struct pattern_spec **tl;
761    struct pattern_spec *t;
762    jb_err err;
763
764    /*
765     * Don't bother to work on trusted URLs
766     */
767    if (!is_untrusted_url(csp))
768    {
769       return NULL;
770    }
771
772    /*
773     * Else, prepare a response:
774     */
775    if (NULL == (rsp = alloc_http_response()))
776    {
777       return cgi_error_memory();
778    }
779
780    rsp->status = strdup_or_die("403 Request blocked by Privoxy");
781    exports = default_exports(csp, NULL);
782    if (exports == NULL)
783    {
784       free_http_response(rsp);
785       return cgi_error_memory();
786    }
787
788    /*
789     * Export the protocol, host, port, and referrer information
790     */
791    err = map(exports, "hostport", 1, csp->http->hostport, 1);
792    if (!err) err = map(exports, "protocol", 1, csp->http->ssl ? "https://" : "http://", 1);
793    if (!err) err = map(exports, "path", 1, csp->http->path, 1);
794
795    if (NULL != (p = get_header_value(csp->headers, "Referer:")))
796    {
797       if (!err) err = map(exports, "referrer", 1, html_encode(p), 0);
798    }
799    else
800    {
801       if (!err) err = map(exports, "referrer", 1, "none set", 1);
802    }
803
804    if (err)
805    {
806       free_map(exports);
807       free_http_response(rsp);
808       return cgi_error_memory();
809    }
810
811    /*
812     * Export the trust list
813     */
814    p = strdup_or_die("");
815    for (tl = csp->config->trust_list; (t = *tl) != NULL ; tl++)
816    {
817       snprintf(buf, sizeof(buf), "<li>%s</li>\n", t->spec);
818       string_append(&p, buf);
819    }
820    err = map(exports, "trusted-referrers", 1, p, 0);
821
822    if (err)
823    {
824       free_map(exports);
825       free_http_response(rsp);
826       return cgi_error_memory();
827    }
828
829    /*
830     * Export the trust info, if available
831     */
832    if (csp->config->trust_info->first)
833    {
834       struct list_entry *l;
835
836       p = strdup_or_die("");
837       for (l = csp->config->trust_info->first; l ; l = l->next)
838       {
839          snprintf(buf, sizeof(buf), "<li> <a href=\"%s\">%s</a><br>\n", l->str, l->str);
840          string_append(&p, buf);
841       }
842       err = map(exports, "trust-info", 1, p, 0);
843    }
844    else
845    {
846       err = map_block_killer(exports, "have-trust-info");
847    }
848
849    if (err)
850    {
851       free_map(exports);
852       free_http_response(rsp);
853       return cgi_error_memory();
854    }
855
856    /*
857     * Export the force conditional block killer if
858     *
859     * - Privoxy was compiled without FEATURE_FORCE_LOAD, or
860     * - Privoxy is configured to enforce blocks, or
861     * - it's a CONNECT request and enforcing wouldn't work anyway.
862     */
863 #ifdef FEATURE_FORCE_LOAD
864    if ((csp->config->feature_flags & RUNTIME_FEATURE_ENFORCE_BLOCKS)
865     || (0 == strcmpic(csp->http->gpc, "connect")))
866    {
867       err = map_block_killer(exports, "force-support");
868    }
869    else
870    {
871       err = map(exports, "force-prefix", 1, FORCE_PREFIX, 1);
872    }
873 #else /* ifndef FEATURE_FORCE_LOAD */
874    err = map_block_killer(exports, "force-support");
875 #endif /* ndef FEATURE_FORCE_LOAD */
876
877    if (err)
878    {
879       free_map(exports);
880       free_http_response(rsp);
881       return cgi_error_memory();
882    }
883
884    /*
885     * Build the response
886     */
887    err = template_fill_for_cgi(csp, "untrusted", exports, rsp);
888    if (err)
889    {
890       free_http_response(rsp);
891       return cgi_error_memory();
892    }
893    rsp->crunch_reason = UNTRUSTED;
894
895    return finish_http_response(csp, rsp);
896 }
897 #endif /* def FEATURE_TRUST */
898
899
900 /*********************************************************************
901  *
902  * Function    :  compile_dynamic_pcrs_job_list
903  *
904  * Description :  Compiles a dynamic pcrs job list (one with variables
905  *                resolved at request time)
906  *
907  * Parameters  :
908  *          1  :  csp = Current client state (buffers, headers, etc...)
909  *          2  :  b = The filter list to compile
910  *
911  * Returns     :  NULL in case of errors, otherwise the
912  *                pcrs job list.
913  *
914  *********************************************************************/
915 pcrs_job *compile_dynamic_pcrs_job_list(const struct client_state *csp, const struct re_filterfile_spec *b)
916 {
917    struct list_entry *pattern;
918    pcrs_job *job_list = NULL;
919    pcrs_job *dummy = NULL;
920    pcrs_job *lastjob = NULL;
921    int error = 0;
922
923    const struct pcrs_variable variables[] =
924    {
925       {"url",    csp->http->url,   1},
926       {"path",   csp->http->path,  1},
927       {"host",   csp->http->host,  1},
928       {"origin", csp->ip_addr_str, 1},
929       {"listen-address", csp->listen_addr_str, 1},
930       {NULL,     NULL,             1}
931    };
932
933    for (pattern = b->patterns->first; pattern != NULL; pattern = pattern->next)
934    {
935       assert(pattern->str != NULL);
936
937       dummy = pcrs_compile_dynamic_command(pattern->str, variables, &error);
938       if (NULL == dummy)
939       {
940          log_error(LOG_LEVEL_ERROR,
941             "Compiling dynamic pcrs job '%s' for '%s' failed with error code %d: %s",
942             pattern->str, b->name, error, pcrs_strerror(error));
943          continue;
944       }
945       else
946       {
947          if (error == PCRS_WARN_TRUNCATION)
948          {
949             log_error(LOG_LEVEL_ERROR,
950                "At least one of the variables in \'%s\' had to "
951                "be truncated before compilation", pattern->str);
952          }
953          if (job_list == NULL)
954          {
955             job_list = dummy;
956          }
957          else
958          {
959             lastjob->next = dummy;
960          }
961          lastjob = dummy;
962       }
963    }
964
965    return job_list;
966 }
967
968
969 /*********************************************************************
970  *
971  * Function    :  rewrite_url
972  *
973  * Description :  Rewrites a URL with a single pcrs command
974  *                and returns the result if it differs from the
975  *                original and isn't obviously invalid.
976  *
977  * Parameters  :
978  *          1  :  old_url = URL to rewrite.
979  *          2  :  pcrs_command = pcrs command formatted as string (s@foo@bar@)
980  *
981  *
982  * Returns     :  NULL if the pcrs_command didn't change the url, or
983  *                the result of the modification.
984  *
985  *********************************************************************/
986 char *rewrite_url(char *old_url, const char *pcrs_command)
987 {
988    char *new_url = NULL;
989    int hits;
990
991    assert(old_url);
992    assert(pcrs_command);
993
994    new_url = pcrs_execute_single_command(old_url, pcrs_command, &hits);
995
996    if (hits == 0)
997    {
998       log_error(LOG_LEVEL_REDIRECTS,
999          "pcrs command \"%s\" didn't change \"%s\".",
1000          pcrs_command, old_url);
1001       freez(new_url);
1002    }
1003    else if (hits < 0)
1004    {
1005       log_error(LOG_LEVEL_REDIRECTS,
1006          "executing pcrs command \"%s\" to rewrite %s failed: %s",
1007          pcrs_command, old_url, pcrs_strerror(hits));
1008       freez(new_url);
1009    }
1010    else if (strncmpic(new_url, "http://", 7) && strncmpic(new_url, "https://", 8))
1011    {
1012       log_error(LOG_LEVEL_ERROR,
1013          "pcrs command \"%s\" changed \"%s\" to \"%s\" (%u hi%s), "
1014          "but the result doesn't look like a valid URL and will be ignored.",
1015          pcrs_command, old_url, new_url, hits, (hits == 1) ? "t" : "ts");
1016       freez(new_url);
1017    }
1018    else
1019    {
1020       log_error(LOG_LEVEL_REDIRECTS,
1021          "pcrs command \"%s\" changed \"%s\" to \"%s\" (%u hi%s).",
1022          pcrs_command, old_url, new_url, hits, (hits == 1) ? "t" : "ts");
1023    }
1024
1025    return new_url;
1026
1027 }
1028
1029
1030 #ifdef FEATURE_FAST_REDIRECTS
1031 /*********************************************************************
1032  *
1033  * Function    :  get_last_url
1034  *
1035  * Description :  Search for the last URL inside a string.
1036  *                If the string already is a URL, it will
1037  *                be the first URL found.
1038  *
1039  * Parameters  :
1040  *          1  :  subject = the string to check
1041  *          2  :  redirect_mode = +fast-redirect{} mode
1042  *
1043  * Returns     :  NULL if no URL was found, or
1044  *                the last URL found.
1045  *
1046  *********************************************************************/
1047 static char *get_last_url(char *subject, const char *redirect_mode)
1048 {
1049    char *new_url = NULL;
1050    char *tmp;
1051
1052    assert(subject);
1053    assert(redirect_mode);
1054
1055    subject = strdup(subject);
1056    if (subject == NULL)
1057    {
1058       log_error(LOG_LEVEL_ERROR, "Out of memory while searching for redirects.");
1059       return NULL;
1060    }
1061
1062    if (0 == strcmpic(redirect_mode, "check-decoded-url") && strchr(subject, '%'))
1063    {
1064       char *url_segment = NULL;
1065       char **url_segments;
1066       size_t max_segments;
1067       int segments;
1068
1069       log_error(LOG_LEVEL_REDIRECTS,
1070          "Checking \"%s\" for encoded redirects.", subject);
1071
1072       /*
1073        * Check each parameter in the URL separately.
1074        * Sectionize the URL at "?" and "&",
1075        * go backwards through the segments, URL-decode them
1076        * and look for a URL in the decoded result.
1077        * Stop the search after the first match.
1078        *
1079        * XXX: This estimate is guaranteed to be high enough as we
1080        *      let ssplit() ignore empty fields, but also a bit wasteful.
1081        */
1082       max_segments = strlen(subject) / 2;
1083       url_segments = malloc(max_segments * sizeof(char *));
1084
1085       if (NULL == url_segments)
1086       {
1087          log_error(LOG_LEVEL_ERROR,
1088             "Out of memory while decoding URL: %s", subject);
1089          freez(subject);
1090          return NULL;
1091       }
1092
1093       segments = ssplit(subject, "?&", url_segments, max_segments);
1094
1095       while (segments-- > 0)
1096       {
1097          char *dtoken = url_decode(url_segments[segments]);
1098          if (NULL == dtoken)
1099          {
1100             log_error(LOG_LEVEL_ERROR, "Unable to decode \"%s\".", url_segments[segments]);
1101             continue;
1102          }
1103          url_segment = strstr(dtoken, "http://");
1104          if (NULL == url_segment)
1105          {
1106             url_segment = strstr(dtoken, "https://");
1107          }
1108          if (NULL != url_segment)
1109          {
1110             url_segment = strdup_or_die(url_segment);
1111             freez(dtoken);
1112             break;
1113          }
1114          freez(dtoken);
1115       }
1116       freez(subject);
1117       freez(url_segments);
1118
1119       if (url_segment == NULL)
1120       {
1121          return NULL;
1122       }
1123       subject = url_segment;
1124    }
1125    else
1126    {
1127       /* Look for a URL inside this one, without decoding anything. */
1128       log_error(LOG_LEVEL_REDIRECTS,
1129          "Checking \"%s\" for unencoded redirects.", subject);
1130    }
1131
1132    /*
1133     * Find the last URL encoded in the request
1134     */
1135    tmp = subject;
1136    while ((tmp = strstr(tmp, "http://")) != NULL)
1137    {
1138       new_url = tmp++;
1139    }
1140    tmp = (new_url != NULL) ? new_url : subject;
1141    while ((tmp = strstr(tmp, "https://")) != NULL)
1142    {
1143       new_url = tmp++;
1144    }
1145
1146    if ((new_url != NULL)
1147       && (  (new_url != subject)
1148          || (0 == strncmpic(subject, "http://", 7))
1149          || (0 == strncmpic(subject, "https://", 8))
1150          ))
1151    {
1152       /*
1153        * Return new URL if we found a redirect
1154        * or if the subject already was a URL.
1155        *
1156        * The second case makes sure that we can
1157        * chain get_last_url after another redirection check
1158        * (like rewrite_url) without losing earlier redirects.
1159        */
1160       new_url = strdup(new_url);
1161       freez(subject);
1162       return new_url;
1163    }
1164
1165    freez(subject);
1166    return NULL;
1167
1168 }
1169 #endif /* def FEATURE_FAST_REDIRECTS */
1170
1171
1172 /*********************************************************************
1173  *
1174  * Function    :  redirect_url
1175  *
1176  * Description :  Checks if Privoxy should answer the request with
1177  *                a HTTP redirect and generates the redirect if
1178  *                necessary.
1179  *
1180  * Parameters  :
1181  *          1  :  csp = Current client state (buffers, headers, etc...)
1182  *
1183  * Returns     :  NULL if the request can pass, HTTP redirect otherwise.
1184  *
1185  *********************************************************************/
1186 struct http_response *redirect_url(struct client_state *csp)
1187 {
1188    struct http_response *rsp;
1189 #ifdef FEATURE_FAST_REDIRECTS
1190    /*
1191     * XXX: Do we still need FEATURE_FAST_REDIRECTS
1192     * as compile-time option? The user can easily disable
1193     * it in his action file.
1194     */
1195    char * redirect_mode;
1196 #endif /* def FEATURE_FAST_REDIRECTS */
1197    char *old_url = NULL;
1198    char *new_url = NULL;
1199    char *redirection_string;
1200
1201    if ((csp->action->flags & ACTION_REDIRECT))
1202    {
1203       redirection_string = csp->action->string[ACTION_STRING_REDIRECT];
1204
1205       /*
1206        * If the redirection string begins with 's',
1207        * assume it's a pcrs command, otherwise treat it as
1208        * properly formatted URL and use it for the redirection
1209        * directly.
1210        *
1211        * According to (the now obsolete) RFC 2616 section 14.30
1212        * the URL has to be absolute and if the user tries:
1213        * +redirect{sadly/this/will/be/parsed/as/pcrs_command.html}
1214        * she would get undefined results anyway.
1215        *
1216        * RFC 7231 7.1.2 actually allows relative references,
1217        * but those start with a leading slash (RFC 3986 4.2) and
1218        * thus can't be mistaken for pcrs commands either.
1219        */
1220
1221       if (*redirection_string == 's')
1222       {
1223          old_url = csp->http->url;
1224          new_url = rewrite_url(old_url, redirection_string);
1225       }
1226       else
1227       {
1228          log_error(LOG_LEVEL_REDIRECTS,
1229             "No pcrs command recognized, assuming that \"%s\" is already properly formatted.",
1230             redirection_string);
1231          new_url = strdup(redirection_string);
1232       }
1233    }
1234
1235 #ifdef FEATURE_FAST_REDIRECTS
1236    if ((csp->action->flags & ACTION_FAST_REDIRECTS))
1237    {
1238       redirect_mode = csp->action->string[ACTION_STRING_FAST_REDIRECTS];
1239
1240       /*
1241        * If it exists, use the previously rewritten URL as input
1242        * otherwise just use the old path.
1243        */
1244       old_url = (new_url != NULL) ? new_url : strdup(csp->http->path);
1245       new_url = get_last_url(old_url, redirect_mode);
1246       freez(old_url);
1247    }
1248
1249    /*
1250     * Disable redirect checkers, so that they
1251     * will be only run more than once if the user
1252     * also enables them through tags.
1253     *
1254     * From a performance point of view
1255     * it doesn't matter, but the duplicated
1256     * log messages are annoying.
1257     */
1258    csp->action->flags &= ~ACTION_FAST_REDIRECTS;
1259 #endif /* def FEATURE_FAST_REDIRECTS */
1260    csp->action->flags &= ~ACTION_REDIRECT;
1261
1262    /* Did any redirect action trigger? */
1263    if (new_url)
1264    {
1265       if (url_requires_percent_encoding(new_url))
1266       {
1267          char *encoded_url;
1268          log_error(LOG_LEVEL_REDIRECTS, "Percent-encoding redirect URL: %N",
1269             strlen(new_url), new_url);
1270          encoded_url = percent_encode_url(new_url);
1271          freez(new_url);
1272          if (encoded_url == NULL)
1273          {
1274             return cgi_error_memory();
1275          }
1276          new_url = encoded_url;
1277          assert(FALSE == url_requires_percent_encoding(new_url));
1278       }
1279
1280       if (0 == strcmpic(new_url, csp->http->url))
1281       {
1282          log_error(LOG_LEVEL_ERROR,
1283             "New URL \"%s\" and old URL \"%s\" are the same. Redirection loop prevented.",
1284             csp->http->url, new_url);
1285             freez(new_url);
1286       }
1287       else
1288       {
1289          log_error(LOG_LEVEL_REDIRECTS, "New URL is: %s", new_url);
1290
1291          if (NULL == (rsp = alloc_http_response()))
1292          {
1293             freez(new_url);
1294             return cgi_error_memory();
1295          }
1296
1297          rsp->status = strdup_or_die("302 Local Redirect from Privoxy");
1298          if (enlist_unique_header(rsp->headers, "Location", new_url))
1299          {
1300             freez(new_url);
1301             free_http_response(rsp);
1302             return cgi_error_memory();
1303          }
1304          rsp->crunch_reason = REDIRECTED;
1305          freez(new_url);
1306
1307          return finish_http_response(csp, rsp);
1308       }
1309    }
1310
1311    /* Only reached if no redirect is required */
1312    return NULL;
1313
1314 }
1315
1316
1317 #ifdef FEATURE_IMAGE_BLOCKING
1318 /*********************************************************************
1319  *
1320  * Function    :  is_imageurl
1321  *
1322  * Description :  Given a URL, decide whether it should be treated
1323  *                as image URL or not.
1324  *
1325  * Parameters  :
1326  *          1  :  csp = Current client state (buffers, headers, etc...)
1327  *
1328  * Returns     :  True (nonzero) if URL is an image URL, false (0)
1329  *                otherwise
1330  *
1331  *********************************************************************/
1332 int is_imageurl(const struct client_state *csp)
1333 {
1334    return ((csp->action->flags & ACTION_IMAGE) != 0);
1335
1336 }
1337 #endif /* def FEATURE_IMAGE_BLOCKING */
1338
1339
1340 #ifdef FEATURE_TRUST
1341 /*********************************************************************
1342  *
1343  * Function    :  is_untrusted_url
1344  *
1345  * Description :  Should we "distrust" this URL (and block it)?
1346  *
1347  *                Yes if it matches a line in the trustfile, or if the
1348  *                    referrer matches a line starting with "+" in the
1349  *                    trustfile.
1350  *                No  otherwise.
1351  *
1352  * Parameters  :
1353  *          1  :  csp = Current client state (buffers, headers, etc...)
1354  *
1355  * Returns     :  0 => trusted, 1 => untrusted
1356  *
1357  *********************************************************************/
1358 int is_untrusted_url(const struct client_state *csp)
1359 {
1360    struct file_list *fl;
1361    struct block_spec *b;
1362    struct pattern_spec **trusted_url;
1363    struct http_request rhttp[1];
1364    const char * referer;
1365    jb_err err;
1366
1367    /*
1368     * If we don't have a trustlist, we trust everybody
1369     */
1370    if (((fl = csp->tlist) == NULL) || ((b  = fl->f) == NULL))
1371    {
1372       return 0;
1373    }
1374
1375    memset(rhttp, '\0', sizeof(*rhttp));
1376
1377    /*
1378     * Do we trust the request URL itself?
1379     */
1380    for (b = b->next; b ; b = b->next)
1381    {
1382       if (url_match(b->url, csp->http))
1383       {
1384          return b->reject;
1385       }
1386    }
1387
1388    if (NULL == (referer = get_header_value(csp->headers, "Referer:")))
1389    {
1390       /* no referrer was supplied */
1391       return 1;
1392    }
1393
1394
1395    /*
1396     * If not, do we maybe trust its referrer?
1397     */
1398    err = parse_http_url(referer, rhttp, REQUIRE_PROTOCOL);
1399    if (err)
1400    {
1401       return 1;
1402    }
1403
1404    for (trusted_url = csp->config->trust_list; *trusted_url != NULL; trusted_url++)
1405    {
1406       if (url_match(*trusted_url, rhttp))
1407       {
1408          /* if the URL's referrer is from a trusted referrer, then
1409           * add the target spec to the trustfile as an unblocked
1410           * domain and return 0 (which means it's OK).
1411           */
1412
1413          FILE *fp;
1414
1415          if (NULL != (fp = fopen(csp->config->trustfile, "a")))
1416          {
1417             char * path;
1418             char * path_end;
1419             char * new_entry = strdup_or_die("~");
1420
1421             string_append(&new_entry, csp->http->hostport);
1422
1423             path = csp->http->path;
1424             if ( (path[0] == '/')
1425               && (path[1] == '~')
1426               && ((path_end = strchr(path + 2, '/')) != NULL))
1427             {
1428                /* since this path points into a user's home space
1429                 * be sure to include this spec in the trustfile.
1430                 */
1431                long path_len = path_end - path; /* save offset */
1432                path = strdup(path); /* Copy string */
1433                if (path != NULL)
1434                {
1435                   path_end = path + path_len; /* regenerate ptr to new buffer */
1436                   *(path_end + 1) = '\0'; /* Truncate path after '/' */
1437                }
1438                string_join(&new_entry, path);
1439             }
1440
1441             /*
1442              * Give a reason for generating this entry.
1443              */
1444             string_append(&new_entry, " # Trusted referrer was: ");
1445             string_append(&new_entry, referer);
1446
1447             if (new_entry != NULL)
1448             {
1449                if (-1 == fprintf(fp, "%s\n", new_entry))
1450                {
1451                   log_error(LOG_LEVEL_ERROR, "Failed to append \'%s\' to trustfile \'%s\': %E",
1452                      new_entry, csp->config->trustfile);
1453                }
1454                freez(new_entry);
1455             }
1456             else
1457             {
1458                /* FIXME: No way to handle out-of memory, so mostly ignoring it */
1459                log_error(LOG_LEVEL_ERROR, "Out of memory adding pattern to trust file");
1460             }
1461
1462             fclose(fp);
1463          }
1464          else
1465          {
1466             log_error(LOG_LEVEL_ERROR, "Failed to append new entry for \'%s\' to trustfile \'%s\': %E",
1467                csp->http->hostport, csp->config->trustfile);
1468          }
1469          return 0;
1470       }
1471    }
1472
1473    return 1;
1474 }
1475 #endif /* def FEATURE_TRUST */
1476
1477
1478 /*********************************************************************
1479  *
1480  * Function    :  get_filter
1481  *
1482  * Description :  Get a filter with a given name and type.
1483  *                Note that taggers are filters, too.
1484  *
1485  * Parameters  :
1486  *          1  :  csp = Current client state (buffers, headers, etc...)
1487  *          2  :  requested_name = Name of the content filter to get
1488  *          3  :  requested_type = Type of the filter to tagger to lookup
1489  *
1490  * Returns     :  A pointer to the requested filter
1491  *                or NULL if the filter wasn't found
1492  *
1493  *********************************************************************/
1494 struct re_filterfile_spec *get_filter(const struct client_state *csp,
1495                                       const char *requested_name,
1496                                       enum filter_type requested_type)
1497 {
1498    int i;
1499    struct re_filterfile_spec *b;
1500    struct file_list *fl;
1501
1502    for (i = 0; i < MAX_AF_FILES; i++)
1503    {
1504      fl = csp->rlist[i];
1505      if ((NULL == fl) || (NULL == fl->f))
1506      {
1507         /*
1508          * Either there are no filter files left or this
1509          * filter file just contains no valid filters.
1510          *
1511          * Continue to be sure we don't miss valid filter
1512          * files that are chained after empty or invalid ones.
1513          */
1514         continue;
1515      }
1516
1517      for (b = fl->f; b != NULL; b = b->next)
1518      {
1519         if (b->type != requested_type)
1520         {
1521            /* The callers isn't interested in this filter type. */
1522            continue;
1523         }
1524         if (strcmp(b->name, requested_name) == 0)
1525         {
1526            /* The requested filter has been found. Abort search. */
1527            return b;
1528         }
1529      }
1530    }
1531
1532    /* No filter with the given name and type exists. */
1533    return NULL;
1534
1535 }
1536
1537
1538 /*********************************************************************
1539  *
1540  * Function    :  pcrs_filter_response
1541  *
1542  * Description :  Execute all text substitutions from all applying
1543  *                +filter actions on the text buffer that's been
1544  *                accumulated in csp->iob->buf.
1545  *
1546  * Parameters  :
1547  *          1  :  csp = Current client state (buffers, headers, etc...)
1548  *
1549  * Returns     :  a pointer to the (newly allocated) modified buffer.
1550  *                or NULL if there were no hits or something went wrong
1551  *
1552  *********************************************************************/
1553 static char *pcrs_filter_response(struct client_state *csp)
1554 {
1555    int hits = 0;
1556    size_t size, prev_size;
1557
1558    char *old = NULL;
1559    char *new = NULL;
1560    pcrs_job *job;
1561
1562    struct re_filterfile_spec *b;
1563    struct list_entry *filtername;
1564
1565    /*
1566     * Sanity first
1567     */
1568    if (csp->iob->cur >= csp->iob->eod)
1569    {
1570       return(NULL);
1571    }
1572
1573    if (filters_available(csp) == FALSE)
1574    {
1575       log_error(LOG_LEVEL_ERROR, "Inconsistent configuration: "
1576          "content filtering enabled, but no content filters available.");
1577       return(NULL);
1578    }
1579
1580    size = (size_t)(csp->iob->eod - csp->iob->cur);
1581    old = csp->iob->cur;
1582
1583    /*
1584     * For all applying +filter actions, look if a filter by that
1585     * name exists and if yes, execute it's pcrs_joblist on the
1586     * buffer.
1587     */
1588    for (filtername = csp->action->multi[ACTION_MULTI_FILTER]->first;
1589         filtername != NULL; filtername = filtername->next)
1590    {
1591       int current_hits = 0; /* Number of hits caused by this filter */
1592       int job_number   = 0; /* Which job we're currently executing  */
1593       int job_hits     = 0; /* How many hits the current job caused */
1594       pcrs_job *joblist;
1595
1596       b = get_filter(csp, filtername->str, FT_CONTENT_FILTER);
1597       if (b == NULL)
1598       {
1599          continue;
1600       }
1601
1602       joblist = b->joblist;
1603
1604       if (b->dynamic) joblist = compile_dynamic_pcrs_job_list(csp, b);
1605
1606       if (NULL == joblist)
1607       {
1608          log_error(LOG_LEVEL_RE_FILTER, "Filter %s has empty joblist. Nothing to do.", b->name);
1609          continue;
1610       }
1611
1612       prev_size = size;
1613       /* Apply all jobs from the joblist */
1614       for (job = joblist; NULL != job; job = job->next)
1615       {
1616          job_number++;
1617          job_hits = pcrs_execute(job, old, size, &new, &size);
1618
1619          if (job_hits >= 0)
1620          {
1621             /*
1622              * That went well. Continue filtering
1623              * and use the result of this job as
1624              * input for the next one.
1625              */
1626             current_hits += job_hits;
1627             if (old != csp->iob->cur)
1628             {
1629                freez(old);
1630             }
1631             old = new;
1632          }
1633          else
1634          {
1635             /*
1636              * This job caused an unexpected error. Inform the user
1637              * and skip the rest of the jobs in this filter. We could
1638              * continue with the next job, but usually the jobs
1639              * depend on each other or are similar enough to
1640              * fail for the same reason.
1641              *
1642              * At the moment our pcrs expects the error codes of pcre 3.4,
1643              * but newer pcre versions can return additional error codes.
1644              * As a result pcrs_strerror()'s error message might be
1645              * "Unknown error ...", therefore we print the numerical value
1646              * as well.
1647              *
1648              * XXX: Is this important enough for LOG_LEVEL_ERROR or
1649              * should we use LOG_LEVEL_RE_FILTER instead?
1650              */
1651             log_error(LOG_LEVEL_ERROR, "Skipped filter \'%s\' after job number %u: %s (%d)",
1652                b->name, job_number, pcrs_strerror(job_hits), job_hits);
1653             break;
1654          }
1655       }
1656
1657       if (b->dynamic) pcrs_free_joblist(joblist);
1658
1659       log_error(LOG_LEVEL_RE_FILTER,
1660          "filtering %s%s (size %lu) with \'%s\' produced %d hits (new size %lu).",
1661          csp->http->hostport, csp->http->path, prev_size, b->name, current_hits, size);
1662 #ifdef FEATURE_EXTENDED_STATISTICS
1663       update_filter_statistics(b->name, current_hits);
1664 #endif
1665       hits += current_hits;
1666    }
1667
1668    /*
1669     * If there were no hits, destroy our copy and let
1670     * chat() use the original in csp->iob
1671     */
1672    if (!hits)
1673    {
1674       freez(new);
1675       return(NULL);
1676    }
1677
1678    csp->flags |= CSP_FLAG_MODIFIED;
1679    csp->content_length = size;
1680    clear_iob(csp->iob);
1681
1682    return(new);
1683
1684 }
1685
1686
1687 #ifdef FEATURE_EXTERNAL_FILTERS
1688 /*********************************************************************
1689  *
1690  * Function    :  get_external_filter
1691  *
1692  * Description :  Lookup the code to execute for an external filter.
1693  *                Masks the misuse of the re_filterfile_spec.
1694  *
1695  * Parameters  :
1696  *          1  :  csp = Current client state (buffers, headers, etc...)
1697  *          2  :  name = Name of the content filter to get
1698  *
1699  * Returns     :  A pointer to the requested code
1700  *                or NULL if the filter wasn't found
1701  *
1702  *********************************************************************/
1703 static const char *get_external_filter(const struct client_state *csp,
1704                                 const char *name)
1705 {
1706    struct re_filterfile_spec *external_filter;
1707
1708    external_filter = get_filter(csp, name, FT_EXTERNAL_CONTENT_FILTER);
1709    if (external_filter == NULL)
1710    {
1711       log_error(LOG_LEVEL_FATAL,
1712          "Didn't find stuff to execute for external filter: %s",
1713          name);
1714    }
1715
1716    return external_filter->patterns->first->str;
1717
1718 }
1719
1720
1721 /*********************************************************************
1722  *
1723  * Function    :  set_privoxy_variables
1724  *
1725  * Description :  Sets a couple of privoxy-specific environment variables
1726  *
1727  * Parameters  :
1728  *          1  :  csp = Current client state (buffers, headers, etc...)
1729  *
1730  * Returns     :  N/A
1731  *
1732  *********************************************************************/
1733 static void set_privoxy_variables(const struct client_state *csp)
1734 {
1735    int i;
1736    struct {
1737       const char *name;
1738       const char *value;
1739    } env[] = {
1740       { "PRIVOXY_URL",    csp->http->url   },
1741       { "PRIVOXY_PATH",   csp->http->path  },
1742       { "PRIVOXY_HOST",   csp->http->host  },
1743       { "PRIVOXY_ORIGIN", csp->ip_addr_str },
1744       { "PRIVOXY_LISTEN_ADDRESS", csp->listen_addr_str },
1745    };
1746
1747    for (i = 0; i < SZ(env); i++)
1748    {
1749       if (setenv(env[i].name, env[i].value, 1))
1750       {
1751          log_error(LOG_LEVEL_ERROR, "Failed to set %s=%s: %E",
1752             env[i].name, env[i].value);
1753       }
1754    }
1755 }
1756
1757
1758 /*********************************************************************
1759  *
1760  * Function    :  execute_external_filter
1761  *
1762  * Description :  Pipe content into external filter and return the output
1763  *
1764  * Parameters  :
1765  *          1  :  csp = Current client state (buffers, headers, etc...)
1766  *          2  :  name = Name of the external filter to execute
1767  *          3  :  content = The original content to filter
1768  *          4  :  size = The size of the content buffer
1769  *
1770  * Returns     :  a pointer to the (newly allocated) modified buffer.
1771  *                or NULL if there were no hits or something went wrong
1772  *
1773  *********************************************************************/
1774 static char *execute_external_filter(const struct client_state *csp,
1775    const char *name, char *content, size_t *size)
1776 {
1777    char cmd[200];
1778    char file_name[FILENAME_MAX];
1779    FILE *fp;
1780    char *filter_output;
1781    int fd;
1782    int ret;
1783    size_t new_size;
1784    const char *external_filter;
1785
1786    if (csp->config->temporary_directory == NULL)
1787    {
1788       log_error(LOG_LEVEL_ERROR,
1789          "No temporary-directory configured. Can't execute filter: %s",
1790          name);
1791       return NULL;
1792    }
1793
1794    external_filter = get_external_filter(csp, name);
1795
1796    if (sizeof(file_name) < snprintf(file_name, sizeof(file_name),
1797          "%s/privoxy-XXXXXXXX", csp->config->temporary_directory))
1798    {
1799       log_error(LOG_LEVEL_ERROR, "temporary-directory path too long");
1800       return NULL;
1801    }
1802
1803    fd = mkstemp(file_name);
1804    if (fd == -1)
1805    {
1806       log_error(LOG_LEVEL_ERROR, "mkstemp() failed to create %s: %E", file_name);
1807       return NULL;
1808    }
1809
1810    fp = fdopen(fd, "w");
1811    if (fp == NULL)
1812    {
1813       log_error(LOG_LEVEL_ERROR, "fdopen() failed: %E");
1814       unlink(file_name);
1815       return NULL;
1816    }
1817
1818    /*
1819     * The size may be zero if a previous filter discarded everything.
1820     *
1821     * This isn't necessary unintentional, so we just don't try
1822     * to fwrite() nothing and let the user deal with the rest.
1823     */
1824    if ((*size != 0) && fwrite(content, *size, 1, fp) != 1)
1825    {
1826       log_error(LOG_LEVEL_ERROR, "fwrite(..., %lu, 1, ..) failed: %E", *size);
1827       unlink(file_name);
1828       fclose(fp);
1829       return NULL;
1830    }
1831    fclose(fp);
1832
1833    if (sizeof(cmd) < snprintf(cmd, sizeof(cmd), "%s < %s", external_filter, file_name))
1834    {
1835       log_error(LOG_LEVEL_ERROR,
1836          "temporary-directory or external filter path too long");
1837       unlink(file_name);
1838       return NULL;
1839    }
1840
1841    log_error(LOG_LEVEL_RE_FILTER, "Executing '%s': %s", name, cmd);
1842
1843    /*
1844     * The locking is necessary to prevent other threads
1845     * from overwriting the environment variables before
1846     * the popen fork. Afterwards this no longer matters.
1847     */
1848    privoxy_mutex_lock(&external_filter_mutex);
1849    set_privoxy_variables(csp);
1850    fp = popen(cmd, "r");
1851    privoxy_mutex_unlock(&external_filter_mutex);
1852    if (fp == NULL)
1853    {
1854       log_error(LOG_LEVEL_ERROR, "popen(\"%s\", \"r\") failed: %E", cmd);
1855       unlink(file_name);
1856       return NULL;
1857    }
1858
1859    /* Allocate at least one byte */
1860    filter_output = malloc_or_die(*size + 1);
1861
1862    new_size = 0;
1863    while (!feof(fp) && !ferror(fp))
1864    {
1865       size_t len;
1866       /* Could be bigger ... */
1867       enum { READ_LENGTH = 2048 };
1868
1869       if (new_size + READ_LENGTH >= *size)
1870       {
1871          char *p;
1872
1873          /* Could be considered wasteful if the content is 'large'. */
1874          *size += (*size >= READ_LENGTH) ? *size : READ_LENGTH;
1875
1876          p = realloc(filter_output, *size);
1877          if (p == NULL)
1878          {
1879             log_error(LOG_LEVEL_ERROR, "Out of memory while reading "
1880                "external filter output. Using what we got so far.");
1881             break;
1882          }
1883          filter_output = p;
1884       }
1885       assert(new_size + READ_LENGTH < *size);
1886       len = fread(&filter_output[new_size], 1, READ_LENGTH, fp);
1887       if (len > 0)
1888       {
1889          new_size += len;
1890       }
1891    }
1892
1893    ret = pclose(fp);
1894    if (ret == -1)
1895    {
1896       log_error(LOG_LEVEL_ERROR, "Executing %s failed: %E", cmd);
1897    }
1898    else
1899    {
1900       log_error(LOG_LEVEL_RE_FILTER,
1901          "Executing '%s' resulted in return value %d. "
1902          "Read %lu of up to %lu bytes.", name, (ret >> 8), new_size, *size);
1903    }
1904
1905    unlink(file_name);
1906    *size = new_size;
1907
1908    return filter_output;
1909
1910 }
1911 #endif /* def FEATURE_EXTERNAL_FILTERS */
1912
1913
1914 /*********************************************************************
1915  *
1916  * Function    :  gif_deanimate_response
1917  *
1918  * Description :  Deanimate the GIF image that has been accumulated in
1919  *                csp->iob->buf, set csp->content_length to the modified
1920  *                size and raise the CSP_FLAG_MODIFIED flag.
1921  *
1922  * Parameters  :
1923  *          1  :  csp = Current client state (buffers, headers, etc...)
1924  *
1925  * Returns     :  a pointer to the (newly allocated) modified buffer.
1926  *                or NULL in case something went wrong.
1927  *
1928  *********************************************************************/
1929 #ifdef FUZZ
1930 char *gif_deanimate_response(struct client_state *csp)
1931 #else
1932 static char *gif_deanimate_response(struct client_state *csp)
1933 #endif
1934 {
1935    struct binbuffer *in, *out;
1936    char *p;
1937    size_t size;
1938
1939    size = (size_t)(csp->iob->eod - csp->iob->cur);
1940
1941    in =  zalloc_or_die(sizeof(*in));
1942    out = zalloc_or_die(sizeof(*out));
1943
1944    in->buffer = csp->iob->cur;
1945    in->size = size;
1946
1947    if (gif_deanimate(in, out, strncmp("last", csp->action->string[ACTION_STRING_DEANIMATE], 4)))
1948    {
1949       log_error(LOG_LEVEL_DEANIMATE, "failed! (gif parsing)");
1950       freez(in);
1951       buf_free(out);
1952       return(NULL);
1953    }
1954    else
1955    {
1956       if ((int)size == out->offset)
1957       {
1958          log_error(LOG_LEVEL_DEANIMATE, "GIF not changed.");
1959       }
1960       else
1961       {
1962          log_error(LOG_LEVEL_DEANIMATE,
1963             "Success! GIF shrunk from %lu bytes to %lu.", size, out->offset);
1964       }
1965       csp->content_length = out->offset;
1966       csp->flags |= CSP_FLAG_MODIFIED;
1967       p = out->buffer;
1968       freez(in);
1969       freez(out);
1970       return(p);
1971    }
1972
1973 }
1974
1975
1976 /*********************************************************************
1977  *
1978  * Function    :  get_filter_function
1979  *
1980  * Description :  Decides which content filter function has
1981  *                to be applied (if any). Only considers functions
1982  *                for internal filters which are mutually-exclusive.
1983  *
1984  * Parameters  :
1985  *          1  :  csp = Current client state (buffers, headers, etc...)
1986  *
1987  * Returns     :  The content filter function to run, or
1988  *                NULL if no content filter is active
1989  *
1990  *********************************************************************/
1991 static filter_function_ptr get_filter_function(const struct client_state *csp)
1992 {
1993    filter_function_ptr filter_function = NULL;
1994
1995    /*
1996     * Choose the applying filter function based on
1997     * the content type and action settings.
1998     */
1999    if ((csp->content_type & CT_TEXT) &&
2000        (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER])))
2001    {
2002       filter_function = pcrs_filter_response;
2003    }
2004    else if ((csp->content_type & CT_GIF) &&
2005             (csp->action->flags & ACTION_DEANIMATE))
2006    {
2007       filter_function = gif_deanimate_response;
2008    }
2009
2010    return filter_function;
2011 }
2012
2013
2014 /*********************************************************************
2015  *
2016  * Function    :  remove_chunked_transfer_coding
2017  *
2018  * Description :  In-situ remove the "chunked" transfer coding as defined
2019  *                in RFC 7230 4.1 from a buffer. XXX: The implementation
2020  *                is neither complete nor compliant (TODO #129).
2021  *
2022  * Parameters  :
2023  *          1  :  buffer = Pointer to the text buffer
2024  *          2  :  size =  In: Number of bytes to be processed,
2025  *                       Out: Number of bytes after de-chunking.
2026  *                       (undefined in case of errors)
2027  *
2028  * Returns     :  JB_ERR_OK for success,
2029  *                JB_ERR_PARSE otherwise
2030  *
2031  *********************************************************************/
2032 #ifdef FUZZ
2033 extern jb_err remove_chunked_transfer_coding(char *buffer, size_t *size)
2034 #else
2035 static jb_err remove_chunked_transfer_coding(char *buffer, size_t *size)
2036 #endif
2037 {
2038    size_t newsize = 0;
2039    unsigned int chunksize = 0;
2040    char *from_p, *to_p;
2041    const char *end_of_buffer = buffer + *size;
2042
2043    if (*size == 0)
2044    {
2045       log_error(LOG_LEVEL_FATAL, "Invalid chunked input. Buffer is empty.");
2046       return JB_ERR_PARSE;
2047    }
2048
2049    assert(buffer);
2050    from_p = to_p = buffer;
2051
2052    if (sscanf(buffer, "%x", &chunksize) != 1)
2053    {
2054       log_error(LOG_LEVEL_ERROR, "Invalid first chunksize while stripping \"chunked\" transfer coding");
2055       return JB_ERR_PARSE;
2056    }
2057
2058    while (chunksize > 0U)
2059    {
2060       /*
2061        * If the chunk-size is valid, we should have at least
2062        * chunk-size bytes of chunk-data and five bytes of
2063        * meta data (chunk-size, CRLF, CRLF) left in the buffer.
2064        */
2065       if (chunksize + 5 >= *size - newsize)
2066       {
2067          log_error(LOG_LEVEL_ERROR,
2068             "Chunk size %u exceeds buffered data left. "
2069             "Already digested %lu of %lu buffered bytes.",
2070             chunksize, newsize, *size);
2071          return JB_ERR_PARSE;
2072       }
2073
2074       /*
2075        * Skip the chunk-size, the optional chunk-ext and the CRLF
2076        * that is supposed to be located directly before the start
2077        * of chunk-data.
2078        */
2079       if (NULL == (from_p = strstr(from_p, "\r\n")))
2080       {
2081          log_error(LOG_LEVEL_ERROR, "Parse error while stripping \"chunked\" transfer coding");
2082          return JB_ERR_PARSE;
2083       }
2084       from_p += 2;
2085
2086       /*
2087        * The previous strstr() does not enforce chunk-validity
2088        * and is sattisfied as long a CRLF is left in the buffer.
2089        *
2090        * Make sure the bytes we consider chunk-data are within
2091        * the valid range.
2092        */
2093       if (from_p + chunksize >= end_of_buffer)
2094       {
2095          log_error(LOG_LEVEL_ERROR,
2096             "End of chunk is beyond the end of the buffer.");
2097          return JB_ERR_PARSE;
2098       }
2099
2100       memmove(to_p, from_p, (size_t) chunksize);
2101       newsize += chunksize;
2102       to_p = buffer + newsize;
2103       from_p += chunksize;
2104
2105       /*
2106        * Not merging this check with the previous one allows us
2107        * to keep chunks without trailing CRLF. It's not clear
2108        * if we actually have to care about those, though.
2109        */
2110       if (from_p + 2 >= end_of_buffer)
2111       {
2112          log_error(LOG_LEVEL_ERROR, "Not enough room for trailing CRLF.");
2113          return JB_ERR_PARSE;
2114       }
2115       from_p += 2;
2116       if (sscanf(from_p, "%x", &chunksize) != 1)
2117       {
2118          log_error(LOG_LEVEL_INFO, "Invalid \"chunked\" transfer encoding detected and ignored.");
2119          break;
2120       }
2121    }
2122
2123    /* XXX: Should get its own loglevel. */
2124    log_error(LOG_LEVEL_RE_FILTER,
2125       "De-chunking successful. Shrunk from %lu to %lu", *size, newsize);
2126
2127    *size = newsize;
2128
2129    return JB_ERR_OK;
2130
2131 }
2132
2133
2134 /*********************************************************************
2135  *
2136  * Function    :  prepare_for_filtering
2137  *
2138  * Description :  If necessary, de-chunks and decompresses
2139  *                the content so it can get filterd.
2140  *
2141  * Parameters  :
2142  *          1  :  csp = Current client state (buffers, headers, etc...)
2143  *
2144  * Returns     :  JB_ERR_OK for success,
2145  *                JB_ERR_PARSE otherwise
2146  *
2147  *********************************************************************/
2148 static jb_err prepare_for_filtering(struct client_state *csp)
2149 {
2150    jb_err err = JB_ERR_OK;
2151
2152    /*
2153     * If the body has a "chunked" transfer-encoding,
2154     * get rid of it, adjusting size and iob->eod
2155     */
2156    if (csp->flags & CSP_FLAG_CHUNKED)
2157    {
2158       size_t size = (size_t)(csp->iob->eod - csp->iob->cur);
2159
2160       log_error(LOG_LEVEL_RE_FILTER, "Need to de-chunk first");
2161       err = remove_chunked_transfer_coding(csp->iob->cur, &size);
2162       if (JB_ERR_OK == err)
2163       {
2164          csp->iob->eod = csp->iob->cur + size;
2165          csp->flags |= CSP_FLAG_MODIFIED;
2166       }
2167       else
2168       {
2169          return JB_ERR_PARSE;
2170       }
2171    }
2172
2173 #ifdef FEATURE_ZLIB
2174    /*
2175     * If the body has a supported transfer-encoding,
2176     * decompress it, adjusting size and iob->eod.
2177     */
2178    if ((csp->content_type & (CT_GZIP|CT_DEFLATE))
2179 #ifdef FEATURE_BROTLI
2180       || (csp->content_type & CT_BROTLI)
2181 #endif
2182        )
2183    {
2184       if (0 == csp->iob->eod - csp->iob->cur)
2185       {
2186          /* Nothing left after de-chunking. */
2187          return JB_ERR_OK;
2188       }
2189
2190       err = decompress_iob(csp);
2191
2192       if (JB_ERR_OK == err)
2193       {
2194          csp->flags |= CSP_FLAG_MODIFIED;
2195          csp->content_type &= ~CT_TABOO;
2196       }
2197       else
2198       {
2199          /*
2200           * Unset content types to remember not to
2201           * modify the Content-Encoding header later.
2202           */
2203          csp->content_type &= ~CT_GZIP;
2204          csp->content_type &= ~CT_DEFLATE;
2205 #ifdef FEATURE_BROTLI
2206          csp->content_type &= ~CT_BROTLI;
2207 #endif
2208       }
2209    }
2210 #endif
2211
2212    return err;
2213 }
2214
2215
2216 /*********************************************************************
2217  *
2218  * Function    :  execute_content_filters
2219  *
2220  * Description :  Executes a given content filter.
2221  *
2222  * Parameters  :
2223  *          1  :  csp = Current client state (buffers, headers, etc...)
2224  *
2225  * Returns     :  Pointer to the modified buffer, or
2226  *                NULL if filtering failed or wasn't necessary.
2227  *
2228  *********************************************************************/
2229 char *execute_content_filters(struct client_state *csp)
2230 {
2231    char *content;
2232    filter_function_ptr content_filter;
2233
2234    assert(content_filters_enabled(csp->action));
2235
2236    if (0 == csp->iob->eod - csp->iob->cur)
2237    {
2238       /*
2239        * No content (probably status code 301, 302 ...),
2240        * no filtering necessary.
2241        */
2242       return NULL;
2243    }
2244
2245    if (JB_ERR_OK != prepare_for_filtering(csp))
2246    {
2247       /*
2248        * failed to de-chunk or decompress.
2249        */
2250       return NULL;
2251    }
2252
2253    if (0 == csp->iob->eod - csp->iob->cur)
2254    {
2255       /*
2256        * Clown alarm: chunked and/or compressed nothing delivered.
2257        */
2258       return NULL;
2259    }
2260
2261    content_filter = get_filter_function(csp);
2262    content = (content_filter != NULL) ? (*content_filter)(csp) : NULL;
2263
2264 #ifdef FEATURE_EXTERNAL_FILTERS
2265    if ((csp->content_type & CT_TEXT) &&
2266        !list_is_empty(csp->action->multi[ACTION_MULTI_EXTERNAL_FILTER]))
2267    {
2268       struct list_entry *filtername;
2269       size_t size = (size_t)csp->content_length;
2270
2271       if (content == NULL)
2272       {
2273          content = csp->iob->cur;
2274          size = (size_t)(csp->iob->eod - csp->iob->cur);
2275       }
2276
2277       for (filtername = csp->action->multi[ACTION_MULTI_EXTERNAL_FILTER]->first;
2278            filtername ; filtername = filtername->next)
2279       {
2280          char *result = execute_external_filter(csp, filtername->str, content, &size);
2281          if (result != NULL)
2282          {
2283             if (content != csp->iob->cur)
2284             {
2285                free(content);
2286             }
2287             content = result;
2288          }
2289       }
2290       csp->flags |= CSP_FLAG_MODIFIED;
2291       csp->content_length = size;
2292    }
2293 #endif /* def FEATURE_EXTERNAL_FILTERS */
2294
2295    return content;
2296
2297 }
2298
2299
2300 /*********************************************************************
2301  *
2302  * Function    :  get_url_actions
2303  *
2304  * Description :  Gets the actions for this URL.
2305  *
2306  * Parameters  :
2307  *          1  :  csp = Current client state (buffers, headers, etc...)
2308  *          2  :  http = http_request request for blocked URLs
2309  *
2310  * Returns     :  N/A
2311  *
2312  *********************************************************************/
2313 void get_url_actions(struct client_state *csp, struct http_request *http)
2314 {
2315    struct file_list *fl;
2316    struct url_actions *b;
2317    int i;
2318
2319    init_current_action(csp->action);
2320
2321    for (i = 0; i < MAX_AF_FILES; i++)
2322    {
2323       if (((fl = csp->actions_list[i]) == NULL) || ((b = fl->f) == NULL))
2324       {
2325          return;
2326       }
2327
2328 #ifdef FEATURE_CLIENT_TAGS
2329       apply_url_actions(csp->action, http, csp->client_tags, b);
2330 #else
2331       apply_url_actions(csp->action, http, b);
2332 #endif
2333    }
2334
2335    return;
2336 }
2337
2338 /*********************************************************************
2339  *
2340  * Function    :  apply_url_actions
2341  *
2342  * Description :  Applies a list of URL actions.
2343  *
2344  * Parameters  :
2345  *          1  :  action = Destination.
2346  *          2  :  http = Current URL
2347  *          3  :  client_tags = list of client tags
2348  *          4  :  b = list of URL actions to apply
2349  *
2350  * Returns     :  N/A
2351  *
2352  *********************************************************************/
2353 static void apply_url_actions(struct current_action_spec *action,
2354                               struct http_request *http,
2355 #ifdef FEATURE_CLIENT_TAGS
2356                               const struct list *client_tags,
2357 #endif
2358                               struct url_actions *b)
2359 {
2360    if (b == NULL)
2361    {
2362       /* Should never happen */
2363       return;
2364    }
2365
2366    for (b = b->next; NULL != b; b = b->next)
2367    {
2368       if (url_match(b->url, http))
2369       {
2370          merge_current_action(action, b->action);
2371       }
2372 #ifdef FEATURE_CLIENT_TAGS
2373       if (client_tag_match(b->url, client_tags))
2374       {
2375          merge_current_action(action, b->action);
2376       }
2377 #endif
2378    }
2379 }
2380
2381
2382 /*********************************************************************
2383  *
2384  * Function    :  get_forward_override_settings
2385  *
2386  * Description :  Returns forward settings as specified with the
2387  *                forward-override{} action. forward-override accepts
2388  *                forward lines similar to the one used in the
2389  *                configuration file, but without the URL pattern.
2390  *
2391  *                For example:
2392  *
2393  *                   forward / .
2394  *
2395  *                in the configuration file can be replaced with
2396  *                the action section:
2397  *
2398  *                 {+forward-override{forward .}}
2399  *                 /
2400  *
2401  * Parameters  :
2402  *          1  :  csp = Current client state (buffers, headers, etc...)
2403  *
2404  * Returns     :  Pointer to forwarding structure in case of success.
2405  *                Invalid syntax is fatal.
2406  *
2407  *********************************************************************/
2408 static const struct forward_spec *get_forward_override_settings(struct client_state *csp)
2409 {
2410    const char *forward_override_line = csp->action->string[ACTION_STRING_FORWARD_OVERRIDE];
2411    char forward_settings[BUFFER_SIZE];
2412    char *http_parent = NULL;
2413    /* variable names were chosen for consistency reasons. */
2414    struct forward_spec *fwd = NULL;
2415    int vec_count;
2416    char *vec[3];
2417
2418    assert(csp->action->flags & ACTION_FORWARD_OVERRIDE);
2419    /* Should be enforced by load_one_actions_file() */
2420    assert(strlen(forward_override_line) < sizeof(forward_settings) - 1);
2421
2422    /* Create a copy ssplit can modify */
2423    strlcpy(forward_settings, forward_override_line, sizeof(forward_settings));
2424
2425    if (NULL != csp->fwd)
2426    {
2427       /*
2428        * XXX: Currently necessary to prevent memory
2429        * leaks when the show-url-info cgi page is visited.
2430        */
2431       unload_forward_spec(csp->fwd);
2432    }
2433
2434    /*
2435     * allocate a new forward node, valid only for
2436     * the lifetime of this request. Save its location
2437     * in csp as well, so sweep() can free it later on.
2438     */
2439    fwd = csp->fwd = zalloc_or_die(sizeof(*fwd));
2440
2441    vec_count = ssplit(forward_settings, " \t", vec, SZ(vec));
2442    if ((vec_count == 2) && !strcasecmp(vec[0], "forward"))
2443    {
2444       fwd->type = SOCKS_NONE;
2445
2446       /* Parse the parent HTTP proxy host:port */
2447       http_parent = vec[1];
2448
2449    }
2450    else if ((vec_count == 2) && !strcasecmp(vec[0], "forward-webserver"))
2451    {
2452       fwd->type = FORWARD_WEBSERVER;
2453
2454       /* Parse the parent HTTP server host:port */
2455       http_parent = vec[1];
2456
2457    }
2458    else if (vec_count == 3)
2459    {
2460       char *socks_proxy = NULL;
2461
2462       if  (!strcasecmp(vec[0], "forward-socks4"))
2463       {
2464          fwd->type = SOCKS_4;
2465          socks_proxy = vec[1];
2466       }
2467       else if (!strcasecmp(vec[0], "forward-socks4a"))
2468       {
2469          fwd->type = SOCKS_4A;
2470          socks_proxy = vec[1];
2471       }
2472       else if (!strcasecmp(vec[0], "forward-socks5"))
2473       {
2474          fwd->type = SOCKS_5;
2475          socks_proxy = vec[1];
2476       }
2477       else if (!strcasecmp(vec[0], "forward-socks5t"))
2478       {
2479          fwd->type = SOCKS_5T;
2480          socks_proxy = vec[1];
2481       }
2482
2483       if (NULL != socks_proxy)
2484       {
2485          /* Parse the SOCKS proxy [user:pass@]host[:port] */
2486          fwd->gateway_port = 1080;
2487          parse_forwarder_address(socks_proxy,
2488             &fwd->gateway_host, &fwd->gateway_port,
2489             &fwd->auth_username, &fwd->auth_password);
2490
2491          http_parent = vec[2];
2492       }
2493    }
2494
2495    if (NULL == http_parent)
2496    {
2497       log_error(LOG_LEVEL_FATAL,
2498          "Invalid forward-override syntax in: %s", forward_override_line);
2499       /* Never get here - LOG_LEVEL_FATAL causes program exit */
2500    }
2501
2502    /* Parse http forwarding settings */
2503    if (strcmp(http_parent, ".") != 0)
2504    {
2505       fwd->forward_port = 8000;
2506       parse_forwarder_address(http_parent,
2507          &fwd->forward_host, &fwd->forward_port,
2508          NULL, NULL);
2509    }
2510
2511    assert (NULL != fwd);
2512
2513    log_error(LOG_LEVEL_CONNECT,
2514       "Overriding forwarding settings based on \'%s\'", forward_override_line);
2515
2516    return fwd;
2517 }
2518
2519
2520 /*********************************************************************
2521  *
2522  * Function    :  forward_url
2523  *
2524  * Description :  Should we forward this to another proxy?
2525  *
2526  * Parameters  :
2527  *          1  :  csp = Current client state (buffers, headers, etc...)
2528  *          2  :  http = http_request request for current URL
2529  *
2530  * Returns     :  Pointer to forwarding information.
2531  *
2532  *********************************************************************/
2533 const struct forward_spec *forward_url(struct client_state *csp,
2534                                        const struct http_request *http)
2535 {
2536    static const struct forward_spec fwd_default[1]; /* Zero'ed due to being static. */
2537    struct forward_spec *fwd = csp->config->forward;
2538
2539    if (csp->action->flags & ACTION_FORWARD_OVERRIDE)
2540    {
2541       return get_forward_override_settings(csp);
2542    }
2543
2544    if (fwd == NULL)
2545    {
2546       return fwd_default;
2547    }
2548
2549    while (fwd != NULL)
2550    {
2551       if (url_match(fwd->url, http))
2552       {
2553          return fwd;
2554       }
2555       fwd = fwd->next;
2556    }
2557
2558    return fwd_default;
2559 }
2560
2561
2562 /*********************************************************************
2563  *
2564  * Function    :  direct_response
2565  *
2566  * Description :  Check if Max-Forwards == 0 for an OPTIONS or TRACE
2567  *                request and if so, return a HTTP 501 to the client.
2568  *
2569  *                FIXME: I have a stupid name and I should handle the
2570  *                requests properly. Still, what we do here is rfc-
2571  *                compliant, whereas ignoring or forwarding are not.
2572  *
2573  * Parameters  :
2574  *          1  :  csp = Current client state (buffers, headers, etc...)
2575  *
2576  * Returns     :  http_response if , NULL if nonmatch or handler fail
2577  *
2578  *********************************************************************/
2579 struct http_response *direct_response(struct client_state *csp)
2580 {
2581    struct http_response *rsp;
2582    struct list_entry *p;
2583
2584    if ((0 == strcmpic(csp->http->gpc, "trace"))
2585       || (0 == strcmpic(csp->http->gpc, "options")))
2586    {
2587       for (p = csp->headers->first; (p != NULL) ; p = p->next)
2588       {
2589          if (!strncmpic(p->str, "Max-Forwards:", 13))
2590          {
2591             unsigned int max_forwards;
2592
2593             /*
2594              * If it's a Max-Forwards value of zero,
2595              * we have to intercept the request.
2596              */
2597             if (1 == sscanf(p->str+12, ": %u", &max_forwards) && max_forwards == 0)
2598             {
2599                /*
2600                 * FIXME: We could handle at least TRACE here,
2601                 * but that would require a verbatim copy of
2602                 * the request which we don't have anymore
2603                 */
2604                 log_error(LOG_LEVEL_HEADER,
2605                   "Detected header \'%s\' in OPTIONS or TRACE request. Returning 501.",
2606                   p->str);
2607
2608                /* Get mem for response or fail*/
2609                if (NULL == (rsp = alloc_http_response()))
2610                {
2611                   return cgi_error_memory();
2612                }
2613
2614                rsp->status = strdup_or_die("501 Not Implemented");
2615                rsp->is_static = 1;
2616                rsp->crunch_reason = UNSUPPORTED;
2617
2618                return(finish_http_response(csp, rsp));
2619             }
2620          }
2621       }
2622    }
2623    return NULL;
2624 }
2625
2626
2627 /*********************************************************************
2628  *
2629  * Function    :  content_requires_filtering
2630  *
2631  * Description :  Checks whether there are any content filters
2632  *                enabled for the current request and if they
2633  *                can actually be applied..
2634  *
2635  * Parameters  :
2636  *          1  :  csp = Current client state (buffers, headers, etc...)
2637  *
2638  * Returns     :  TRUE for yes, FALSE otherwise
2639  *
2640  *********************************************************************/
2641 int content_requires_filtering(struct client_state *csp)
2642 {
2643    if ((csp->content_type & CT_TABOO)
2644       && !(csp->action->flags & ACTION_FORCE_TEXT_MODE))
2645    {
2646       return FALSE;
2647    }
2648
2649    /*
2650     * Are we enabling text mode by force?
2651     */
2652    if (csp->action->flags & ACTION_FORCE_TEXT_MODE)
2653    {
2654       /*
2655        * Do we really have to?
2656        */
2657       if (csp->content_type & CT_TEXT)
2658       {
2659          log_error(LOG_LEVEL_HEADER, "Text mode is already enabled.");
2660       }
2661       else
2662       {
2663          csp->content_type |= CT_TEXT;
2664          log_error(LOG_LEVEL_HEADER, "Text mode enabled by force. Take cover!");
2665       }
2666    }
2667
2668    if (!(csp->content_type & CT_DECLARED))
2669    {
2670       /*
2671        * The server didn't bother to declare a MIME-Type.
2672        * Assume it's text that can be filtered.
2673        *
2674        * This also regulary happens with 304 responses,
2675        * therefore logging anything here would cause
2676        * too much noise.
2677        */
2678       csp->content_type |= CT_TEXT;
2679    }
2680
2681    /*
2682     * Choose the applying filter function based on
2683     * the content type and action settings.
2684     */
2685    if ((csp->content_type & CT_TEXT) &&
2686        (!list_is_empty(csp->action->multi[ACTION_MULTI_FILTER]) ||
2687         !list_is_empty(csp->action->multi[ACTION_MULTI_EXTERNAL_FILTER])))
2688    {
2689       return TRUE;
2690    }
2691    else if ((csp->content_type & CT_GIF)  &&
2692             (csp->action->flags & ACTION_DEANIMATE))
2693    {
2694       return TRUE;
2695    }
2696
2697    return FALSE;
2698
2699 }
2700
2701
2702 /*********************************************************************
2703  *
2704  * Function    :  content_filters_enabled
2705  *
2706  * Description :  Checks whether there are any content filters
2707  *                enabled for the current request.
2708  *
2709  * Parameters  :
2710  *          1  :  action = Action spec to check.
2711  *
2712  * Returns     :  TRUE for yes, FALSE otherwise
2713  *
2714  *********************************************************************/
2715 int content_filters_enabled(const struct current_action_spec *action)
2716 {
2717    return ((action->flags & ACTION_DEANIMATE) ||
2718       !list_is_empty(action->multi[ACTION_MULTI_FILTER]) ||
2719       !list_is_empty(action->multi[ACTION_MULTI_EXTERNAL_FILTER]));
2720 }
2721
2722
2723 /*********************************************************************
2724  *
2725  * Function    :  filters_available
2726  *
2727  * Description :  Checks whether there are any filters available.
2728  *
2729  * Parameters  :
2730  *          1  :  csp = Current client state (buffers, headers, etc...)
2731  *
2732  * Returns     :  TRUE for yes, FALSE otherwise.
2733  *
2734  *********************************************************************/
2735 int filters_available(const struct client_state *csp)
2736 {
2737    int i;
2738    for (i = 0; i < MAX_AF_FILES; i++)
2739    {
2740       const struct file_list *fl = csp->rlist[i];
2741       if ((NULL != fl) && (NULL != fl->f))
2742       {
2743          return TRUE;
2744       }
2745    }
2746    return FALSE;
2747 }
2748
2749 #ifdef FEATURE_EXTENDED_STATISTICS
2750
2751 struct filter_statistics_entry
2752 {
2753    char *filter;
2754    unsigned long long executions;
2755    unsigned long long response_bodies_modified;
2756    unsigned long long hits;
2757
2758    struct filter_statistics_entry *next;
2759 };
2760
2761 static struct filter_statistics_entry *filter_statistics = NULL;
2762
2763
2764 /*********************************************************************
2765  *
2766  * Function    :  register_filter_for_statistics
2767  *
2768  * Description :  Registers a filter so we can gather statistics for
2769  *                it unless the filter has already been registered
2770  *                before.
2771  *
2772  * Parameters  :
2773  *          1  :  filter = Name of the filter to register
2774  *
2775  * Returns     :  void
2776  *
2777  *********************************************************************/
2778 void register_filter_for_statistics(const char *filter)
2779 {
2780    struct filter_statistics_entry *entry;
2781
2782    privoxy_mutex_lock(&filter_statistics_mutex);
2783
2784    if (filter_statistics == NULL)
2785    {
2786       filter_statistics = zalloc_or_die(sizeof(struct filter_statistics_entry));
2787       entry = filter_statistics;
2788       entry->filter = strdup_or_die(filter);
2789       privoxy_mutex_unlock(&filter_statistics_mutex);
2790       return;
2791    }
2792    entry = filter_statistics;
2793    while (entry != NULL)
2794    {
2795       if (!strcmp(entry->filter, filter))
2796       {
2797          /* Already registered, nothing to do. */
2798          break;
2799       }
2800       if (entry->next == NULL)
2801       {
2802          entry->next = zalloc_or_die(sizeof(struct filter_statistics_entry));
2803          entry->next->filter = strdup_or_die(filter);
2804          break;
2805       }
2806       entry = entry->next;
2807    }
2808
2809    privoxy_mutex_unlock(&filter_statistics_mutex);
2810
2811 }
2812
2813
2814 /*********************************************************************
2815  *
2816  * Function    :  update_filter_statistics
2817  *
2818  * Description :  Updates the statistics for a filter.
2819  *
2820  * Parameters  :
2821  *          1  :  filter = Name of the filter to update
2822  *          2  :  hits = Hit count.
2823  *
2824  * Returns     :  void
2825  *
2826  *********************************************************************/
2827 void update_filter_statistics(const char *filter, int hits)
2828 {
2829    struct filter_statistics_entry *entry;
2830
2831    privoxy_mutex_lock(&filter_statistics_mutex);
2832
2833    entry = filter_statistics;
2834    while (entry != NULL)
2835    {
2836       if (!strcmp(entry->filter, filter))
2837       {
2838          entry->executions++;
2839          if (hits != 0)
2840          {
2841             entry->response_bodies_modified++;
2842             entry->hits += (unsigned)hits;
2843          }
2844          break;
2845       }
2846       entry = entry->next;
2847    }
2848
2849    privoxy_mutex_unlock(&filter_statistics_mutex);
2850
2851 }
2852
2853
2854 /*********************************************************************
2855  *
2856  * Function    :  get_filter_statistics
2857  *
2858  * Description :  Gets the statistics for a filter.
2859  *
2860  * Parameters  :
2861  *          1  :  filter = Name of the filter to get statistics for.
2862  *          2  :  executions = Storage for the execution count.
2863  *          3  :  response_bodies_modified = Storage for the number
2864  *                of modified response bodies.
2865  *          4  :  hits = Storage for the number of hits.
2866  *
2867  * Returns     :  void
2868  *
2869  *********************************************************************/
2870 void get_filter_statistics(const char *filter, unsigned long long *executions,
2871                            unsigned long long *response_bodies_modified,
2872                            unsigned long long *hits)
2873 {
2874    struct filter_statistics_entry *entry;
2875
2876    privoxy_mutex_lock(&filter_statistics_mutex);
2877
2878    entry = filter_statistics;
2879    while (entry != NULL)
2880    {
2881       if (!strcmp(entry->filter, filter))
2882       {
2883          *executions = entry->executions;
2884          *response_bodies_modified = entry->response_bodies_modified;
2885          *hits = entry->hits;
2886          break;
2887       }
2888       entry = entry->next;
2889    }
2890
2891    privoxy_mutex_unlock(&filter_statistics_mutex);
2892
2893 }
2894
2895
2896 struct block_statistics_entry
2897 {
2898    char *block_reason;
2899    unsigned long long count;
2900
2901    struct block_statistics_entry *next;
2902 };
2903
2904 static struct block_statistics_entry *block_statistics = NULL;
2905
2906 /*********************************************************************
2907  *
2908  * Function    :  register_block_reason_for_statistics
2909  *
2910  * Description :  Registers a block reason so we can gather statistics
2911  *                for it unless the block reason has already been
2912  *                registered before.
2913  *
2914  * Parameters  :
2915  *          1  :  block_reason = Block reason to register
2916  *
2917  * Returns     :  void
2918  *
2919  *********************************************************************/
2920 void register_block_reason_for_statistics(const char *block_reason)
2921 {
2922    struct block_statistics_entry *entry;
2923
2924    privoxy_mutex_lock(&block_statistics_mutex);
2925
2926    if (block_statistics == NULL)
2927    {
2928       block_statistics = zalloc_or_die(sizeof(struct block_statistics_entry));
2929       entry = block_statistics;
2930       entry->block_reason = strdup_or_die(block_reason);
2931       privoxy_mutex_unlock(&block_statistics_mutex);
2932       return;
2933    }
2934    entry = block_statistics;
2935    while (entry != NULL)
2936    {
2937       if (!strcmp(entry->block_reason, block_reason))
2938       {
2939          /* Already registered, nothing to do. */
2940          break;
2941       }
2942       if (entry->next == NULL)
2943       {
2944          entry->next = zalloc_or_die(sizeof(struct block_statistics_entry));
2945          entry->next->block_reason = strdup_or_die(block_reason);
2946          break;
2947       }
2948       entry = entry->next;
2949    }
2950
2951    privoxy_mutex_unlock(&block_statistics_mutex);
2952
2953 }
2954
2955
2956 /*********************************************************************
2957  *
2958  * Function    :  increment_block_reason_counter
2959  *
2960  * Description :  Updates the counter for a block reason.
2961  *
2962  * Parameters  :
2963  *          1  :  block_reason = Block reason to count
2964  *
2965  * Returns     :  void
2966  *
2967  *********************************************************************/
2968 static void increment_block_reason_counter(const char *block_reason)
2969 {
2970    struct block_statistics_entry *entry;
2971
2972    privoxy_mutex_lock(&block_statistics_mutex);
2973
2974    entry = block_statistics;
2975    while (entry != NULL)
2976    {
2977       if (!strcmp(entry->block_reason, block_reason))
2978       {
2979          entry->count++;
2980          break;
2981       }
2982       entry = entry->next;
2983    }
2984
2985    privoxy_mutex_unlock(&block_statistics_mutex);
2986
2987 }
2988
2989
2990 /*********************************************************************
2991  *
2992  * Function    :  get_block_reason_count
2993  *
2994  * Description :  Gets number of times a block reason was used.
2995  *
2996  * Parameters  :
2997  *          1  :  block_reason = Block reason to get statistics for.
2998  *          2  :  count = Storage for the number of times the block
2999  *                        reason was used.
3000  *
3001  * Returns     :  void
3002  *
3003  *********************************************************************/
3004 void get_block_reason_count(const char *block_reason, unsigned long long *count)
3005 {
3006    struct block_statistics_entry *entry;
3007
3008    privoxy_mutex_lock(&block_statistics_mutex);
3009
3010    entry = block_statistics;
3011    while (entry != NULL)
3012    {
3013       if (!strcmp(entry->block_reason, block_reason))
3014       {
3015          *count = entry->count;
3016          break;
3017       }
3018       entry = entry->next;
3019    }
3020
3021    privoxy_mutex_unlock(&block_statistics_mutex);
3022
3023 }
3024
3025 #endif /* def FEATURE_EXTENDED_STATISTICS */
3026
3027 /*
3028   Local Variables:
3029   tab-width: 3
3030   end:
3031 */