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