home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / ONLINE / IJB20OS2 / SOURCE / LOADERS.C < prev    next >
C/C++ Source or Header  |  1997-09-16  |  24KB  |  1,219 lines

  1. char *loaders_rcs = "$Id: loaders.c,v 1.17 1997/09/08 14:05:05 ACJC Exp $";
  2. /* Written and copyright by the Anonymous Coders and Junkbusters Corporation.
  3.  * Will be made available under the GNU General Public License.
  4.  * This software comes with NO WARRANTY.
  5.  */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <sys/types.h>
  10. #include <string.h>
  11. #include <malloc.h>
  12. #include <errno.h>
  13. #include <sys/stat.h>
  14. #include <ctype.h>
  15.  
  16. #ifndef _WIN32
  17. #include <unistd.h>
  18. #endif
  19.  
  20. #ifdef REGEX
  21. #include <gnu_regex.h>
  22. #endif
  23.  
  24. #include "jcc.h"
  25.  
  26.  
  27. /* sweep() is basically a mark and sweep garbage collector.
  28.  * it is run (by the parent thread) every once in a while to reclaim memory.
  29.  *
  30.  * it uses a mark and sweep strategy:
  31.  *   1) mark all files as inactive
  32.  *
  33.  *   2) check with each client:
  34.  *       if it is active,   mark its files as active
  35.  *       if it is inactive, free its resources
  36.  *
  37.  *   3) free the resources of all of the files that
  38.  *      are still marked as inactive (and are obsolete).
  39.  *
  40.  *   N.B. files that are not obsolete don't have an unloader defined.
  41.  */
  42.  
  43. void
  44. sweep()
  45. {
  46.     struct file_list *fl, *nfl;
  47.     struct client_state *csp, *ncsp;
  48.  
  49.     /* clear all of the file's active flags */
  50.     for(fl = files->next; fl ; fl = fl->next) {
  51.         fl->active = 0;
  52.     }
  53.  
  54.     for(csp = clients; csp && (ncsp = csp->next) ; csp = csp->next) {
  55.         if(ncsp->active) {
  56.             /* mark this client's files as active */
  57.             if(ncsp->blist) ncsp->blist->active = 1;
  58.             if(ncsp->clist) ncsp->clist->active = 1;
  59.             if(ncsp->tlist) ncsp->tlist->active = 1;
  60.         } else {
  61.             /* this client one is not active,
  62.              * release its resources
  63.              */
  64.             csp->next = ncsp->next;
  65.  
  66.             freez(ncsp->ip_addr_str);
  67.             freez(ncsp->referrer);
  68.             freez(ncsp->x_forwarded);
  69.             freez(ncsp->ip_addr_str);
  70.             freez(ncsp->iob->buf);
  71.  
  72.             free_http_request(ncsp->http);
  73.  
  74.             destroy_list(ncsp->headers);
  75.             destroy_list(ncsp->cookie_list);
  76.  
  77.             freez(ncsp);
  78.         }
  79.     }
  80.  
  81.     for(fl = files; fl && (nfl = fl->next) ; fl = fl->next) {
  82.         if(nfl->active == 0) {
  83.             if(nfl->unloader) {
  84.                 fl->next = nfl->next;
  85.  
  86.                 (nfl->unloader)(nfl->f);
  87.  
  88.                 freez(nfl->proxy_args);
  89.  
  90.                 freez(nfl);
  91.             }
  92.         }
  93.     }
  94. }
  95.  
  96. void
  97. unload_url(struct url_spec *url)
  98. {
  99.     if(url == NULL) return;
  100.  
  101.     freez(url->spec);
  102.     freez(url->domain);
  103.     freez(url->dbuf);
  104.     freez(url->dvec);
  105.     freez(url->path);
  106. #ifdef REGEX
  107.     if(url->preg) {
  108.         regfree(url->preg);
  109.         freez(url->preg);
  110.     }
  111. #endif
  112. }
  113.  
  114. void
  115. unload_blockfile(struct block_spec *b)
  116. {
  117.     if(b == NULL) return;
  118.  
  119.     unload_blockfile(b->next);
  120.  
  121.     unload_url(b->url);
  122.  
  123.     freez(b);
  124. }
  125.  
  126. void
  127. unload_cookiefile(struct cookie_spec *b)
  128. {
  129.     if(b == NULL) return;
  130.  
  131.     unload_cookiefile(b->next);
  132.  
  133.     unload_url(b->url);
  134.  
  135.     freez(b);
  136. }
  137.  
  138. void
  139. unload_trustfile(struct block_spec *b)
  140. {
  141.     if(b == NULL) return;
  142.  
  143.     unload_trustfile(b->next);
  144.  
  145.     unload_url(b->url);
  146.  
  147.     freez(b);
  148. }
  149.  
  150. void
  151. unload_forwardfile(struct forward_spec *b)
  152. {
  153.     if(b == NULL) return;
  154.  
  155.     unload_forwardfile(b->next);
  156.  
  157.     unload_url(b->url);
  158.  
  159.     freez(b->gw->gateway_host);
  160.     freez(b->gw->forward_host);
  161.  
  162.     freez(b);
  163. }
  164.  
  165. static struct file_list *current_blockfile;
  166. static struct file_list *current_cookiefile;
  167. static struct file_list *current_trustfile;
  168. static struct file_list *current_forwardfile;
  169.  
  170. int
  171. load_blockfile(struct client_state *csp)
  172. {
  173.     FILE *fp;
  174.  
  175.     struct block_spec *b, *bl;
  176.     char  buf[BUFSIZ], *p, *q;
  177.     int port, reject;
  178.     struct file_list *fs;
  179.     static struct stat prev[1], curr[1];
  180.     struct url_spec url[1];
  181.  
  182.     if(stat(blockfile, curr) < 0) {
  183.         goto load_blockfile_error;
  184.     }
  185.  
  186.     if(current_blockfile && (prev->st_mtime == curr->st_mtime)) {
  187.         csp->blist = current_blockfile;
  188.         return(0);
  189.     }
  190.  
  191.     fs = (struct file_list  *) zalloc(sizeof(*fs));
  192.     bl = (struct block_spec *) zalloc(sizeof(*bl));
  193.  
  194.     if((fs == NULL) || (bl == NULL)) {
  195.         goto load_blockfile_error;
  196.     }
  197.  
  198.     fs->f = bl;
  199.  
  200.     fs->next    = files->next;
  201.     files->next = fs;
  202.  
  203.     if(csp) {
  204.         csp->blist = fs;
  205.     }
  206.  
  207.     *prev = *curr;
  208.  
  209.     if((fp = fopen(blockfile, "r")) == NULL) {
  210.         goto load_blockfile_error;
  211.     }
  212.     
  213.     sprintf(buf, "<h2>The file `%s' contains the following patterns</h2>\n", blockfile);
  214.     fs->proxy_args = strsav(fs->proxy_args, buf);
  215.  
  216.     fs->proxy_args = strsav(fs->proxy_args, "<pre>");
  217.  
  218.     while(fgets(buf, sizeof(buf), fp)) {
  219.  
  220.         fs->proxy_args = strsav(fs->proxy_args, buf);
  221.         fs->proxy_args = strsav(fs->proxy_args, "<br>");
  222.  
  223.         if((p = strpbrk(buf, "\r\n")) == NULL) {
  224.             errno = EINVAL;
  225.             fclose(fp);
  226.             goto load_blockfile_error;
  227.         }
  228.  
  229.         *p = '\0';
  230.  
  231.         /* comments */
  232.         if((p = strchr(buf, '#'))) *p = '\0';
  233.  
  234.         /* elide white-space */
  235.         for(p = q = buf; *q ; q++) {
  236.             if(!isspace(*q)) *p++ = *q;
  237.         }
  238.  
  239.         *p = '\0';
  240.  
  241.         reject = 1;
  242.  
  243.         if(*buf == '~') {
  244.             reject = 0;
  245.             p = buf;
  246.             q = p+1;
  247.             while ((*p++ = *q++)) {
  248.                 /* nop */
  249.             }
  250.         }
  251.  
  252.         /* skip blank lines */
  253.         if(*buf == '\0') continue;
  254.  
  255.         /* allocate a new node */
  256.         if(((b            = zalloc(sizeof(*b)))            == NULL)
  257. #ifdef REGEX
  258.         || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
  259. #endif
  260.         ) {
  261.             fclose(fp);
  262.             goto load_blockfile_error;
  263.         }
  264.  
  265.         /* add it to the list */
  266.         b->next  = bl->next;
  267.         bl->next = b;
  268.  
  269.         /* save a copy of the orignal specification */
  270.         if((b->url->spec = strdup(buf)) == NULL) {
  271.             fclose(fp);
  272.             goto load_blockfile_error;
  273.         }
  274.  
  275.         b->reject = reject;
  276.  
  277.         if((p = strchr(buf, '/'))) {
  278.             b->url->path    = strdup(p);
  279.             b->url->pathlen = strlen(b->url->path);
  280.             *p = '\0';
  281.         } else {
  282.             b->url->path    = NULL;
  283.             b->url->pathlen = 0;
  284.         }
  285. #ifdef REGEX
  286.         if(b->url->path) {
  287.             int errcode;
  288.             char rebuf[BUFSIZ];
  289.  
  290.             sprintf(rebuf, "^(%s)", b->url->path);
  291.  
  292.             errcode = regcomp(b->url->preg, rebuf,
  293.                     (REG_EXTENDED|REG_NOSUB|REG_ICASE));
  294.  
  295.             if(errcode) {
  296.                 size_t errlen =
  297.                     regerror(errcode,
  298.                         b->url->preg, buf, sizeof(buf));
  299.  
  300.                 buf[errlen] = '\0';
  301.  
  302.                 fprintf(logfp,
  303.                     "%s: error compiling %s: %s\n",
  304.                         prog, b->url->spec, buf);
  305.                 fclose(fp);
  306.                 goto load_blockfile_error;
  307.             }
  308.         } else {
  309.             freez(b->url->preg);
  310.         }
  311. #endif
  312.         if((p = strchr(buf, ':')) == NULL) {
  313.             port = 0;
  314.         } else {
  315.             *p++ = '\0';
  316.             port = atoi(p);
  317.         }
  318.  
  319.         b->url->port = port;
  320.  
  321.         if((b->url->domain = strdup(buf)) == NULL) {
  322.             fclose(fp);
  323.             goto load_blockfile_error;
  324.         }
  325.  
  326.         /* split domain into components */
  327.         *url = dsplit(b->url->domain);
  328.         b->url->dbuf = url->dbuf;
  329.         b->url->dcnt = url->dcnt;
  330.         b->url->dvec = url->dvec;
  331.     }
  332.     fs->proxy_args = strsav(fs->proxy_args, "</pre>");
  333.  
  334.     fclose(fp);
  335.  
  336.     /* the old one is now obsolete */
  337.     if(current_blockfile) {
  338.         current_blockfile->unloader = unload_blockfile;
  339.     }
  340.  
  341.     current_blockfile = fs;
  342.  
  343.     return(0);
  344.  
  345. load_blockfile_error:
  346.     fprintf(logfp, "%s: can't load blockfile '%s': ",
  347.         prog, blockfile);
  348.     fperror(logfp, "");
  349.     return(-1);
  350. }
  351.  
  352. int
  353. load_cookiefile(struct client_state *csp)
  354. {
  355.     FILE *fp;
  356.  
  357.     struct cookie_spec *b, *bl;
  358.     char  buf[BUFSIZ], *p, *q;
  359.     char *tmp_vec[BUFSIZ];
  360.     int port, user_cookie, server_cookie;
  361.     static struct stat prev[1], curr[1];
  362.     static struct file_list *fs;
  363.     struct url_spec url[1];
  364.  
  365.     if(stat(cookiefile, curr) < 0) {
  366.         goto load_cookie_error;
  367.     }
  368.  
  369.     if(current_cookiefile && (prev->st_mtime == curr->st_mtime)) {
  370.         csp->clist = current_cookiefile;
  371.         return(0);
  372.     }
  373.  
  374.     fs = (struct file_list   *) zalloc(sizeof(*fs));
  375.         bl = (struct cookie_spec *) zalloc(sizeof(*bl));
  376.  
  377.     if((fs == NULL) || (bl == NULL)) {
  378.         goto load_cookie_error;
  379.     }
  380.  
  381.     fs->f = bl;
  382.  
  383.     fs->next    = files->next;
  384.     files->next = fs;
  385.  
  386.     if(csp) {
  387.         csp->clist = fs;
  388.     }
  389.  
  390.     *prev = *curr;
  391.     
  392.     if((fp = fopen(cookiefile, "r")) == NULL) {
  393.         goto load_cookie_error;
  394.     }
  395.  
  396.     sprintf(buf, "<h2>The file `%s' contains the following patterns</h2>\n", cookiefile);
  397.     fs->proxy_args = strsav(fs->proxy_args, buf);
  398.  
  399.     fs->proxy_args = strsav(fs->proxy_args, "<pre>");
  400.  
  401.     while(fgets(buf, sizeof(buf), fp)) {
  402.  
  403.         fs->proxy_args = strsav(fs->proxy_args, buf);
  404.         fs->proxy_args = strsav(fs->proxy_args, "<br>");
  405.  
  406.         if((p = strpbrk(buf, "\r\n")) == NULL) {
  407.             errno = EINVAL;
  408.             fclose(fp);
  409.             goto load_cookie_error;
  410.         }
  411.  
  412.         *p = '\0';
  413.  
  414.         /* comments */
  415.         if((p = strchr(buf, '#'))) *p = '\0';
  416.  
  417.         /* elide white-space */
  418.         for(p = q = buf; *q ; q++) {
  419.             if(!isspace(*q)) *p++ = *q;
  420.         }
  421.  
  422.         *p = '\0';
  423.  
  424.         p = buf;
  425.  
  426.         switch((int)*p) {
  427.         case '>':
  428.             server_cookie = 0;
  429.             user_cookie   = 1;
  430.             p++;
  431.             break;
  432.         case '<':
  433.             server_cookie = 1;
  434.             user_cookie   = 0;
  435.             p++;
  436.             break;
  437.         case '~':
  438.             server_cookie = 0;
  439.             user_cookie   = 0;
  440.             p++;
  441.             break;
  442.         default:
  443.             server_cookie = 1;
  444.             user_cookie   = 1;
  445.             break;
  446.         }
  447.  
  448.         /* elide any of the "special" chars from the
  449.          * front of the pattern
  450.          */
  451.         q = buf;
  452.         if(p > q) while ((*q++ = *p++)) {
  453.             /* nop */
  454.         }
  455.  
  456.         /* skip blank lines */
  457.         if(*buf == '\0') continue;
  458.  
  459.         /* allocate a new node */
  460.         if(((b            = zalloc(sizeof(*b)))            == NULL)
  461. #ifdef REGEX
  462.         || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
  463. #endif
  464.         ) {
  465.             fclose(fp);
  466.             goto load_cookie_error;
  467.         }
  468.  
  469.         /* add it to the list */
  470.         b->next  = bl->next;
  471.         bl->next = b;
  472.  
  473.         /* save a copy of the orignal specification */
  474.         if((b->url->spec = strdup(buf)) == NULL) {
  475.             fclose(fp);
  476.             goto load_cookie_error;
  477.         }
  478.  
  479.         b->send_user_cookie     = user_cookie;
  480.         b->accept_server_cookie = server_cookie;
  481.  
  482.         if((p = strchr(buf, '/'))) {
  483.             b->url->path    = strdup(p);
  484.             b->url->pathlen = strlen(b->url->path);
  485.             *p = '\0';
  486.         } else {
  487.             b->url->path    = NULL;
  488.             b->url->pathlen = 0;
  489.         }
  490. #ifdef REGEX
  491.         if(b->url->path) {
  492.             int errcode;
  493.             char rebuf[BUFSIZ];
  494.  
  495.             sprintf(rebuf, "^(%s)", b->url->path);
  496.  
  497.             errcode = regcomp(b->url->preg, rebuf,
  498.                     (REG_EXTENDED|REG_NOSUB|REG_ICASE));
  499.             if(errcode) {
  500.                 size_t errlen =
  501.                     regerror(errcode,
  502.                         b->url->preg, buf, sizeof(buf));
  503.  
  504.                 buf[errlen] = '\0';
  505.  
  506.                 fprintf(logfp,
  507.                     "%s: error compiling %s: %s\n",
  508.                         prog, b->url->spec, buf);
  509.                 fclose(fp);
  510.                 goto load_cookie_error;
  511.             }
  512.         } else {
  513.             freez(b->url->preg);
  514.         }
  515. #endif
  516.         if((p = strchr(buf, ':')) == NULL) {
  517.             port = 0;
  518.         } else {
  519.             *p++ = '\0';
  520.             port = atoi(p);
  521.         }
  522.  
  523.         b->url->port = port;
  524.  
  525.         if((b->url->domain = strdup(buf)) == NULL) {
  526.             fclose(fp);
  527.             goto load_cookie_error;
  528.         }
  529.  
  530.         /* split domain into components */
  531.         *url = dsplit(b->url->domain, tmp_vec);
  532.         b->url->dbuf = url->dbuf;
  533.         b->url->dcnt = url->dcnt;
  534.         b->url->dvec = url->dvec;
  535.     }
  536.  
  537.     fs->proxy_args = strsav(fs->proxy_args, "</pre>");
  538.  
  539.     fclose(fp);
  540.  
  541.     /* the old one is now obsolete */
  542.     if(current_cookiefile) {
  543.         current_cookiefile->unloader = unload_cookiefile;
  544.     }
  545.  
  546.     current_cookiefile = fs;
  547.  
  548.     return(0);
  549.  
  550. load_cookie_error:
  551.     fprintf(logfp, "%s: can't load cookiefile '%s': ",
  552.         prog, cookiefile);
  553.     fperror(logfp, "");
  554.     return(-1);
  555. }
  556.  
  557. int
  558. load_trustfile(struct client_state *csp)
  559. {
  560.     FILE *fp;
  561.  
  562.     struct block_spec *b, *bl;
  563.     struct url_spec **tl;
  564.  
  565.     char  buf[BUFSIZ], *p, *q;
  566.     int port, reject, trusted;
  567.     struct file_list *fs;
  568.     static struct stat prev[1], curr[1];
  569.     struct url_spec url[1];
  570.  
  571.     if(stat(trustfile, curr) < 0) {
  572.         goto load_trustfile_error;
  573.     }
  574.  
  575.     if(current_trustfile && (prev->st_mtime == curr->st_mtime)) {
  576.         csp->tlist = current_trustfile;
  577.         return(0);
  578.     }
  579.  
  580.     fs = (struct file_list  *) zalloc(sizeof(*fs));
  581.     bl = (struct block_spec *) zalloc(sizeof(*bl));
  582.  
  583.     if((fs == NULL) || (bl == NULL)) {
  584.         goto load_trustfile_error;
  585.     }
  586.  
  587.     fs->f = bl;
  588.  
  589.     fs->next    = files->next;
  590.     files->next = fs;
  591.  
  592.     if(csp) {
  593.         csp->tlist = fs;
  594.     }
  595.  
  596.     *prev = *curr;
  597.  
  598.     if((fp = fopen(trustfile, "r")) == NULL) {
  599.         goto load_trustfile_error;
  600.     }
  601.     
  602.     sprintf(buf, "<h2>The file `%s' contains the following patterns</h2>\n", trustfile);
  603.     fs->proxy_args = strsav(fs->proxy_args, buf);
  604.  
  605.     fs->proxy_args = strsav(fs->proxy_args, "<pre>");
  606.  
  607.     tl = trust_list;
  608.  
  609.     while(fgets(buf, sizeof(buf), fp)) {
  610.  
  611.         fs->proxy_args = strsav(fs->proxy_args, buf);
  612.         fs->proxy_args = strsav(fs->proxy_args, "<br>");
  613.  
  614.         if((p = strpbrk(buf, "\r\n")) == NULL) {
  615.             errno = EINVAL;
  616.             fclose(fp);
  617.             goto load_trustfile_error;
  618.         }
  619.  
  620.         *p = '\0';
  621.  
  622.         /* comments */
  623.         if((p = strchr(buf, '#'))) *p = '\0';
  624.  
  625.         /* elide white-space */
  626.         for(p = q = buf; *q ; q++) {
  627.             if(!isspace(*q)) *p++ = *q;
  628.         }
  629.  
  630.         *p = '\0';
  631.  
  632.         trusted = 0;
  633.         reject  = 1;
  634.  
  635.         if(*buf == '+') {
  636.             trusted = 1;
  637.             *buf = '~';
  638.         }
  639.  
  640.         if(*buf == '~') {
  641.             reject = 0;
  642.             p = buf;
  643.             q = p+1;
  644.             while ((*p++ = *q++)) {
  645.                 /* nop */
  646.             }
  647.         }
  648.  
  649.         /* skip blank lines */
  650.         if(*buf == '\0') continue;
  651.  
  652.         /* allocate a new node */
  653.         if(((b            = zalloc(sizeof(*b)))            == NULL)
  654. #ifdef REGEX
  655.         || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
  656. #endif
  657.         ) {
  658.             fclose(fp);
  659.             goto load_trustfile_error;
  660.         }
  661.  
  662.         /* add it to the list */
  663.         b->next  = bl->next;
  664.         bl->next = b;
  665.  
  666.         /* save a copy of the orignal specification */
  667.         if((b->url->spec = strdup(buf)) == NULL) {
  668.             fclose(fp);
  669.             goto load_trustfile_error;
  670.         }
  671.  
  672.         b->reject = reject;
  673.  
  674.         if((p = strchr(buf, '/'))) {
  675.             b->url->path    = strdup(p);
  676.             b->url->pathlen = strlen(b->url->path);
  677.             *p = '\0';
  678.         } else {
  679.             b->url->path    = NULL;
  680.             b->url->pathlen = 0;
  681.         }
  682. #ifdef REGEX
  683.         if(b->url->path) {
  684.             int errcode;
  685.             char rebuf[BUFSIZ];
  686.  
  687.             sprintf(rebuf, "^(%s)", b->url->path);
  688.  
  689.             errcode = regcomp(b->url->preg, rebuf,
  690.                     (REG_EXTENDED|REG_NOSUB|REG_ICASE));
  691.  
  692.             if(errcode) {
  693.                 size_t errlen =
  694.                     regerror(errcode,
  695.                         b->url->preg, buf, sizeof(buf));
  696.  
  697.                 buf[errlen] = '\0';
  698.  
  699.                 fprintf(logfp,
  700.                     "%s: error compiling %s: %s\n",
  701.                         prog, b->url->spec, buf);
  702.                 fclose(fp);
  703.                 goto load_trustfile_error;
  704.             }
  705.         } else {
  706.             freez(b->url->preg);
  707.         }
  708. #endif
  709.         if((p = strchr(buf, ':')) == NULL) {
  710.             port = 0;
  711.         } else {
  712.             *p++ = '\0';
  713.             port = atoi(p);
  714.         }
  715.  
  716.         b->url->port = port;
  717.  
  718.         if((b->url->domain = strdup(buf)) == NULL) {
  719.             fclose(fp);
  720.             goto load_trustfile_error;
  721.         }
  722.  
  723.         /* split domain into components */
  724.         *url = dsplit(b->url->domain);
  725.         b->url->dbuf = url->dbuf;
  726.         b->url->dcnt = url->dcnt;
  727.         b->url->dvec = url->dvec;
  728.  
  729.         /* save a pointer to URL's spec
  730.          * in the list of trusted URL's, too
  731.          */
  732.         if(trusted) *tl++ = b->url;
  733.     }
  734.  
  735.     fs->proxy_args = strsav(fs->proxy_args, "</pre>");
  736.  
  737.     *tl = NULL;
  738.  
  739.     fclose(fp);
  740.  
  741.     /* the old one is now obsolete */
  742.     if(current_trustfile) {
  743.         current_trustfile->unloader = unload_trustfile;
  744.     }
  745.  
  746.     current_trustfile = fs;
  747.  
  748.     return(0);
  749.  
  750. load_trustfile_error:
  751.     fprintf(logfp, "%s: can't load trustfile '%s': ",
  752.         prog, trustfile);
  753.     fperror(logfp, "");
  754.     return(-1);
  755. }
  756.  
  757. int
  758. load_forwardfile(struct client_state *csp)
  759. {
  760.     FILE *fp;
  761.  
  762.     struct forward_spec *b, *bl;
  763.     char  buf[BUFSIZ], *p, *q, *tmp;
  764.     char  *vec[4];
  765.     int port, n, reject;
  766.     struct file_list *fs;
  767.     struct gateway *gw;
  768.     static struct stat prev[1], curr[1];
  769.     struct url_spec url[1];
  770.  
  771.     if(stat(forwardfile, curr) < 0) {
  772.         goto load_forwardfile_error;
  773.     }
  774.  
  775.     if(current_forwardfile && (prev->st_mtime == curr->st_mtime)) {
  776.         csp->flist = current_forwardfile;
  777.         return(0);
  778.     }
  779.  
  780.     fs = (struct file_list    *) zalloc(sizeof(*fs));
  781.     bl = (struct forward_spec *) zalloc(sizeof(*bl));
  782.  
  783.     if((fs == NULL) || (bl == NULL)) {
  784.         goto load_forwardfile_error;
  785.     }
  786.  
  787.     memset(fs, '\0', sizeof(*fs));
  788.     memset(bl, '\0', sizeof(*bl));
  789.  
  790.     fs->f = bl;
  791.  
  792.     fs->next    = files->next;
  793.     files->next = fs;
  794.  
  795.     if(csp) {
  796.         csp->flist = fs;
  797.     }
  798.  
  799.     *prev = *curr;
  800.  
  801.     if((fp = fopen(forwardfile, "r")) == NULL) {
  802.         goto load_forwardfile_error;
  803.     }
  804.     
  805.     sprintf(buf, "<h2>The file `%s' contains the following patterns</h2>\n", forwardfile);
  806.     fs->proxy_args = strsav(fs->proxy_args, buf);
  807.  
  808.     tmp = NULL;
  809.  
  810.     fs->proxy_args = strsav(fs->proxy_args, "<pre>");
  811.  
  812.     while(fgets(buf, sizeof(buf), fp)) {
  813.  
  814.         freez(tmp);
  815.  
  816.         fs->proxy_args = strsav(fs->proxy_args, buf);
  817.         fs->proxy_args = strsav(fs->proxy_args, "<br>");
  818.  
  819.         if((p = strpbrk(buf, "\r\n")) == NULL) {
  820.             errno = EINVAL;
  821.             fclose(fp);
  822.             goto load_forwardfile_error;
  823.         }
  824.  
  825.         *p = '\0';
  826.  
  827.         /* comments */
  828.         if((p = strchr(buf, '#'))) *p = '\0';
  829.  
  830.         /* skip blank lines */
  831.         if(*buf == '\0') continue;
  832.  
  833.         tmp = strdup(buf);
  834.  
  835.         n = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
  836.  
  837.         if(n != 4) {
  838.             fprintf(stderr, "error in forwardfile: %s\n", buf);
  839.             continue;
  840.         }
  841.  
  842.         strcpy(buf, vec[0]);
  843.  
  844.         reject = 1;
  845.  
  846.         if(*buf == '~') {
  847.             reject = 0;
  848.             p = buf;
  849.             q = p+1;
  850.             while ((*p++ = *q++)) {
  851.                 /* nop */
  852.             }
  853.         }
  854.  
  855.         /* skip blank lines */
  856.         if(*buf == '\0') continue;
  857.  
  858.         /* allocate a new node */
  859.         if(((b            = zalloc(sizeof(*b)))            == NULL)
  860. #ifdef REGEX
  861.         || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
  862. #endif
  863.         ) {
  864.             fclose(fp);
  865.             goto load_forwardfile_error;
  866.         }
  867.  
  868.         /* add it to the list */
  869.         b->next  = bl->next;
  870.         bl->next = b;
  871.  
  872.         /* save a copy of the orignal specification */
  873.         if((b->url->spec = strdup(buf)) == NULL) {
  874.             fclose(fp);
  875.             goto load_forwardfile_error;
  876.         }
  877.  
  878.         b->reject = reject;
  879.  
  880.         if((p = strchr(buf, '/'))) {
  881.             b->url->path    = strdup(p);
  882.             b->url->pathlen = strlen(b->url->path);
  883.             *p = '\0';
  884.         } else {
  885.             b->url->path    = NULL;
  886.             b->url->pathlen = 0;
  887.         }
  888. #ifdef REGEX
  889.         if(b->url->path) {
  890.             int errcode;
  891.             char rebuf[BUFSIZ];
  892.  
  893.             sprintf(rebuf, "^(%s)", b->url->path);
  894.  
  895.             errcode = regcomp(b->url->preg, rebuf,
  896.                     (REG_EXTENDED|REG_NOSUB|REG_ICASE));
  897.  
  898.             if(errcode) {
  899.                 size_t errlen =
  900.                     regerror(errcode,
  901.                         b->url->preg, buf, sizeof(buf));
  902.  
  903.                 buf[errlen] = '\0';
  904.  
  905.                 fprintf(logfp,
  906.                     "%s: error compiling %s: %s\n",
  907.                         prog, b->url->spec, buf);
  908.                 fclose(fp);
  909.                 goto load_forwardfile_error;
  910.             }
  911.         } else {
  912.             freez(b->url->preg);
  913.         }
  914. #endif
  915.         if((p = strchr(buf, ':')) == NULL) {
  916.             port = 0;
  917.         } else {
  918.             *p++ = '\0';
  919.             port = atoi(p);
  920.         }
  921.  
  922.         b->url->port = port;
  923.  
  924.         if((b->url->domain = strdup(buf)) == NULL) {
  925.             fclose(fp);
  926.             goto load_forwardfile_error;
  927.         }
  928.  
  929.         /* split domain into components */
  930.         *url = dsplit(b->url->domain);
  931.         b->url->dbuf = url->dbuf;
  932.         b->url->dcnt = url->dcnt;
  933.         b->url->dvec = url->dvec;
  934.  
  935.         /* now parse the gateway specs */
  936.  
  937.         p = vec[2];
  938.  
  939.         for(gw = gateways; gw->name; gw++) {
  940.             if(strcmp(gw->name, p) == 0) {
  941.                 break;
  942.             }
  943.         }
  944.  
  945.         if(gw->name == NULL) {
  946.             goto load_forwardfile_error;
  947.         }
  948.  
  949.         /* save this as the gateway type */
  950.         *b->gw = *gw;
  951.  
  952.         /* now parse the gateway host[:port] spec */
  953.         p = vec[3];
  954.  
  955.         if(strcmp(p, ".") != 0) {
  956.             b->gw->gateway_host = strdup(p);
  957.  
  958.             if((p = strchr(b->gw->gateway_host, ':'))) {
  959.                 *p++ = '\0';
  960.                 b->gw->gateway_port = atoi(p);
  961.             }
  962.  
  963.             if(b->gw->gateway_port <= 0) {
  964.                 goto load_forwardfile_error;
  965.             }
  966.         }
  967.  
  968.         /* now parse the forwarding spec */
  969.         p = vec[1];
  970.  
  971.         if(strcmp(p, ".") != 0) {
  972.             b->gw->forward_host = strdup(p);
  973.  
  974.             if((p = strchr(b->gw->forward_host, ':'))) {
  975.                 *p++ = '\0';
  976.                 b->gw->forward_port = atoi(p);
  977.             }
  978.  
  979.             if(b->gw->forward_port <= 0) {
  980.                 b->gw->forward_port = 8000;
  981.             }
  982.         }
  983.     }
  984.  
  985.     fs->proxy_args = strsav(fs->proxy_args, "</pre>");
  986.  
  987.     freez(tmp);
  988.  
  989.     fclose(fp);
  990.  
  991.     /* the old one is now obsolete */
  992.     if(current_forwardfile) {
  993.         current_forwardfile->unloader = unload_forwardfile;
  994.     }
  995.  
  996.     current_forwardfile = fs;
  997.  
  998.     return(0);
  999.  
  1000. load_forwardfile_error:
  1001.     fprintf(logfp, "%s: can't load forwardfile '%s': ",
  1002.         prog, forwardfile);
  1003.     fperror(logfp, "");
  1004.     return(-1);
  1005. }
  1006.  
  1007. #define JUNKBUSTERS "http://www.junkbusters.com"
  1008. #define OPT "href=\"" JUNKBUSTERS "/ht/en/ijb" VERSION "man.html#"
  1009.  
  1010. /* strsav() takes a pointer to a string stored in a dynamically allocated
  1011.  * buffer and a pointer to a string and returns a pointer to a new dynamically
  1012.  * allocated space that contains the concatenation of the two input strings
  1013.  * the previous space is free()'d by realloc().
  1014.  */
  1015. char *
  1016. strsav(char *old, char *text_to_append)
  1017. {
  1018.     int old_len, new_len;
  1019.     char *p;
  1020.  
  1021.     if(( text_to_append == NULL)
  1022.     || (*text_to_append == '\0')) {
  1023.         return(old);
  1024.     }
  1025.  
  1026.     if(old) {
  1027.         old_len = strlen(old);
  1028.     } else {
  1029.         old_len = 0;
  1030.     }
  1031.  
  1032.     new_len = old_len + strlen(text_to_append) + 1;
  1033.  
  1034.     if(old) {
  1035.         if((p = realloc(old, new_len)) == NULL) {
  1036.             fprintf(logfp, "%s: realloc(%d) bytes for proxy_args failed!\n", prog, new_len);
  1037.             exit(1);
  1038.         }
  1039.     } else {
  1040.         if((p = malloc(new_len)) == NULL) {
  1041.             fprintf(logfp, "%s: malloc(%d) bytes for proxy_args failed!\n", prog, new_len);
  1042.             exit(1);
  1043.         }
  1044.     }
  1045.  
  1046.     strcpy(p + old_len, text_to_append);
  1047.     return(p);
  1048. }
  1049.  
  1050. void
  1051. savearg(char *c, char *o)
  1052. {
  1053.     char buf[BUFSIZ];
  1054.     static int one_shot = 1;
  1055.  
  1056.     if(one_shot) {
  1057.         one_shot = 0;
  1058.         proxy_args->invocation = strsav(proxy_args->invocation,
  1059.             "<br>\n"
  1060.             "and the following options were set "
  1061.             "in the configuration file"
  1062.             "<br><br>\n"
  1063.         );
  1064.     }
  1065.  
  1066.     *buf = '\0';
  1067.  
  1068.     if(c && *c) { sprintf(buf, "<a " OPT "%s\">%s</a> ", c, c);    }
  1069.     if(o && *o) { 
  1070.         if(strncmpic(o, "http://", 7) == 0) {
  1071.             strcat(buf, "<a href=\"");
  1072.             strcat(buf, o);
  1073.             strcat(buf, "\">");
  1074.             strcat(buf, o);
  1075.             strcat(buf, "</a>");
  1076.         } else {
  1077.             strcat(buf, o);
  1078.         }
  1079.     }
  1080.  
  1081.     strcat(buf, "<br>\n");
  1082.  
  1083.     proxy_args->invocation = strsav(proxy_args->invocation, buf);
  1084. }
  1085.  
  1086.  
  1087. void
  1088. init_proxy_args(int argc, char *argv[])
  1089. {
  1090.     struct gateway *g;
  1091.     int i;
  1092.  
  1093.     proxy_args->header = strsav(proxy_args->header,
  1094.         "HTTP/1.0 200 OK\n"
  1095.         "Server: IJ/" VERSION "\n"
  1096.         "Content-type: text/html\n\n"
  1097.  
  1098.         "<html>"
  1099.         "<head>"
  1100.         "<title>Internet Junkbuster Proxy Status</title>"
  1101.         "</head>\n"
  1102.         "<body bgcolor=\"#f8f8f0\" link=\"#000078\" alink=\"#ff0022\" vlink=\"#787878\">\n"
  1103.         "<center>\n"
  1104.         "<h1>" BANNER "\n"
  1105.         "<a href=\"" JUNKBUSTERS "/ht/en/ijb" VERSION "faq.html#show\">Proxy Status</a>\n"
  1106.         "</h1></center>\n"
  1107.         "<h2>You are using the " BANNER " <sup><small><small>TM</small></small></sup></h2>\n"
  1108.         "Version: IJ/" VERSION "\n"
  1109.         "<p>\n"
  1110.     );
  1111.  
  1112.     proxy_args->header = strsav(proxy_args->header,
  1113.         "<h2>The program was invoked as follows</h2>\n");
  1114.  
  1115.     for(i=0; i < argc; i++) {
  1116.         proxy_args->header = strsav(proxy_args->header, argv[i]);
  1117.         proxy_args->header = strsav(proxy_args->header, " ");
  1118.     }
  1119.     proxy_args->header = strsav(proxy_args->header, "<br>\n");
  1120.  
  1121.     proxy_args->gateways = strsav(proxy_args->gateways,
  1122.         "<h2>It supports the following gateway protocols:</h2>\n");
  1123.  
  1124.     for(g = gateways; g->name; g++) {
  1125.         proxy_args->gateways = strsav(proxy_args->gateways, g->name);
  1126.         proxy_args->gateways = strsav(proxy_args->gateways, " ");
  1127.     }
  1128.     proxy_args->gateways = strsav(proxy_args->gateways, "<br>\n");
  1129. }
  1130.  
  1131. void
  1132. end_proxy_args()
  1133. {
  1134.     char buf[BUFSIZ];
  1135.     char *b = NULL;
  1136.  
  1137.     extern char    *acl_rcs, *bind_rcs, *conn_rcs, *encode_rcs,
  1138.             *jcc_rcs, *loaders_rcs, *parsers_rcs, *filters_rcs,
  1139.             *socks4_rcs, *ssplit_rcs, *gnu_regex_rcs, *win32_rcs;
  1140.  
  1141.     b = strsav(b, "<h2>Source versions:</h2>\n");
  1142.     b = strsav(b, "<pre>");
  1143.     sprintf(buf, "%s\n", jcc_rcs       );    b = strsav(b, buf);
  1144.     sprintf(buf, "%s\n", parsers_rcs   );    b = strsav(b, buf);
  1145.     sprintf(buf, "%s\n", filters_rcs   );    b = strsav(b, buf);
  1146.     sprintf(buf, "%s\n", loaders_rcs   );    b = strsav(b, buf);
  1147.     sprintf(buf, "%s\n", conn_rcs      );    b = strsav(b, buf);
  1148.     sprintf(buf, "%s\n", bind_rcs      );    b = strsav(b, buf);
  1149.     sprintf(buf, "%s\n", encode_rcs    );    b = strsav(b, buf);
  1150.     sprintf(buf, "%s\n", socks4_rcs    );    b = strsav(b, buf);
  1151.     sprintf(buf, "%s\n", ssplit_rcs    );    b = strsav(b, buf);
  1152.     sprintf(buf, "%s\n", acl_rcs       );    b = strsav(b, buf);
  1153.     sprintf(buf, "%s\n", gnu_regex_rcs );    b = strsav(b, buf);
  1154.     sprintf(buf, "%s\n", win32_rcs     );    b = strsav(b, buf);
  1155.     b = strsav(b, "</pre>");
  1156.  
  1157. #ifdef REGEX
  1158.     b = strsav(b, "<p>This " BANNER " supports POSIX regular expressions in the path specs.\n");
  1159. #endif
  1160.  
  1161.  
  1162.     b = strsav(b,
  1163.         "<small><small><p>\n"
  1164.         "Code and documentation of the " BANNER " Proxy"
  1165.         "<sup><small>TM</small></sup>\n"
  1166.         "<a href=\""  JUNKBUSTERS "/ht/en/legal.html#copy\">\n" "Copyright</a>© 1997 Junkbusters Corporation\n"
  1167.         "<a href=\"" JUNKBUSTERS "/ht/en/legal.html#marks\"><sup><small>TM</small></sup></a><br>\n"
  1168.         "Copying and distribution permitted under the"
  1169.         "<a href=\""  JUNKBUSTERS "/ht/en/gpl.html\">\n"
  1170.         "<small>GNU</small></a> "
  1171.         "General Public License.\n"
  1172.         "</small>"
  1173.         "<address><kbd>webmaster@junkbusters.com</kbd></address>"
  1174.         "</small>"
  1175.         "</body></html>\n"
  1176.     );
  1177.  
  1178.     proxy_args->trailer = b;
  1179. }
  1180.  
  1181. void
  1182. add_loader(int (*loader)())
  1183. {
  1184.     int i;
  1185.  
  1186.     for(i=0; i < NLOADERS; i++) {
  1187.         if(loaders[i] == NULL) {
  1188.             loaders[i] = loader;
  1189.             break;
  1190.         }
  1191.     }
  1192. }
  1193.  
  1194. int
  1195. run_loader(struct client_state *csp)
  1196. {
  1197.     int ret = 0;
  1198.     int i;
  1199.  
  1200.     for(i=0; i < NLOADERS; i++) {
  1201.         if(loaders[i] == NULL) break;
  1202.         ret |= (loaders[i])(csp);
  1203.     }
  1204.     return(ret);
  1205. }
  1206.  
  1207. /* the way calloc() ought to be -acjc */
  1208. void *
  1209. zalloc(int size)
  1210. {
  1211.     void *ret;
  1212.  
  1213.     if((ret = malloc(size))) {
  1214.         memset(ret, '\0', size);
  1215.     }
  1216.     return(ret);
  1217. }
  1218.  
  1219.