ae6c1f4605923372498db64ff7b5a90429dd724d
[privoxy.git] / parsers.c
1 const char parsers_rcs[] = "$Id: parsers.c,v 1.1.1.1 2001/05/15 13:59:01 oes Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/parsers.c,v $
5  *
6  * Purpose     :  Declares functions to parse/crunch headers and pages.
7  *                Functions declared include:
8  *                   `add_to_iob', `client_cookie_adder', `client_from',
9  *                   `client_referrer', `client_send_cookie', `client_ua',
10  *                   `client_uagent', `client_x_forwarded',
11  *                   `client_x_forwarded_adder', `client_xtra_adder',
12  *                   `content_type', `crumble', `destroy_list', `enlist',
13  *                   `flush_socket', `free_http_request', `get_header',
14  *                   `list_to_text', `match', `parse_http_request', `sed',
15  *                   and `server_set_cookie'.
16  *
17  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
18  *                IJBSWA team.  http://ijbswa.sourceforge.net
19  *
20  *                Based on the Internet Junkbuster originally written
21  *                by and Copyright (C) 1997 Anonymous Coders and 
22  *                Junkbusters Corporation.  http://www.junkbusters.com
23  *
24  *                This program is free software; you can redistribute it 
25  *                and/or modify it under the terms of the GNU General
26  *                Public License as published by the Free Software
27  *                Foundation; either version 2 of the License, or (at
28  *                your option) any later version.
29  *
30  *                This program is distributed in the hope that it will
31  *                be useful, but WITHOUT ANY WARRANTY; without even the
32  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
33  *                PARTICULAR PURPOSE.  See the GNU General Public
34  *                License for more details.
35  *
36  *                The GNU General Public License should be included with
37  *                this file.  If not, you can view it at
38  *                http://www.gnu.org/copyleft/gpl.html
39  *                or write to the Free Software Foundation, Inc., 59
40  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
41  *
42  * Revisions   :
43  *    $Log: parsers.c,v $
44  *    Revision 1.1.1.1  2001/05/15 13:59:01  oes
45  *    Initial import of version 2.9.3 source tree
46  *
47  *
48  *********************************************************************/
49 \f
50
51 #include "config.h"
52
53 #include <stdio.h>
54 #include <sys/types.h>
55 #include <stdlib.h>
56 #include <ctype.h>
57 #include <string.h>
58
59 #ifndef _WIN32
60 #include <unistd.h>
61 #endif
62
63 #include "project.h"
64 #include "parsers.h"
65 #include "encode.h"
66 #include "filters.h"
67 #include "loaders.h"
68 #include "showargs.h"
69 #include "jcc.h"
70 #include "ssplit.h"
71 #include "errlog.h"
72 #include "jbsockets.h"
73 #include "miscutil.h"
74
75 const char parsers_h_rcs[] = PARSERS_H_VERSION;
76
77 /* Fix a problem with Solaris.  There should be no effect on other
78  * platforms.
79  * Solaris's isspace() is a macro which uses it's argument directly
80  * as an array index.  Therefore we need to make sure that high-bit
81  * characters generate +ve values, and ideally we also want to make
82  * the argument match the declared parameter type of "int".
83  * 
84  * Why did they write a character function that can't take a simple 
85  * "char" argument?  Doh!
86  */
87 #define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
88 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
89
90
91 const struct parsers client_patterns[] = {
92    { "referer:",                 8,    client_referrer },
93    { "user-agent:",              11,   client_uagent },
94    { "ua-",                      3,    client_ua },
95    { "from:",                    5,    client_from },
96    { "cookie:",                  7,    client_send_cookie },
97    { "x-forwarded-for:",         16,   client_x_forwarded },
98    { "proxy-connection:",        17,   crumble },
99 #ifdef DENY_GZIP
100    { "Accept-Encoding: gzip",    21,   crumble },
101 #endif /* def DENY_GZIP */
102 #if defined(DETECT_MSIE_IMAGES)
103    { "Accept:",                   7,   client_accept },
104 #endif /* defined(DETECT_MSIE_IMAGES) */
105 #ifdef FORCE_LOAD
106    { "Host:",                     5,   client_host },
107 #endif /* def FORCE_LOAD */
108 /* { "if-modified-since:",       18,   crumble }, */
109    { NULL,                       0,    NULL }
110 };
111
112 const struct interceptors intercept_patterns[] = {
113    { "show-proxy-args",    14, show_proxy_args },
114 #ifdef TRUST_FILES
115    { "ij-untrusted-url",   14, ij_untrusted_url },
116 #endif /* def TRUST_FILES */
117    { NULL, 0, NULL }
118 };
119
120 const struct parsers server_patterns[] = {
121    { "set-cookie:",        11, server_set_cookie },
122    { "connection:",        11, crumble },
123 #ifdef PCRS
124    { "Content-Type:",      13, content_type },
125    { "Content-Length:",    15, crumble },
126 #endif /* def PCRS */
127    { NULL, 0, NULL }
128 };
129
130
131 void (* const add_client_headers[])(struct client_state *) = {
132    client_cookie_adder,
133    client_x_forwarded_adder,
134    client_xtra_adder,
135    NULL
136 };
137
138
139 void (* const add_server_headers[])(struct client_state *) = {
140    NULL
141 };
142
143
144 /*********************************************************************
145  *
146  * Function    :  match
147  *
148  * Description :  Do a `strncmpic' on every pattern in pats.
149  *
150  * Parameters  :
151  *          1  :  buf = a string to match to a list of patterns
152  *          2  :  pats = list of strings to compare against buf.
153  *
154  * Returns     :  Return the matching "struct parsers *",
155  *                or NULL if no pattern matches.
156  *
157  *********************************************************************/
158 static const struct parsers *match(char *buf, const struct parsers *pats)
159 {
160    const struct parsers *v;
161
162    if (buf == NULL)
163    {
164       /* hit me */
165       log_error(LOG_LEVEL_ERROR, "NULL parameter to match()");
166       return(NULL);
167    }
168
169    for (v = pats; v->str ; v++)
170    {
171       if (strncmpic(buf, v->str, v->len) == 0)
172       {
173          return(v);
174       }
175    }
176    return(NULL);
177
178 }
179
180
181 /*********************************************************************
182  *
183  * Function    :  flush_socket
184  *
185  * Description :  Write any pending "buffered" content.
186  *
187  * Parameters  :
188  *          1  :  fd = file descriptor of the socket to read
189  *          2  :  csp = Current client state (buffers, headers, etc...)
190  *
191  * Returns     :  On success, the number of bytes written are returned (zero
192  *                indicates nothing was written).  On error, -1 is returned,
193  *                and errno is set appropriately.  If count is zero and the
194  *                file descriptor refers to a regular file, 0 will be
195  *                returned without causing any other effect.  For a special
196  *                file, the results are not portable.
197  *
198  *********************************************************************/
199 int flush_socket(int fd, struct client_state *csp)
200 {
201    struct iob *iob = csp->iob;
202    int n = iob->eod - iob->cur;
203
204    if (n <= 0)
205    {
206       return(0);
207    }
208
209    n = write_socket(fd, iob->cur, n);
210    iob->eod = iob->cur = iob->buf;
211    return(n);
212
213 }
214
215
216 /*********************************************************************
217  *
218  * Function    :  add_to_iob
219  *
220  * Description :  Add content to the buffered page.
221  *
222  * Parameters  :
223  *          1  :  csp = Current client state (buffers, headers, etc...)
224  *          2  :  buf = holds the content to be added to the page
225  *          3  :  n = number of bytes to be added
226  *
227  * Returns     :  Number of bytes in the content buffer.
228  *
229  *********************************************************************/
230 int add_to_iob(struct client_state *csp, char *buf, int n)
231 {
232    struct iob *iob = csp->iob;
233    int have, need;
234    char *p;
235
236    have = iob->eod - iob->cur;
237
238    if (n <= 0)
239    {
240       return(have);
241    }
242
243    need = have + n;
244
245    if ((p = (char *)malloc(need + 1)) == NULL)
246    {
247       log_error(LOG_LEVEL_ERROR, "malloc() iob failed: %E");
248       return(-1);
249    }
250
251    if (have)
252    {
253       /* there is something in the buffer - save it */
254       memcpy(p, iob->cur, have);
255
256       /* replace the buffer with the new space */
257       freez(iob->buf);
258       iob->buf = p;
259
260       /* point to the end of the data */
261       p += have;
262    }
263    else
264    {
265       /* the buffer is empty, free it and reinitialize */
266       freez(iob->buf);
267       iob->buf = p;
268    }
269
270    /* copy the new data into the iob buffer */
271    memcpy(p, buf, n);
272
273    /* point to the end of the data */
274    p += n;
275
276    /* null terminate == cheap insurance */
277    *p = '\0';
278
279    /* set the pointers to the new values */
280    iob->cur = iob->buf;
281    iob->eod = p;
282
283    return(need);
284
285 }
286
287
288 /*********************************************************************
289  *
290  * Function    :  get_header
291  *
292  * Description :  This (odd) routine will parse the csp->iob
293  *
294  * Parameters  :
295  *          1  :  csp = Current client state (buffers, headers, etc...)
296  *
297  * Returns     :  Any one of the following:
298  *
299  * 1) a pointer to a dynamically allocated string that contains a header line
300  * 2) NULL  indicating that the end of the header was reached
301  * 3) ""    indicating that the end of the iob was reached before finding
302  *          a complete header line.
303  *
304  *********************************************************************/
305 char *get_header(struct client_state *csp)
306 {
307    struct iob *iob;
308    char *p, *q, *ret;
309    iob = csp->iob;
310
311    if ((iob->cur == NULL)
312       || ((p = strchr(iob->cur, '\n')) == NULL))
313    {
314       return(""); /* couldn't find a complete header */
315    }
316
317    *p = '\0';
318
319    ret = strdup(iob->cur);
320
321    iob->cur = p+1;
322
323    if ((q = strchr(ret, '\r'))) *q = '\0';
324
325    /* is this a blank linke (i.e. the end of the header) ? */
326    if (*ret == '\0')
327    {
328       freez(ret);
329       return(NULL);
330    }
331
332    return(ret);
333
334 }
335
336
337 /*********************************************************************
338  *
339  * Function    :  enlist
340  *
341  * Description :  Append a string into a specified string list.
342  *
343  * Parameters  :
344  *          1  :  h = pointer to list 'dummy' header
345  *          2  :  s = string to add to the list
346  *
347  * Returns     :  N/A
348  *
349  *********************************************************************/
350 void enlist(struct list *h, const char *s)
351 {
352    struct list *n = (struct list *)malloc(sizeof(*n));
353    struct list *l;
354
355    if (n)
356    {
357       n->str  = strdup(s);
358       n->next = NULL;
359
360       if ((l = h->last))
361       {
362          l->next = n;
363       }
364       else
365       {
366          h->next = n;
367       }
368
369       h->last = n;
370    }
371
372 }
373
374
375 /*********************************************************************
376  *
377  * Function    :  destroy_list
378  *
379  * Description :  Destroy a string list (opposite of enlist)
380  *
381  * Parameters  :
382  *          1  :  h = pointer to list 'dummy' header
383  *
384  * Returns     :  N/A
385  *
386  *********************************************************************/
387 void destroy_list(struct list *h)
388 {
389    struct list *p, *n;
390
391    for (p = h->next; p ; p = n)
392    {
393       n = p->next;
394       freez(p->str);
395       freez(p);
396    }
397
398    memset(h, '\0', sizeof(*h));
399
400 }
401
402
403 /*********************************************************************
404  *
405  * Function    :  list_to_text
406  *
407  * Description :  "Flaten" a string list into 1 long \r\n delimited string.
408  *
409  * Parameters  :
410  *          1  :  h = pointer to list 'dummy' header
411  *
412  * Returns     :  NULL on malloc error, else new long string.
413  *
414  *********************************************************************/
415 static char *list_to_text(struct list *h)
416 {
417    struct list *p;
418    char *ret = NULL;
419    char *s;
420    int size;
421
422    size = 0;
423
424    for (p = h->next; p ; p = p->next)
425    {
426       if (p->str)
427       {
428          size += strlen(p->str) + 2;
429       }
430    }
431
432    if ((ret = (char *)malloc(size + 1)) == NULL)
433    {
434       return(NULL);
435    }
436
437    ret[size] = '\0';
438
439    s = ret;
440
441    for (p = h->next; p ; p = p->next)
442    {
443       if (p->str)
444       {
445          strcpy(s, p->str);
446          s += strlen(s);
447          *s++ = '\r'; *s++ = '\n';
448       }
449    }
450
451    return(ret);
452
453 }
454
455
456 /*********************************************************************
457  *
458  * Function    :  sed
459  *
460  * Description :  add, delete or modify lines in the HTTP header streams.
461  *                On entry, it receives a linked list of headers space
462  *                that was allocated dynamically (both the list nodes
463  *                and the header contents).
464  *
465  *                As a side effect it frees the space used by the original
466  *                header lines.
467  *
468  * Parameters  :
469  *          1  :  pats = list of patterns to match against headers
470  *          2  :  more_headers = list of functions to add more
471  *                headers (client or server)
472  *          3  :  csp = Current client state (buffers, headers, etc...)
473  *
474  * Returns     :  Single pointer to a fully formed header.
475  *
476  *********************************************************************/
477 char *sed(const struct parsers pats[], void (* const more_headers[])(struct client_state *), struct client_state *csp)
478 {
479    struct list *p;
480    const struct parsers *v;
481    char *hdr;
482    void (* const *f)();
483
484    for (p = csp->headers->next; p ; p = p->next)
485    {
486       log_error(LOG_LEVEL_HEADER, "scan: %s", p->str);
487
488       if ((v = match(p->str, pats)))
489       {
490          hdr = v->parser(v, p->str, csp);
491          freez(p->str);
492          p->str = hdr;
493       }
494
495    }
496
497    /* place any additional headers on the csp->headers list */
498    for (f = more_headers; *f ; f++)
499    {
500       (*f)(csp);
501    }
502
503    /* add the blank line at the end of the header */
504    enlist(csp->headers, "");
505
506    hdr = list_to_text(csp->headers);
507
508    return(hdr);
509
510 }
511
512
513 /*********************************************************************
514  *
515  * Function    :  free_http_request
516  *
517  * Description :  Freez a http_request structure
518  *
519  * Parameters  :
520  *          1  :  http = points to a http_request structure to free
521  *
522  * Returns     :  N/A
523  *
524  *********************************************************************/
525 void free_http_request(struct http_request *http)
526 {
527    freez(http->cmd);
528    freez(http->gpc);
529    freez(http->host);
530    freez(http->hostport);
531    freez(http->path);
532    freez(http->ver);
533
534 }
535
536
537 /*********************************************************************
538  *
539  * Function    :  parse_http_request
540  *
541  * Description :  Parse out the host and port from the URL.  Find the
542  *                hostname & path, port (if ':'), and/or password (if '@')
543  *
544  * Parameters  :
545  *          1  :  req = URL (or is it URI?) to break down
546  *          2  :  http = pointer to the http structure to hold elements
547  *          3  :  csp = Current client state (buffers, headers, etc...)
548  *
549  * Returns     :  N/A
550  *
551  *********************************************************************/
552 void parse_http_request(char *req, struct http_request *http, struct client_state *csp)
553 {
554    char *buf, *v[10], *url, *p;
555    int n;
556
557    memset(http, '\0', sizeof(*http));
558
559    http->cmd = strdup(req);
560
561    buf = strdup(req);
562
563    n = ssplit(buf, " \r\n", v, SZ(v), 1, 1);
564
565    if (n == 3)
566    {
567       /* this could be a CONNECT request */
568       if (strcmpic(v[0], "connect") == 0)
569       {
570          http->ssl      = 1;
571          http->gpc      = strdup(v[0]);
572          http->hostport = strdup(v[1]);
573          http->ver      = strdup(v[2]);
574       }
575
576 #ifdef WEBDAV
577
578 /* This next line is a little ugly, but it simplifies the if statement below. */
579 /* Basically if using webDAV, we want the OR condition to use these too.      */
580
581 /*
582  * by haroon
583  * These are the headers as defined in RFC2518 to add webDAV support
584  */
585
586 #define OR_WEBDAV || \
587          (0 == strcmpic(v[0], "propfind")) || \
588          (0 == strcmpic(v[0], "proppatch")) || \
589          (0 == strcmpic(v[0], "move")) || \
590          (0 == strcmpic(v[0], "copy")) || \
591          (0 == strcmpic(v[0], "mkcol")) || \
592          (0 == strcmpic(v[0], "lock")) || \
593          (0 == strcmpic(v[0], "unlock"))
594
595 #else /* No webDAV support is enabled.  Provide an empty OR_WEBDAV macro. */
596
597 #define OR_WEBDAV
598
599 #endif
600
601       /* or it could be a GET or a POST (possibly webDAV too) */
602       if ((strcmpic(v[0], "get")  == 0) ||
603           (strcmpic(v[0], "head") == 0) OR_WEBDAV ||
604           (strcmpic(v[0], "post") == 0))
605       {
606          http->ssl      = 0;
607          http->gpc      = strdup(v[0]);
608          url            = v[1];
609          http->ver      = strdup(v[2]);
610
611          if (strncmpic(url, "http://",  7) == 0)
612          {
613             url += 7;
614          }
615          else if (strncmpic(url, "https://", 8) == 0)
616          {
617             url += 8;
618          }
619          else
620          {
621             url = NULL;
622          }
623
624          if (url && (p = strchr(url, '/')))
625          {
626             http->path = strdup(p);
627             *p = '\0';
628             http->hostport = strdup(url);
629          }
630       }
631    }
632
633    freez(buf);
634
635
636    if (http->hostport == NULL)
637    {
638       free_http_request(http);
639       return;
640    }
641
642    buf = strdup(http->hostport);
643
644
645    /* check if url contains password */
646    n = ssplit(buf, "@", v, SZ(v), 1, 1);
647    if (n == 2)
648    {
649       char * newbuf = NULL;
650       newbuf = strdup(v[1]);
651       freez(buf);
652       buf = newbuf;
653    }
654
655    n = ssplit(buf, ":", v, SZ(v), 1, 1);
656
657    if (n == 1)
658    {
659       http->host = strdup(v[0]);
660       http->port = 80;
661    }
662
663    if (n == 2)
664    {
665       http->host = strdup(v[0]);
666       http->port = atoi(v[1]);
667    }
668
669    freez(buf);
670
671    if (http->host == NULL)
672    {
673       free_http_request(http);
674    }
675
676    if (http->path == NULL)
677    {
678       http->path = strdup("");
679    }
680
681 }
682
683
684 /* here begins the family of parser functions that reformat header lines */
685
686
687 /*********************************************************************
688  *
689  * Function    :  crumble
690  *
691  * Description :  This is called if a header matches a pattern to "crunch"
692  *
693  * Parameters  :
694  *          1  :  v = Pointer to parsers structure, which basically holds
695  *                headers (client or server) that we want to "crunch"
696  *          2  :  s = header (from sed) to "crunch"
697  *          3  :  csp = Current client state (buffers, headers, etc...)
698  *
699  * Returns     :  Always NULL.
700  *
701  *********************************************************************/
702 char *crumble(const struct parsers *v, char *s, struct client_state *csp)
703 {
704    log_error(LOG_LEVEL_HEADER, "crunch!");
705    return(NULL);
706
707 }
708
709
710 #ifdef PCRS
711
712 /*********************************************************************
713  *
714  * Function    :  content_type
715  *
716  * Description :  Is this a text/* or javascript MIME Type?
717  *
718  * Parameters  :
719  *          1  :  v = ignored
720  *          2  :  s = header string we are "considering"
721  *          3  :  csp = Current client state (buffers, headers, etc...)
722  *
723  * Returns     :  A duplicate string pointer to this header (ie. pass thru)
724  *
725  *********************************************************************/
726 char *content_type(const struct parsers *v, char *s, struct client_state *csp)
727 {
728    if (strstr (s, " text/") || strstr (s, "application/x-javascript"))
729       csp->is_text = 1;
730    else
731       csp->is_text = 0;
732
733    return(strdup(s));
734
735 }
736
737 #endif /* def PCRS */
738
739
740 /*********************************************************************
741  *
742  * Function    :  client_referrer
743  *
744  * Description :  Handle the "referer" config setting properly.
745  *                Called from `sed'.
746  *
747  * Parameters  :
748  *          1  :  v = ignored
749  *          2  :  s = header (from sed) to "crunch"
750  *          3  :  csp = Current client state (buffers, headers, etc...)
751  *
752  * Returns     :  NULL if crunched, or a malloc'ed string with the original
753  *                or modified header
754  *
755  *********************************************************************/
756 char *client_referrer(const struct parsers *v, char *s, struct client_state *csp)
757 {
758 #ifdef FORCE_LOAD
759    /* Since the referrer can include the prefix even
760     * even if the request itself is non-forced, we must
761     * clean it unconditionally 
762     */
763    strclean(s, FORCE_PREFIX);
764 #endif /* def FORCE_LOAD */
765
766    csp->referrer = strdup(s);
767
768    if (referrer == NULL)
769    {
770       log_error(LOG_LEVEL_HEADER, "crunch!");
771       return(NULL);
772    }
773
774    if (*referrer == '.')
775    {
776       return(strdup(s));
777    }
778
779    if (*referrer == '@')
780    {
781       if (csp->send_user_cookie)
782       {
783          return(strdup(s));
784       }
785       else
786       {
787          log_error(LOG_LEVEL_HEADER, "crunch!");
788          return(NULL);
789       }
790    }
791
792    /*
793     * New option § or L: Forge a referer as http://[hostname:port of REQUEST]/
794     * to fool stupid checks for in-site links
795     */
796
797    if (*referrer == '§' || *referrer == 'L')
798    {
799       if (csp->send_user_cookie)
800       {
801          return(strdup(s));
802       }
803       else
804       {
805          log_error(LOG_LEVEL_HEADER, "crunch+forge!");
806          s = strsav(NULL, "Referer: ");
807          s = strsav(s, "http://");
808          s = strsav(s, csp->http->hostport);
809          s = strsav(s, "/");
810          return(s);
811       }
812    }
813
814    log_error(LOG_LEVEL_HEADER, "modified");
815
816    s = strsav( NULL, "Referer: " );
817    s = strsav( s, referrer );
818    return(s);
819
820 }
821
822
823 /*********************************************************************
824  *
825  * Function    :  client_uagent
826  *
827  * Description :  Handle the "user-agent" config setting properly.
828  *                Called from `sed'.
829  *
830  * Parameters  :
831  *          1  :  v = ignored
832  *          2  :  s = header (from sed) to "crunch"
833  *          3  :  csp = Current client state (buffers, headers, etc...)
834  *
835  * Returns     :  A malloc'ed pointer to the default agent, or
836  *                a malloc'ed string pointer to this header (ie. pass thru).
837  *
838  *********************************************************************/
839 char *client_uagent(const struct parsers *v, char *s, struct client_state *csp)
840 {
841 #ifdef DETECT_MSIE_IMAGES
842    if (strstr (s, "MSIE "))
843    {
844       /* This is Microsoft Internet Explorer.
845        * Enable auto-detect.
846        */
847       csp->accept_types |= ACCEPT_TYPE_IS_MSIE;
848    }
849 #endif /* def DETECT_MSIE_IMAGES */
850
851    if (uagent == NULL)
852    {
853       log_error(LOG_LEVEL_HEADER, "default");
854       return(strdup(DEFAULT_USER_AGENT));
855    }
856
857    if (*uagent == '.')
858    {
859       return(strdup(s));
860    }
861
862    if (*uagent == '@')
863    {
864       if (csp->send_user_cookie)
865       {
866          return(strdup(s));
867       }
868       else
869       {
870          log_error(LOG_LEVEL_HEADER, "default");
871          return(strdup(DEFAULT_USER_AGENT));
872       }
873    }
874
875    log_error(LOG_LEVEL_HEADER, "modified");
876
877    s = strsav( NULL, "User-Agent: " );
878    s = strsav( s, uagent );
879    return(s);
880
881 }
882
883
884 /*********************************************************************
885  *
886  * Function    :  client_ua
887  *
888  * Description :  Handle "ua-" headers properly.  Called from `sed'.
889  *
890  * Parameters  :
891  *          1  :  v = ignored
892  *          2  :  s = header (from sed) to "crunch"
893  *          3  :  csp = Current client state (buffers, headers, etc...)
894  *
895  * Returns     :  NULL if crunched, or a malloc'ed string to original header
896  *
897  *********************************************************************/
898 char *client_ua(const struct parsers *v, char *s, struct client_state *csp)
899 {
900    if (uagent == NULL)
901    {
902       log_error(LOG_LEVEL_HEADER, "crunch!");
903       return(NULL);
904    }
905
906    if (*uagent == '.')
907    {
908       return(strdup(s));
909    }
910
911    if (*uagent == '@')
912    {
913       if (csp->send_user_cookie)
914       {
915          return(strdup(s));
916       }
917       else
918       {
919          log_error(LOG_LEVEL_HEADER, "crunch!");
920          return(NULL);
921       }
922    }
923
924    log_error(LOG_LEVEL_HEADER, "crunch!");
925    return(NULL);
926
927 }
928
929
930 /*********************************************************************
931  *
932  * Function    :  client_from
933  *
934  * Description :  Handle the "from" config setting properly.
935  *                Called from `sed'.
936  *
937  * Parameters  :
938  *          1  :  v = ignored
939  *          2  :  s = header (from sed) to "crunch"
940  *          3  :  csp = Current client state (buffers, headers, etc...)
941  *
942  * Returns     :  NULL if crunched, or a malloc'ed string to
943  *                modified/original header.
944  *
945  *********************************************************************/
946 char *client_from(const struct parsers *v, char *s, struct client_state *csp)
947 {
948    /* if not set, zap it */
949    if (from == NULL)
950    {
951       log_error(LOG_LEVEL_HEADER, "crunch!");
952       return(NULL);
953    }
954
955    if (*from == '.')
956    {
957       return(strdup(s));
958    }
959
960    log_error(LOG_LEVEL_HEADER, " modified");
961
962    s = strsav( NULL, "From: " );
963    s = strsav( s, from );
964    return(s);
965
966 }
967
968
969 /*********************************************************************
970  *
971  * Function    :  client_send_cookie
972  *
973  * Description :  Handle the "cookie" header properly.  Called from `sed'.
974  *                If cookie is accepted, add it to the cookie_list,
975  *                else we crunch it.  Mmmmmmmmmmm ... cookie ......
976  *
977  * Parameters  :
978  *          1  :  v = pattern of cookie `sed' found matching
979  *          2  :  s = header (from sed) to "crunch"
980  *          3  :  csp = Current client state (buffers, headers, etc...)
981  *
982  * Returns     :  Always NULL.
983  *
984  *********************************************************************/
985 char *client_send_cookie(const struct parsers *v, char *s, struct client_state *csp)
986 {
987    if (csp->send_user_cookie)
988    {
989       enlist(csp->cookie_list, s + v->len + 1);
990    }
991    else
992    {
993       log_error(LOG_LEVEL_HEADER, " crunch!");
994    }
995
996    /*
997     * Always return NULL here.  The cookie header
998     * will be sent at the end of the header.
999     */
1000    return(NULL);
1001
1002 }
1003
1004
1005 /*********************************************************************
1006  *
1007  * Function    :  client_x_forwarded
1008  *
1009  * Description :  Handle the "x-forwarded-for" config setting properly,
1010  *                also used in the add_client_headers list.  Called from `sed'.
1011  *
1012  * Parameters  :
1013  *          1  :  v = ignored
1014  *          2  :  s = header (from sed) to "crunch"
1015  *          3  :  csp = Current client state (buffers, headers, etc...)
1016  *
1017  * Returns     :  Always NULL.
1018  *
1019  *********************************************************************/
1020 char *client_x_forwarded(const struct parsers *v, char *s, struct client_state *csp)
1021 {
1022    if (add_forwarded)
1023    {
1024       csp->x_forwarded = strdup(s);
1025    }
1026
1027    /*
1028     * Always return NULL, since this information
1029     * will be sent at the end of the header.
1030     */
1031
1032    return(NULL);
1033
1034 }
1035
1036 #if defined(DETECT_MSIE_IMAGES)
1037 /*********************************************************************
1038  *
1039  * Function    :  client_accept
1040  *
1041  * Description :  Detect whether the client wants HTML or an image.
1042  *                Clients do not always make this information available
1043  *                in a sane way.  Always passes the header through
1044  *                the proxy unchanged.
1045  *
1046  * Parameters  :
1047  *          1  :  v = Ignored.
1048  *          2  :  s = Header string.  Null terminated.
1049  *          3  :  csp = Current client state (buffers, headers, etc...)
1050  *
1051  * Returns     :  Duplicate of argument s.
1052  *
1053  *********************************************************************/
1054 char *client_accept(const struct parsers *v, char *s, struct client_state *csp)
1055 {
1056 #ifdef DETECT_MSIE_IMAGES
1057    if (strstr (s, "image/gif"))
1058    {
1059       /* Client will accept HTML.  If this seems counterintuitive,
1060        * blame Microsoft. 
1061        */
1062       csp->accept_types |= ACCEPT_TYPE_MSIE_HTML;
1063    }
1064    else
1065    {
1066       csp->accept_types |= ACCEPT_TYPE_MSIE_IMAGE;
1067    }
1068 #endif /* def DETECT_MSIE_IMAGES */
1069
1070    return(strdup(s));
1071
1072 }
1073 #endif /* defined(DETECT_MSIE_IMAGES) */
1074
1075
1076
1077 /* the following functions add headers directly to the header list */
1078
1079
1080 /*********************************************************************
1081  *
1082  * Function    :  client_cookie_adder
1083  *
1084  * Description :  Used in the add_client_headers list.  Called from `sed'.
1085  *
1086  * Parameters  :
1087  *          1  :  csp = Current client state (buffers, headers, etc...)
1088  *
1089  * Returns     :  N/A
1090  *
1091  *********************************************************************/
1092 void client_cookie_adder(struct client_state *csp)
1093 {
1094    struct list *l;
1095    char *tmp = NULL;
1096    char *e;
1097
1098    for (l = csp->cookie_list->next; l ; l = l->next)
1099    {
1100       if (tmp)
1101       {
1102          tmp = strsav(tmp, "; ");
1103       }
1104       tmp = strsav(tmp, l->str);
1105    }
1106
1107    for (l = wafer_list->next;  l ; l = l->next)
1108    {
1109       if (tmp)
1110       {
1111          tmp = strsav(tmp, "; ");
1112       }
1113
1114       if ((e = cookie_encode(l->str)))
1115       {
1116          tmp = strsav(tmp, e);
1117          freez(e);
1118       }
1119    }
1120
1121    if (tmp)
1122    {
1123       char *ret;
1124
1125       ret = strdup("Cookie: ");
1126       ret = strsav(ret, tmp);
1127       log_error(LOG_LEVEL_HEADER, "addh: %s", ret);
1128       enlist(csp->headers, ret);
1129       freez(tmp);
1130       freez(ret);
1131    }
1132
1133 }
1134
1135
1136 /*********************************************************************
1137  *
1138  * Function    :  client_xtra_adder
1139  *
1140  * Description :  Used in the add_client_headers list.  Called from `sed'.
1141  *
1142  * Parameters  :
1143  *          1  :  csp = Current client state (buffers, headers, etc...)
1144  *
1145  * Returns     :  N/A
1146  *
1147  *********************************************************************/
1148 void client_xtra_adder(struct client_state *csp)
1149 {
1150    struct list *l;
1151
1152    for (l = xtra_list->next; l ; l = l->next)
1153    {
1154       log_error(LOG_LEVEL_HEADER, "addh: %s", l->str);
1155       enlist(csp->headers, l->str);
1156    }
1157
1158 }
1159
1160
1161 /*********************************************************************
1162  *
1163  * Function    :  client_x_forwarded_adder
1164  *
1165  * Description :  Used in the add_client_headers list.  Called from `sed'.
1166  *
1167  * Parameters  :
1168  *          1  :  csp = Current client state (buffers, headers, etc...)
1169  *
1170  * Returns     :  N/A
1171  *
1172  *********************************************************************/
1173 void client_x_forwarded_adder(struct client_state *csp)
1174 {
1175    char *p = NULL;
1176
1177    if (add_forwarded == 0) return;
1178
1179    if (csp->x_forwarded)
1180    {
1181       p = strsav(p, csp->x_forwarded);
1182       p = strsav(p, ", ");
1183       p = strsav(p, csp->ip_addr_str);
1184    }
1185    else
1186    {
1187       p = strsav(p, "X-Forwarded-For: ");
1188       p = strsav(p, csp->ip_addr_str);
1189    }
1190
1191    log_error(LOG_LEVEL_HEADER, "addh: %s", p);
1192    enlist(csp->headers, p);
1193
1194 }
1195
1196
1197 /*********************************************************************
1198  *
1199  * Function    :  server_set_cookie
1200  *
1201  * Description :  Handle the server "cookie" header properly.
1202  *                Log cookie to the jar file.  Then "crunch" it,
1203  *                or accept it.  Called from `sed'.
1204  *
1205  * Parameters  :
1206  *          1  :  v = parser pattern that matched this header
1207  *          2  :  s = header that matched this pattern
1208  *          3  :  csp = Current client state (buffers, headers, etc...)
1209  *
1210  * Returns     :  `crumble' or a newly malloc'ed string.
1211  *
1212  *********************************************************************/
1213 char *server_set_cookie(const struct parsers *v, char *s, struct client_state *csp)
1214 {
1215 #ifdef JAR_FILES
1216    if (jar)
1217    {
1218       fprintf(jar, "%s\t%s\n", csp->http->host, (s + v->len + 1));
1219    }
1220 #endif /* def JAR_FILES */
1221
1222    if (csp->accept_server_cookie == 0)
1223    {
1224       return(crumble(v, s, csp));
1225    }
1226
1227    return(strdup(s));
1228
1229 }
1230
1231
1232 #ifdef FORCE_LOAD
1233 /*********************************************************************
1234  *
1235  * Function    :  client_host
1236  *
1237  * Description :  Clean the FORCE_PREFIX out of the 'host' http
1238  *                header, if we use force
1239  *
1240  * Parameters  :
1241  *          1  :  v = ignored
1242  *          2  :  s = header (from sed) to clean
1243  *          3  :  csp = Current client state (buffers, headers, etc...)
1244  *
1245  * Returns     :  A malloc'ed pointer to the cleaned host header 
1246  *
1247  *********************************************************************/
1248 char *client_host(const struct parsers *v, char *s, struct client_state *csp)
1249 {
1250    char *cleanhost = strdup(s);
1251  
1252    if(csp->force)
1253       strclean(cleanhost, FORCE_PREFIX);
1254  
1255    return(cleanhost);
1256 }
1257 #endif /* def FORCE_LOAD */
1258  
1259  
1260 #ifdef FORCE_LOAD 
1261 /*********************************************************************
1262  *
1263  * Function    :  strclean
1264  *
1265  * Description :  In-Situ-Eliminate all occurances of substring in 
1266  *                string
1267  *
1268  * Parameters  :
1269  *          1  :  string = string to clean
1270  *          2  :  substring = substring to eliminate
1271  *
1272  * Returns     :  Number of eliminations
1273  *
1274  *********************************************************************/
1275 int strclean(const char *string, const char *substring)
1276 {
1277    int hits = 0, len = strlen(substring);
1278    char *pos, *p;
1279
1280    while((pos = strstr(string, substring)))
1281    {
1282       p = pos + len;
1283       do
1284       {
1285          *(p - len) = *p; 
1286       }
1287       while (*p++ != '\0');
1288
1289       hits++;
1290    }
1291
1292    return(hits);
1293 }
1294 #endif /* def FORCE_LOAD */
1295
1296
1297 /*
1298   Local Variables:
1299   tab-width: 3
1300   end:
1301 */