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