home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 April / PCWorld_2001-04_cd.bin / Software / TemaCD / junkbust / linux / parsers.c < prev    next >
C/C++ Source or Header  |  1998-10-30  |  13KB  |  640 lines

  1. char *parsers_rcs = "$Id: parsers.c,v 1.26 1998/10/23 01:54:12 ACJC Exp $";
  2. /* Written and copyright 1997 Anonymous Coders and Junkbusters Corporation.
  3.  * Distributed under the GNU General Public License; see the README file.
  4.  * This code comes with NO WARRANTY. http://www.junkbusters.com/ht/en/gpl.html
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <sys/types.h>
  9. #include <stdlib.h>
  10. #include <ctype.h>
  11. #include <string.h>
  12.  
  13. #ifndef _WIN32
  14. #include <unistd.h>
  15. #endif
  16.  
  17. #ifdef REGEX
  18. #include <gnu_regex.h>
  19. #endif
  20.  
  21. #include "jcc.h"
  22.  
  23. struct parsers client_patterns[] = {
  24.     { "referer:", /* sic */     8,    client_referrer        },
  25.     { "user-agent:",    11,    client_uagent        },
  26.     { "ua-",         3,    client_ua        },
  27.     { "from:",         5,    client_from        },
  28.     { "cookie:",         7,    client_send_cookie    },
  29.     { "x-forwarded-for:",    16,    client_x_forwarded    },
  30.     { "proxy-connection:",    17,    crumble            },
  31. /*    { "if-modified-since:", 18,    crumble            }, */
  32.     { NULL,             0,    NULL            }
  33. };
  34.  
  35. struct interceptors intercept_patterns[] = {
  36.     { "show-proxy-args",    14,    show_proxy_args        },
  37.     { "ij-blocked-url",    14,    ij_blocked_url        },
  38.     { "ij-untrusted-url",    14,    ij_untrusted_url    },
  39.     { NULL,             0,    NULL            }
  40. };
  41.  
  42. struct parsers server_patterns[] = {
  43.     { "set-cookie:",    11,    server_set_cookie    },
  44.     { "connection:",    11,    crumble            },
  45.     { NULL,             0,    NULL            }
  46. };
  47.  
  48. void (*add_client_headers[])() = {
  49.     client_cookie_adder,
  50.     client_x_forwarded_adder,
  51.     client_xtra_adder,
  52.     NULL
  53. };
  54.  
  55. void (*add_server_headers[])() = {
  56.     NULL
  57. };
  58.  
  59. struct parsers *
  60. match(char *buf, struct parsers *pats)
  61. {
  62.     struct parsers *v;
  63.  
  64.     if(buf == NULL) {
  65.         /* hit me */
  66.         fprintf(logfp, "bingo!\n");
  67.         return(NULL);
  68.     }
  69.  
  70.     for(v = pats; v->str ; v++) {
  71.         if(strncmpic(buf, v->str, v->len) == 0) {
  72.             return(v);
  73.         }
  74.     }
  75.     return(NULL);
  76. }
  77.  
  78. int
  79. flush_socket(int fd, struct client_state *csp)
  80. {
  81.     struct iob *iob = csp->iob;
  82.     int n = iob->eod - iob->cur;
  83.  
  84.     if(n <= 0) return(0);
  85.  
  86.     n = write_socket(fd, iob->cur, n);
  87.  
  88.     iob->eod = iob->cur = iob->buf;
  89.  
  90.     return(n);
  91. }
  92.  
  93. int
  94. add_to_iob(struct client_state *csp, char *buf, int n)
  95. {
  96.     struct iob *iob = csp->iob;
  97.     int have, need;
  98.     char *p;
  99.  
  100.     have = iob->eod - iob->cur;
  101.  
  102.     if(n <= 0) return(have);
  103.  
  104.     need = have + n;
  105.  
  106.     if((p = malloc(need + 1)) == NULL) {
  107.             fprintf(logfp, "%s: malloc() iob failed\n", prog);
  108.             fperror(logfp, "");
  109.             return(-1);
  110.     }
  111.  
  112.     if(have) {
  113.         /* there is something in the buffer - save it */
  114.         memcpy(p, iob->cur, have);
  115.  
  116.         /* replace the buffer with the new space */
  117.         freez(iob->buf);
  118.         iob->buf = p;
  119.  
  120.         /* point to the end of the data */
  121.         p += have;
  122.     } else {
  123.         /* the buffer is empty, free it and reinitialize */
  124.         freez(iob->buf);
  125.         iob->buf = p;
  126.     }
  127.  
  128.     /* copy the new data into the iob buffer */
  129.     memcpy(p, buf, n);
  130.  
  131.     /* point to the end of the data */
  132.      p +=   n ;
  133.  
  134.     /* null terminate == cheap insurance */
  135.     *p  = '\0';
  136.  
  137.     /* set the pointers to the new values */
  138.     iob->cur = iob->buf;
  139.     iob->eod = p;
  140.  
  141.     return(need);
  142. }
  143.  
  144. /* this (odd) routine will parse the csp->iob and return one of the following:
  145.  *
  146.  * 1) a pointer to a dynamically allocated string that contains a header line
  147.  * 2) NULL  indicating that the end of the header was reached
  148.  * 3) ""    indicating that the end of the iob was reached before finding
  149.  *          a complete header line.
  150.  */
  151.  
  152. char *
  153. get_header(struct client_state *csp)
  154. {
  155.     struct iob *iob = csp->iob;
  156.     char *p, *q, *ret;
  157.  
  158.     if((iob->cur == NULL)
  159.     || ((p = strchr(iob->cur, '\n')) == NULL)) {
  160.         return("");    /* couldn't find a complete header */
  161.     }
  162.  
  163.     *p = '\0';
  164.  
  165.     ret = strdup(iob->cur);
  166.  
  167.     iob->cur = p+1;
  168.  
  169.     if((q = strchr(ret, '\r'))) *q = '\0';
  170.  
  171.     /* is this a blank linke (i.e. the end of the header) ? */
  172.     if(*ret == '\0') {
  173.         freez(ret);
  174.         return(NULL);
  175.     }
  176.  
  177.     return(ret);
  178. }
  179.  
  180. /* h = pointer to list 'dummy' header
  181.  * s = string to add to the list
  182.  */
  183.  
  184. void
  185. enlist(struct list *h, char *s)
  186. {
  187.     struct list *n = (struct list *)malloc(sizeof(*n));
  188.     struct list *l;
  189.  
  190.     if(n) {
  191.         n->str  = strdup(s);
  192.         n->next = NULL;
  193.  
  194.         if((l = h->last)) {
  195.             l->next = n;
  196.         } else {
  197.             h->next = n;
  198.         }
  199.  
  200.         h->last = n;
  201.     }
  202. }
  203.  
  204. void
  205. destroy_list(struct list *h)
  206. {
  207.     struct list *p, *n;
  208.  
  209.     for(p = h->next; p ; p = n) {
  210.  
  211.         n = p->next;
  212.  
  213.         freez(p->str);
  214.  
  215.         freez(p);
  216.     }
  217.  
  218.     memset(h, '\0', sizeof(*h));
  219. }
  220.  
  221. char *
  222. list_to_text(struct list *h)
  223. {
  224.     struct list *p;
  225.     char *ret = NULL;
  226.     char *s;
  227.     int size;
  228.  
  229.     size = 0;
  230.  
  231.     for(p = h->next; p ; p = p->next) {
  232.         if(p->str) {
  233.             size += strlen(p->str) + 2;
  234.         }
  235.     }
  236.  
  237.     if((ret = malloc(size + 1)) == NULL) {
  238.         return(NULL);
  239.     }
  240.  
  241.     ret[size] = '\0';
  242.  
  243.     s = ret;
  244.  
  245.     for(p = h->next; p ; p = p->next) {
  246.         if(p->str) {
  247.             strcpy(s, p->str);
  248.             s += strlen(s);
  249.             *s++ = '\r'; *s++ = '\n';
  250.         }
  251.     }
  252.  
  253.     return(ret);
  254. }
  255.  
  256. /* sed(): add, delete or modify lines in the HTTP header streams.
  257.  * on entry, it receives a linked list of headers space that was
  258.  * allocated dynamically (both the list nodes and the header contents).
  259.  *
  260.  * it returns a single pointer to a fully formed header.
  261.  *
  262.  * as a side effect it frees the space used by the original header lines.
  263.  *
  264.  */
  265.  
  266. char *
  267. sed(pats, more_headers, csp)
  268. struct parsers pats[];
  269. int (*more_headers[])();
  270. struct client_state *csp;
  271. {
  272.     struct list *p;
  273.     struct parsers *v;
  274.     char *hdr;
  275.     int (**f)();
  276.  
  277.     for(p = csp->headers->next; p ; p = p->next) {
  278.  
  279.         if(DEBUG(HDR)) fprintf(logfp, "scan: %s", p->str);
  280.  
  281.         if((v = match(p->str, pats))) {
  282.             hdr = v->parser(v, p->str, csp);
  283.             freez(p->str);
  284.             p->str = hdr;
  285.         }
  286.  
  287.         if(DEBUG(HDR)) fprintf(logfp, "\n");
  288.     }
  289.  
  290.     /* place any additional headers on the csp->headers list */
  291.     for(f = more_headers; *f ; f++) {
  292.         (*f)(csp);
  293.     }
  294.  
  295.     /* add the blank line at the end of the header */
  296.     enlist(csp->headers, "");
  297.  
  298.     hdr = list_to_text(csp->headers);
  299.  
  300.     return(hdr);
  301. }
  302.  
  303. void
  304. free_http_request(struct http_request *http)
  305. {
  306.     freez(http->cmd);
  307.     freez(http->gpc);
  308.     freez(http->host);
  309.     freez(http->hostport);
  310.     freez(http->path);
  311.     freez(http->ver);
  312. }
  313.  
  314. /* parse out the host and port from the URL */
  315.  
  316. void
  317. parse_http_request(char *req, struct http_request *http, struct client_state *csp)
  318. {
  319.     char *buf, *v[10], *url, *p;
  320.     int n;
  321.  
  322.     memset(http, '\0', sizeof(*http));
  323.  
  324.     http->cmd = strdup(req);
  325.  
  326.     buf = strdup(req);
  327.  
  328.     n = ssplit(buf, " \r\n", v, SZ(v), 1, 1);
  329.  
  330.     if(n == 3) {
  331.  
  332.         /* this could be a CONNECT request */
  333.         if(strcmpic(v[0], "connect") == 0) {
  334.             http->ssl      = 1;
  335.             http->gpc      = strdup(v[0]);
  336.             http->hostport = strdup(v[1]);
  337.             http->ver      = strdup(v[2]);
  338.         }
  339.  
  340.         /* or it could be a GET or a POST */
  341.         if((strcmpic(v[0], "get")  == 0)
  342.         || (strcmpic(v[0], "head") == 0)
  343.         || (strcmpic(v[0], "post") == 0)) {
  344.  
  345.             http->ssl      = 0;
  346.             http->gpc      = strdup(v[0]);
  347.             url            =        v[1] ;
  348.             http->ver      = strdup(v[2]);
  349.  
  350.             if(strncmpic(url, "http://",  7) == 0) {
  351.                 url += 7;
  352.             } else if(strncmpic(url, "https://", 8) == 0) {
  353.                 url += 8;
  354.             } else {
  355.                 url = NULL;
  356.             }
  357.  
  358.             if(url && (p = strchr(url, '/'))) {
  359.                 http->path = strdup(p);
  360.  
  361.                 *p = '\0';
  362.  
  363.                 http->hostport = strdup(url);
  364.             }
  365.         }
  366.     }
  367.  
  368.     freez(buf);
  369.  
  370.  
  371.     if(http->hostport == NULL) {
  372.         free_http_request(http);
  373.         return;
  374.     }
  375.  
  376.     buf = strdup(http->hostport);
  377.  
  378.     n = ssplit(buf, ":", v, SZ(v), 1, 1);
  379.  
  380.     if(n == 1) {
  381.         http->host = strdup(v[0]);
  382.         http->port = 80;
  383.     }
  384.  
  385.     if(n == 2) {
  386.         http->host = strdup(v[0]);
  387.         http->port = atoi(v[1]);
  388.     }
  389.  
  390.     freez(buf);
  391.  
  392.     if(http->host == NULL) {
  393.         free_http_request(http);
  394.     }
  395.  
  396.     if(http->path == NULL) {
  397.         http->path = strdup("");
  398.     }
  399. }
  400.  
  401. /* here begins the family of parser functions that reformat header lines */
  402.  
  403. char *crumble(struct parsers *v, char *s, struct client_state *csp)
  404. {
  405.     if(DEBUG(HDR)) fprintf(logfp, " crunch!");
  406.     return(NULL);
  407. }
  408.  
  409. char *client_referrer(struct parsers *v, char *s, struct client_state *csp)
  410. {
  411.     csp->referrer = strdup(s);
  412.  
  413.     if(referrer == NULL) {
  414.         if(DEBUG(HDR)) fprintf(logfp, " crunch!");
  415.         return(NULL);
  416.     }
  417.  
  418.     if(*referrer == '.') {
  419.         return(strdup(s));
  420.     }
  421.  
  422.     if(*referrer == '@') {
  423.         if(csp->send_user_cookie) {
  424.             return(strdup(s));
  425.         } else {
  426.             if(DEBUG(HDR)) fprintf(logfp, " crunch!");
  427.             return(NULL);
  428.         }
  429.     }
  430.  
  431.     if(DEBUG(HDR)) fprintf(logfp, " modified");
  432.  
  433.     s = strsav(NULL, "Referer: ");
  434.     s = strsav(s,     referrer  );
  435.     return(s);
  436. }
  437.  
  438. char *client_uagent(struct parsers *v, char *s, struct client_state *csp)
  439. {
  440.     if(uagent == NULL) {
  441.         if(DEBUG(HDR)) fprintf(logfp, " default");
  442.         return(strdup(DEFAULT_USER_AGENT));
  443.     }
  444.  
  445.     if(*uagent == '.') {
  446.         return(strdup(s));
  447.     }
  448.  
  449.     if(*uagent == '@') {
  450.         if(csp->send_user_cookie) {
  451.             return(strdup(s));
  452.         } else {
  453.             if(DEBUG(HDR)) fprintf(logfp, " default");
  454.             return(strdup(DEFAULT_USER_AGENT));
  455.         }
  456.     }
  457.  
  458.     if(DEBUG(HDR)) fprintf(logfp, " modified");
  459.  
  460.     s = strsav(NULL, "User-Agent: ");
  461.     s = strsav(s,     uagent   );
  462.     return(s);
  463. }
  464.  
  465. char *client_ua(struct parsers *v, char *s, struct client_state *csp)
  466. {
  467.     if(uagent == NULL) {
  468.         if(DEBUG(HDR)) fprintf(logfp, " crunch!");
  469.         return(NULL);
  470.     }
  471.  
  472.     if(*uagent == '.') {
  473.         return(strdup(s));
  474.     }
  475.  
  476.     if(*uagent == '@') {
  477.         if(csp->send_user_cookie) {
  478.             return(strdup(s));
  479.         } else {
  480.             if(DEBUG(HDR)) fprintf(logfp, " crunch!");
  481.             return(NULL);
  482.         }
  483.     }
  484.  
  485.     if(DEBUG(HDR)) fprintf(logfp, " crunch!");
  486.     return(NULL);
  487. }
  488.  
  489. char *client_from(struct parsers *v, char *s, struct client_state *csp)
  490. {
  491.     /* if not set, zap it */
  492.     if(from == NULL) {
  493.         if(DEBUG(HDR)) fprintf(logfp, " crunch!");
  494.         return(NULL);
  495.     }
  496.  
  497.     if(*from == '.') {
  498.         return(strdup(s));
  499.     }
  500.  
  501.     if(DEBUG(HDR)) fprintf(logfp, " modified");
  502.  
  503.     s = strsav(NULL, "From: ");
  504.     s = strsav(s,     from   );
  505.     return(s);
  506. }
  507.  
  508. char *client_send_cookie(struct parsers *v, char *s, struct client_state *csp)
  509. {
  510.     if(csp->send_user_cookie) {
  511.         enlist(csp->cookie_list, s + v->len + 1);
  512.     } else {
  513.         if(DEBUG(HDR)) fprintf(logfp, " crunch!");
  514.     }
  515.  
  516.     /* always return NULL here.  the cookie header will be sent
  517.      * at the end of the header.
  518.      */
  519.     return(NULL);
  520. }
  521.  
  522. char *client_x_forwarded(struct parsers *v, char *s, struct client_state *csp)
  523. {
  524.     if(add_forwarded) {
  525.         csp->x_forwarded = strdup(s);
  526.     }
  527.  
  528.     /* always return NULL, since this information
  529.      * will be sent at the end of the header.
  530.      */
  531.  
  532.     return(NULL);
  533. }
  534.  
  535. /* the following functions add headers directly to the header list */
  536. void client_cookie_adder(struct client_state *csp)
  537. {
  538.     struct list *l;
  539.     char *tmp = NULL;
  540.     char *e;
  541.  
  542.     for(l = csp->cookie_list->next; l ; l = l->next) {
  543.         if(tmp) {
  544.             tmp = strsav(tmp, "; ");
  545.         }
  546.         tmp = strsav(tmp, l->str);
  547.     }
  548.  
  549.     for(l = wafer_list->next;  l ; l = l->next) {
  550.         if(tmp) {
  551.             tmp = strsav(tmp, "; ");
  552.         }
  553.  
  554.         if((e = url_encode(cookie_code_map, l->str))) {
  555.             tmp = strsav(tmp, e);
  556.             freez(e);
  557.         }
  558.     }
  559.  
  560.     if(tmp) {
  561.         char *ret;
  562.  
  563.         ret = strdup("Cookie: ");
  564.         ret = strsav(ret, tmp);
  565.         if(DEBUG(HDR)) fprintf(logfp, "addh: %s\r\n", ret);
  566.         enlist(csp->headers, ret);
  567.         freez(tmp);
  568.         freez(ret);
  569.     }
  570. }
  571.  
  572. void client_xtra_adder(struct client_state *csp)
  573. {
  574.     struct list *l;
  575.  
  576.     for(l = xtra_list->next; l ; l = l->next) {
  577.         if(DEBUG(HDR)) fprintf(logfp, "addh: %s\r\n", l->str);
  578.         enlist(csp->headers, l->str);
  579.     }
  580. }
  581.  
  582. void client_x_forwarded_adder(struct client_state *csp)
  583. {
  584.     char *p = NULL;
  585.  
  586.     if(add_forwarded == 0) return;
  587.  
  588.     if(csp->x_forwarded) {
  589.         p = strsav(p, csp->x_forwarded);
  590.         p = strsav(p, ", ");
  591.         p = strsav(p, csp->ip_addr_str);
  592.     } else {
  593.         p = strsav(p, "X-Forwarded-For: ");
  594.         p = strsav(p, csp->ip_addr_str);
  595.     }
  596.     if(DEBUG(HDR)) fprintf(logfp, "addh: %s\r\n", p);
  597.     enlist(csp->headers, p);
  598. }
  599.  
  600. char *server_set_cookie(struct parsers *v, char *s, struct client_state *csp)
  601. {
  602.     if(jar) fprintf(jar, "%s\t%s\n", csp->http->host, (s + v->len + 1));
  603.  
  604.     if(csp->accept_server_cookie == 0) return(crumble(v, s, csp));
  605.  
  606.     return(strdup(s));
  607. }
  608.  
  609. /* case insensitive string comparison */
  610. int strcmpic(char *s1, char *s2)
  611. {
  612.     while(*s1 && *s2) {
  613.         if((        *s1  !=         *s2)
  614.         && (tolower(*s1) != tolower(*s2))) {
  615.             break;
  616.         }
  617.         s1++, s2++;
  618.     }
  619.     return(tolower(*s1) - tolower(*s2));
  620. }
  621.  
  622. int strncmpic(char *s1, char *s2, size_t n)
  623. {
  624.     if(n <= 0) return(0);
  625.  
  626.     while(*s1 && *s2) {
  627.  
  628.  
  629.         if((        *s1  !=         *s2)
  630.         && (tolower(*s1) != tolower(*s2))) {
  631.             break;
  632.         }
  633.  
  634.         if(--n <= 0) break;
  635.  
  636.         s1++, s2++;
  637.     }
  638.     return(tolower(*s1) - tolower(*s2));
  639. }
  640.