home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 8 / CDACTUAL8.iso / share / os2 / varios / apache / util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-25  |  28.0 KB  |  1,197 lines

  1.  
  2. /* ====================================================================
  3.  * Copyright (c) 1995 The Apache Group.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer. 
  11.  *
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in
  14.  *    the documentation and/or other materials provided with the
  15.  *    distribution.
  16.  *
  17.  * 3. All advertising materials mentioning features or use of this
  18.  *    software must display the following acknowledgment:
  19.  *    "This product includes software developed by the Apache Group
  20.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  21.  *
  22.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  23.  *    endorse or promote products derived from this software without
  24.  *    prior written permission.
  25.  *
  26.  * 5. Redistributions of any form whatsoever must retain the following
  27.  *    acknowledgment:
  28.  *    "This product includes software developed by the Apache Group
  29.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  30.  *
  31.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  32.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  33.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  34.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  35.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  42.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  43.  * ====================================================================
  44.  *
  45.  * This software consists of voluntary contributions made by many
  46.  * individuals on behalf of the Apache Group and was originally based
  47.  * on public domain software written at the National Center for
  48.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  49.  * For more information on the Apache Group and the Apache HTTP server
  50.  * project, please see <http://www.apache.org/>.
  51.  *
  52.  */
  53.  
  54.  
  55. /*
  56.  * str.c: string utility things
  57.  * 
  58.  * 3/21/93 Rob McCool
  59.  * 
  60.  */
  61.  
  62.  
  63. #include "httpd.h"
  64. #include "http_conf_globals.h"    /* for user_id & group_id */
  65. #ifdef QNX
  66. #include <time.h>
  67. #endif
  68.  
  69. #ifdef NOTDEF
  70. extern char** environ;
  71.  
  72. /* taken from bdflush-1.5 for Linux source code */
  73. void inststr(char *dst[], int argc, char *src)
  74. {
  75.     if (strlen(src) <= strlen(dst[0]))
  76.     {
  77.         char *ptr;
  78.  
  79.         for (ptr = dst[0]; *ptr; *(ptr++) = '\0');
  80.  
  81.         strcpy(dst[0], src);
  82.     } else
  83.     {
  84.         /* stolen from the source to perl 4.036 (assigning to $0) */
  85.         char *ptr, *ptr2;
  86.         int count;
  87.         ptr = dst[0] + strlen(dst[0]);
  88.         for (count = 1; count < argc; count++) {
  89.             if (dst[count] == ptr + 1)
  90.                 ptr += strlen(++ptr);
  91.         }
  92.         if (environ[0] == ptr + 1) {
  93.             for (count = 0; environ[count]; count++)
  94.                 if (environ[count] == ptr + 1)
  95.                     ptr += strlen(++ptr);
  96.         }
  97.         count = 0;
  98.         for (ptr2 = dst[0]; ptr2 <= ptr; ptr2++) {
  99.             *ptr2 = '\0';
  100.             count++;
  101.         }
  102.         strncpy(dst[0], src, count);
  103.     }
  104. }
  105. #endif
  106.  
  107. char *get_time() {
  108.     time_t t;
  109.     char *time_string;
  110.  
  111.     t=time(NULL);
  112.     time_string = ctime(&t);
  113.     time_string[strlen(time_string) - 1] = '\0';
  114.     return (time_string);
  115. }
  116.  
  117. char *ht_time(pool *p, time_t t, char *fmt, int gmt) {
  118.     char ts[MAX_STRING_LEN];
  119.     struct tm *tms;
  120.  
  121.     tms = (gmt ? gmtime(&t) : localtime(&t));
  122.  
  123.     /* check return code? */
  124.     strftime(ts,MAX_STRING_LEN,fmt,tms);
  125.     return pstrdup (p, ts);
  126. }
  127.  
  128. char *gm_timestr_822(pool *p, time_t sec) {
  129.     static const char *const days[7]=
  130.        {"Sun","Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  131.     char ts[50];
  132.     struct tm *tms;
  133.  
  134.     tms = gmtime(&sec);
  135.  
  136. /* RFC date format; as strftime '%a, %d %b %Y %T GMT' */
  137.     sprintf(ts, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", days[tms->tm_wday],
  138.         tms->tm_mday, month_snames[tms->tm_mon], tms->tm_year + 1900,
  139.         tms->tm_hour, tms->tm_min, tms->tm_sec);
  140.  
  141.     return pstrdup (p, ts);
  142. }
  143.  
  144. /* What a pain in the ass. */
  145. struct tm *get_gmtoff(long *tz) {
  146.     time_t tt;
  147.     struct tm *t;
  148.  
  149.     tt = time(NULL);
  150.     t = localtime(&tt);
  151. #if defined(HAS_GMTOFF)
  152.     *tz = t->tm_gmtoff;
  153. #elif !defined(NO_TIMEZONE)
  154.     *tz = - timezone;
  155.     if(t->tm_isdst)
  156.         *tz += 3600;
  157. #else
  158.   {
  159.     static struct tm loc_t;
  160.  
  161.     loc_t = *t;   /* save it */
  162.     t = gmtime(&tt);
  163.     *tz = mktime(&loc_t) - mktime(t);
  164.     t = &loc_t; /* return pointer to saved time */
  165.   }
  166. #endif
  167.     return t;
  168. }
  169.  
  170.  
  171. /* Match = 0, NoMatch = 1, Abort = -1 */
  172. /* Based loosely on sections of wildmat.c by Rich Salz
  173.  * Hmmm... shouldn't this really go component by component?
  174.  */
  175. int strcmp_match(char *str, char *exp) {
  176.     int x,y;
  177.  
  178.     for(x=0,y=0;exp[y];++y,++x) {
  179.         if((!str[x]) && (exp[y] != '*'))
  180.             return -1;
  181.         if(exp[y] == '*') {
  182.             while(exp[++y] == '*');
  183.             if(!exp[y])
  184.                 return 0;
  185.             while(str[x]) {
  186.                 int ret;
  187.                 if((ret = strcmp_match(&str[x++],&exp[y])) != 1)
  188.                     return ret;
  189.             }
  190.             return -1;
  191.         } else 
  192.             if((exp[y] != '?') && (str[x] != exp[y]))
  193.                 return 1;
  194.     }
  195.     return (str[x] != '\0');
  196. }
  197.  
  198. int strcasecmp_match(char *str, char *exp) {
  199.     int x,y;
  200.  
  201.     for(x=0,y=0;exp[y];++y,++x) {
  202.         if((!str[x]) && (exp[y] != '*'))
  203.             return -1;
  204.         if(exp[y] == '*') {
  205.             while(exp[++y] == '*');
  206.             if(!exp[y])
  207.                 return 0;
  208.             while(str[x]) {
  209.                 int ret;
  210.                 if((ret = strcasecmp_match(&str[x++],&exp[y])) != 1)
  211.                     return ret;
  212.             }
  213.             return -1;
  214.         } else 
  215.             if((exp[y] != '?') && (tolower(str[x]) != tolower(exp[y])))
  216.                 return 1;
  217.     }
  218.     return (str[x] != '\0');
  219. }
  220.  
  221. int is_matchexp(char *str) {
  222.     register int x;
  223.  
  224.     for(x=0;str[x];x++)
  225.         if((str[x] == '*') || (str[x] == '?'))
  226.             return 1;
  227.     return 0;
  228. }
  229.  
  230. /*
  231.  * Parse .. so we don't compromise security
  232.  */
  233. void getparents(char *name)
  234. {
  235.     int l, w;
  236.  
  237.     /* Four paseses, as per RFC 1808 */
  238.     /* a) remove ./ path segments */
  239.  
  240.     for (l=0, w=0; name[l] != '\0';)
  241.     {
  242.     if (name[l] == '.' && name[l+1] == '/' && (l == 0 || name[l-1] == '/'))
  243.         l += 2;
  244.     else
  245.         name[w++] = name[l++];
  246.     }
  247.  
  248.     /* b) remove trailing . path, segment */
  249.     if (w == 1 && name[0] == '.') w--;
  250.     else if (w > 1 && name[w-1] == '.' && name[w-2] == '/') w--;
  251.     name[w] = '\0';
  252.  
  253.     /* c) remove all xx/../ segments. (including leading ../ and /../) */
  254.     l = 0;
  255.  
  256.     while(name[l]!='\0') {
  257.         if(name[l] == '.' && name[l+1] == '.' && name[l+2] == '/' &&
  258.         (l == 0 || name[l-1] == '/')) {
  259.         register int m=l+3,n;
  260.  
  261.         l=l-2;
  262.         if(l>=0) {
  263.             while(l >= 0 && name[l] != '/') l--;
  264.             l++;
  265.         }
  266.         else l=0;
  267.         n=l;
  268.         while((name[n]=name[m])) (++n,++m);
  269.             }
  270.     else ++l;
  271.     }
  272.  
  273.     /* d) remove trailing xx/.. segment. */
  274.     if (l == 2 && name[0] == '.' && name[1] == '.') name[0] = '\0';
  275.     else if (l > 2 && name[l-1] == '.' && name[l-2] == '.' && name[l-3] == '/')
  276.     {
  277.     l = l - 4;
  278.     if (l >= 0)
  279.     {
  280.         while (l >= 0 && name[l] != '/') l--;
  281.         l++;
  282.     }
  283.     else l = 0;
  284.     name[l] = '\0';
  285.     }
  286.  
  287. void no2slash(char *name) {
  288.     register int x,y;
  289.  
  290.     for(x=0; name[x];)
  291.         if(x && (name[x-1] == '/') && (name[x] == '/'))
  292.             for(y=x+1;name[y-1];y++)
  293.                 name[y-1] = name[y];
  294.     else x++;
  295. }
  296.  
  297. char *make_dirstr(pool *p, char *s, int n) {
  298.     register int x,f;
  299.     char *res;
  300.  
  301.     for(x=0,f=0;s[x];x++) {
  302.         if(s[x] == '/')
  303.             if((++f) == n) {
  304.         res = palloc(p, x + 2);
  305.         strncpy (res, s, x);
  306.         res[x] = '/';
  307.         res[x+1] = '\0';
  308.                 return res;
  309.             }
  310.     }
  311.  
  312.     if (s[strlen(s) - 1] == '/')
  313.         return pstrdup (p, s);
  314.     else
  315.         return pstrcat (p, s, "/", NULL);
  316. }
  317.  
  318. int count_dirs(char *path) {
  319.     register int x,n;
  320.  
  321.     for(x=0,n=0;path[x];x++)
  322.         if(path[x] == '/') n++;
  323.     return n;
  324. }
  325.  
  326.  
  327. void chdir_file(char *file) {
  328.     int i;
  329.  
  330.     if((i = rind(file,'/')) == -1)
  331.         return;
  332.     file[i] = '\0';
  333.     chdir(file);
  334.     file[i] = '/';
  335. }
  336.  
  337. char *getword(pool* atrans, char **line, char stop) {
  338.     int pos = ind(*line, stop);
  339.     char *res;
  340.  
  341.     if (pos == -1) {
  342.         res = pstrdup (atrans, *line);
  343.     *line += strlen (*line);
  344.     return res;
  345.     }
  346.   
  347.     res = palloc(atrans, pos + 1);
  348.     strncpy (res, *line, pos);
  349.     res[pos] = '\0';
  350.     
  351.     while ((*line)[pos] == stop) ++pos;
  352.     
  353.     *line += pos;
  354.     
  355.     return res;
  356. }
  357. char *getword_nulls(pool* atrans, char **line, char stop) {
  358.     int pos = ind(*line, stop);
  359.     char *res;
  360.  
  361.     if (pos == -1) {
  362.         res = pstrdup (atrans, *line);
  363.     *line += strlen (*line);
  364.     return res;
  365.     }
  366.   
  367.     res = palloc(atrans, pos + 1);
  368.     strncpy (res, *line, pos);
  369.     res[pos] = '\0';
  370.     
  371.     ++pos;
  372.     
  373.     *line += pos;
  374.     
  375.     return res;
  376. }
  377.  
  378. /* Get a word, (new) config-file style --- quoted strings and backslashes
  379.  * all honored
  380.  */
  381.  
  382. char *substring_conf (pool *p, char *start, int len)
  383. {
  384.     char *result = palloc (p, len + 2);
  385.     char *resp = result;
  386.     int i;
  387.  
  388.     for (i = 0; i < len; ++i) {
  389.         if (start[i] == '\\') 
  390.         *resp++ = start[++i];
  391.     else
  392.         *resp++ = start[i];
  393.     }
  394.  
  395.     *resp++ = '\0';
  396.     return result;
  397. }
  398.  
  399. char *getword_conf(pool* p, char **line) {
  400.     char *str = *line, *strend, *res;
  401.     char quote;
  402.  
  403.     while (*str && isspace (*str))
  404.         ++str;
  405.  
  406.     if (!*str) {
  407.         *line = str;
  408.         return "";
  409.     }
  410.  
  411.     if ((quote = *str) == '"' || quote == '\'') {
  412.         strend = str + 1;
  413.     while (*strend && *strend != quote) {
  414.         if (*strend == '\\' && strend[1]) strend += 2;
  415.         else ++strend;
  416.     }
  417.     res = substring_conf (p, str + 1, strend - str - 1);
  418.  
  419.     if (*strend == quote) ++strend;
  420.     } else {
  421.         strend = str;
  422.     while (*strend && !isspace (*strend))
  423.         if (*strend == '\\' && strend[1]) strend += 2;
  424.         else ++strend;
  425.  
  426.     res = substring_conf (p, str, strend - str);
  427.     }
  428.  
  429.     while (*strend && isspace(*strend)) ++ strend;
  430.     *line = strend;
  431.     return res;
  432. }
  433.  
  434. void cfg_getword(char *word, char *line) {
  435.     int x=0,y;
  436.     
  437.     for(x=0;line[x] && isspace(line[x]);x++);
  438.     y=0;
  439.     while(1) {
  440.         if(!(word[y] = line[x]))
  441.             break;
  442.         if(isspace(line[x]))
  443.             if((!x) || (line[x-1] != '\\'))
  444.                 break;
  445.         if(line[x] != '\\') ++y;
  446.         ++x;
  447.     }
  448.     word[y] = '\0';
  449.     while(line[x] && isspace(line[x])) ++x;
  450.     for(y=0;(line[y] = line[x]);++x,++y);
  451. }
  452.  
  453. int
  454. cfg_getline(char *s, int n, FILE *f) {
  455.     register int i=0, c;
  456.  
  457.     s[0] = '\0';
  458.     /* skip leading whitespace */
  459.     do {
  460.         c = getc(f);
  461.     } while (c == '\t' || c == ' ');
  462.  
  463.     while(1) {
  464.         if((c == '\t') || (c == ' ')) {
  465.             s[i++] = ' ';
  466.             while((c == '\t') || (c == ' ')) 
  467.                 c = getc(f);
  468.         }
  469.         if(c == CR) {
  470.             c = getc(f);
  471.         }
  472.         if(c == EOF || c == 0x4 || c == LF || i == (n-1)) {
  473.             /* blast trailing whitespace */
  474.             while(i && (s[i-1] == ' ')) --i;
  475.             s[i] = '\0';
  476.             return (feof(f) ? 1 : 0);
  477.         }
  478.         s[i] = c;
  479.         ++i;
  480.         c = getc(f);
  481.     }
  482. }
  483.  
  484. /* Retrieve a token, spacing over it and returning a pointer to
  485.  * the first non-white byte afterwards.  Note that these tokens
  486.  * are delimited by semis and commas; and can also be delimited
  487.  * by whitespace at the caller's option.
  488.  */
  489.  
  490. char *get_token (pool *p, char **accept_line, int accept_white)
  491. {
  492.     char *ptr = *accept_line;
  493.     char *tok_start;
  494.     char *token;
  495.     int tok_len;
  496.   
  497.     /* Find first non-white byte */
  498.     
  499.     while (*ptr && isspace(*ptr))
  500.       ++ptr;
  501.  
  502.     tok_start = ptr;
  503.     
  504.     /* find token end, skipping over quoted strings.
  505.      * (comments are already gone).
  506.      */
  507.     
  508.     while (*ptr && (accept_white || !isspace(*ptr))
  509.        && *ptr != ';' && *ptr != ',')
  510.     {
  511.     if (*ptr++ == '"')
  512.         while (*ptr)
  513.             if (*ptr++ == '"') break;
  514.     }
  515.       
  516.     tok_len = ptr - tok_start;
  517.     token = palloc (p, tok_len + 1);
  518.     strncpy (token, tok_start, tok_len);
  519.     token[tok_len] = '\0';
  520.     
  521.     /* Advance accept_line pointer to the next non-white byte */
  522.  
  523.     while (*ptr && isspace(*ptr))
  524.       ++ptr;
  525.  
  526.     *accept_line = ptr;
  527.     return token;
  528. }
  529.  
  530. char *escape_shell_cmd(pool *p, char *s) {
  531.     register int x,y,l;
  532.     char *cmd;
  533.  
  534.     l=strlen(s);
  535.     cmd = palloc (p, 2 * l + 1); /* Be safe */
  536.     strcpy (cmd, s);
  537.     
  538.     for(x=0;cmd[x];x++) {
  539.     
  540. #ifdef __EMX__
  541.         /* Don't allow '&' in parameters under OS/2. */
  542.         /* This can be used to send commands to the shell. */
  543.         if (cmd[x] == '&') {
  544.             cmd[x] = ' ';
  545.         }
  546. #endif
  547.  
  548.         if(ind("&;`'\"|*?~<>^()[]{}$\\\n",cmd[x]) != -1){
  549.             for(y=l+1;y>x;y--)
  550.                 cmd[y] = cmd[y-1];
  551.             l++; /* length has been increased */
  552.             cmd[x] = '\\';
  553.             x++; /* skip the character */
  554.         }
  555.     }
  556.  
  557.     return cmd;
  558. }
  559.  
  560. void plustospace(char *str) {
  561.     register int x;
  562.  
  563.     for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' ';
  564. }
  565.  
  566. void spacetoplus(char *str) {
  567.     register int x;
  568.  
  569.     for(x=0;str[x];x++) if(str[x] == ' ') str[x] = '+';
  570. }
  571.  
  572. char x2c(char *what) {
  573.     register char digit;
  574.  
  575.     digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
  576.     digit *= 16;
  577.     digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
  578.     return(digit);
  579. }
  580.  
  581. /*
  582.  * Unescapes a URL.
  583.  * Returns 0 on success, non-zero on error
  584.  * Failure is due to
  585.  *   bad % escape       returns BAD_REQUEST
  586.  *
  587.  *   decoding %00 -> \0
  588.  *   decoding %2f -> /   (a special character)
  589.  *                      returns NOT_FOUND
  590.  */
  591. int
  592. unescape_url(char *url) {
  593.     register int x,y, badesc, badpath;
  594.  
  595.     badesc = 0;
  596.     badpath = 0;
  597.     for(x=0,y=0;url[y];++x,++y) {
  598.     if (url[y] != '%') url[x] = url[y];
  599.     else
  600.     {
  601.         if (!isxdigit(url[y+1]) || !isxdigit(url[y+2]))
  602.         {
  603.         badesc = 1;
  604.         url[x] = '%';
  605.         } else
  606.         {
  607.         url[x] = x2c(&url[y+1]);
  608.         y += 2;
  609.         if (url[x] == '/' || url[x] == '\0') badpath = 1;
  610.         }
  611.         }
  612.     }
  613.     url[x] = '\0';
  614.     if (badesc) return BAD_REQUEST;
  615.     else if (badpath) return NOT_FOUND;
  616.     else return OK;
  617. }
  618.  
  619. char *construct_url(pool *p, char *uri, server_rec *s) {
  620.     char portnum[10];        /* Long enough.  Really! */
  621.   
  622.     if (s->port == 80) {
  623.         return pstrcat (p, "http://", s->server_hostname, uri, NULL);
  624.     } else {
  625.         sprintf (portnum, "%d", s->port);
  626.     return pstrcat (p, "http://", s->server_hostname, ":", portnum, uri,
  627.             NULL);
  628.     }
  629. }
  630.  
  631. #define c2x(what,where) sprintf(where,"%%%02x",what)
  632.  
  633. /*
  634. escape_path_segment() escapes a path segment, as defined in RFC 1808. This
  635. routine is (should be) OS independent.
  636.  
  637. os_escape_path() converts an OS path to a URL, in an OS dependent way. In all
  638. cases if a ':' occurs before the first '/' in the URL, the URL should be
  639. prefixed with "./" (or the ':' escaped). In the case of Unix, this means
  640. leaving '/' alone, but otherwise doing what escape_path_segment() does. For
  641. efficiency reasons, we don't use escape_path_segment(), which is provided for
  642. reference. Again, RFC 1808 is where this stuff is defined.
  643.  
  644. If partial is set, os_escape_path() assumes that the path will be appended to
  645. something with a '/' in it (and thus does not prefix "./").
  646. */
  647.  
  648. char *escape_path_segment(pool *p, const char *segment) {
  649.     register int x,y;
  650.     char *copy = palloc (p, 3 * strlen (segment) + 1);
  651.             
  652.     for(x=0,y=0; segment[x]; x++,y++) {
  653.       char c=segment[x];
  654.       if((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c >'9')
  655.      && ind("$-_.+!*'(),:@&=~",c) == -1)
  656.     {
  657.       c2x(c,©[y]);
  658.       y+=2;
  659.     }
  660.       else
  661.     copy[y]=c;
  662.     }
  663.     copy[y] = '\0';
  664.     return copy;
  665. }
  666.  
  667. char *os_escape_path(pool *p,const char *path,int partial) {
  668.   char *copy=palloc(p,3*strlen(path)+3);
  669.   char *s=copy;
  670.  
  671.   if(!partial)
  672.     {
  673.       int colon=ind(path,':');
  674.       int slash=ind(path,'/');
  675.  
  676.       if(colon >= 0 && (colon < slash || slash < 0))
  677.     {
  678.       *s++='.';
  679.       *s++='/';
  680.     }
  681.     }
  682.   for( ; *path ; ++path)
  683.     {
  684.       char c=*path;
  685.       if((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && (c < '0' || c >'9')
  686.      && ind("$-_.+!*'(),:@&=/~",c) == -1)
  687.     {
  688.       c2x(c,s);
  689.       s+=3;
  690.     }
  691.       else
  692.     *s++=c;
  693.     }
  694.   *s='\0';
  695.   return copy;
  696. }
  697.  
  698. char *escape_uri(pool *p, char *uri) {
  699.     register int x,y;
  700.     char *copy = palloc (p, 3 * strlen (uri) + 1);
  701.             
  702.     for(x=0,y=0; uri[x]; x++,y++) {
  703.         if (ind (":% ?+&",(copy[y] = uri[x])) != -1) {
  704.             c2x(uri[x],©[y]);
  705.             y+=2;
  706.         }
  707.     }
  708.     copy[y] = '\0';
  709.     return copy;
  710. }
  711.  
  712. char *
  713. escape_html(pool *p, const char *s)
  714. {
  715.     int i, j;
  716.     char *x;
  717.  
  718. /* first, count the number of extra characters */
  719.     for (i=0, j=0; s[i] != '\0'; i++)
  720.     if (s[i] == '<' || s[i] == '>') j += 3;
  721.     else if (s[i] == '&') j += 4;
  722.  
  723.     if (j == 0) return pstrdup(p, s);
  724.     x = palloc(p, i + j + 1);
  725.     for (i=0, j=0; s[i] != '\0'; i++, j++)
  726.     if (s[i] == '<')
  727.     {
  728.         memcpy(&x[j], "<", 4);
  729.         j += 3;
  730.     } else if (s[i] == '>')
  731.     {
  732.         memcpy(&x[j], ">", 4);
  733.         j += 3;
  734.     } else if (s[i] == '&')
  735.     {
  736.         memcpy(&x[j], "&", 5);
  737.         j += 4;
  738.     } else
  739.             x[j] = s[i];
  740.  
  741.     x[j] = '\0';
  742.     return x;
  743. }
  744.  
  745. #ifdef NOTDEF
  746.  
  747. void escape_url(char *url) {
  748.     register int x,y;
  749.     register char digit;
  750.     char *copy;
  751.  
  752.     copy = strdup(url);
  753.             
  754.     for(x=0,y=0;copy[x];x++,y++) {
  755.         if(ind("% ?+&",url[y] = copy[x]) != -1) {
  756.             c2x(copy[x],&url[y]);
  757.             y+=2;
  758.         }
  759.     }
  760.     url[y] = '\0';
  761.     free(copy);
  762. }
  763.  
  764. #endif
  765.  
  766. int is_directory(char *path) {
  767.     struct stat finfo;
  768.  
  769.     if(stat(path,&finfo) == -1)
  770.         return 0; /* in error condition, just return no */
  771.  
  772.     return(S_ISDIR(finfo.st_mode));
  773. }
  774.  
  775. char *make_full_path(pool *a, char *src1,char *src2) {
  776.     register int x;
  777.  
  778.     x = strlen(src1);
  779.     if (x == 0) return pstrcat (a, "/", src2, NULL);
  780.  
  781.     if (src1[x - 1] != '/') return pstrcat (a, src1, "/", src2, NULL);
  782.     else return pstrcat (a, src1, src2, NULL);
  783. }
  784.  
  785. int is_url(char *u) {
  786.     register int x;
  787.  
  788.     for(x=0;u[x] != ':';x++)
  789.         if((!u[x]) || (!isalpha(u[x])))
  790.             return 0;
  791.  
  792.     if((u[x+1] == '/') && (u[x+2] == '/'))
  793.         return 1;
  794.     else return 0;
  795. }
  796.  
  797. int can_exec(struct stat *finfo) {
  798. #ifdef __EMX__
  799.     /* OS/2 dosen't have Users and Groups */
  800.     return (finfo->st_mode & S_IEXEC);
  801. #else    
  802.     if(user_id == finfo->st_uid)
  803.         if(finfo->st_mode & S_IXUSR)
  804.             return 1;
  805.     if(group_id == finfo->st_gid)
  806.         if(finfo->st_mode & S_IXGRP)
  807.             return 1;
  808.     return (finfo->st_mode & S_IXOTH);
  809. #endif    
  810. }
  811.  
  812. #ifdef NEED_STRDUP
  813. char *strdup (char *str)
  814. {
  815.   char *dup;
  816.  
  817.   if(!(dup = (char *)malloc (strlen (str) + 1)))
  818.       return NULL;
  819.   dup = strcpy (dup, str);
  820.  
  821.   return dup;
  822. }
  823. #endif
  824.  
  825. /* The following two routines were donated for SVR4 by Andreas Vogel */
  826. #ifdef NEED_STRCASECMP
  827. int strcasecmp (const char *a, const char *b)
  828. {
  829.     const char *p = a;
  830.     const char *q = b;
  831.     for (p = a, q = b; *p && *q; p++, q++)
  832.     {
  833.       int diff = tolower(*p) - tolower(*q);
  834.       if (diff) return diff;
  835.     }
  836.     if (*p) return 1;       /* p was longer than q */
  837.     if (*q) return -1;      /* p was shorter than q */
  838.     return 0;               /* Exact match */
  839. }
  840.  
  841. #endif
  842.  
  843. #ifdef NEED_STRNCASECMP
  844. int strncasecmp (const char *a, const char *b, int n)
  845. {
  846.     const char *p = a;
  847.     const char *q = b;
  848.  
  849.     for (p = a, q = b; /*NOTHING*/; p++, q++)
  850.     {
  851.       int diff;
  852.       if (p == a + n) return 0;     /*   Match up to n characters */
  853.       if (!(*p && *q)) return *p - *q;
  854.       diff = tolower(*p) - tolower(*q);
  855.       if (diff) return diff;
  856.     }
  857.     /*NOTREACHED*/
  858. }
  859. #endif
  860.  
  861.  
  862.  
  863. #ifdef NEED_INITGROUPS
  864. int initgroups(const char *name, gid_t basegid)
  865. {
  866. #ifdef QNX
  867. /* QNX does not appear to support supplementary groups.
  868. Ben <ben@algroup.co.uk> */
  869.     return 0;
  870. #else /* ndef QNX */
  871.   gid_t groups[NGROUPS_MAX];
  872.   struct group *g;
  873.   int index = 0;
  874.  
  875.   setgrent();
  876.  
  877.   groups[index++] = basegid;
  878.  
  879.   while (index < NGROUPS_MAX && ((g = getgrent()) != NULL))
  880.     if (g->gr_gid != basegid)
  881.     {
  882.       char **names;
  883.  
  884.       for (names = g->gr_mem; *names != NULL; ++names)
  885.         if (!strcmp(*names, name))
  886.           groups[index++] = g->gr_gid;
  887.     }
  888.  
  889.   endgrent();
  890.  
  891.   return setgroups(index, groups);
  892. #endif /* def QNX */
  893. }
  894. #endif /* def NEED_INITGROUPS */
  895.  
  896. #ifdef NEED_WAITPID
  897. /* From ikluft@amdahl.com */
  898. /* this is not ideal but it works for SVR3 variants */
  899. /* httpd does not use the options so this doesn't implement them */
  900. int waitpid(pid_t pid, int *statusp, int options)
  901. {
  902.     int tmp_pid;
  903.     if ( kill ( pid,0 ) == -1) {
  904.         errno=ECHILD;
  905.         return -1;
  906.     }
  907.     while ((( tmp_pid = wait(statusp)) != pid) && ( tmp_pid != -1 ));
  908.     return tmp_pid;
  909. }
  910. #endif
  911.  
  912. int ind(const char *s, char c) {
  913.     register int x;
  914.  
  915.     for(x=0;s[x];x++)
  916.         if(s[x] == c) return x;
  917.  
  918.     return -1;
  919. }
  920.  
  921. int rind(const char *s, char c) {
  922.     register int x;
  923.  
  924.     for(x=strlen(s)-1;x != -1;x--)
  925.         if(s[x] == c) return x;
  926.  
  927.     return -1;
  928. }
  929.  
  930. void str_tolower(char *str) {
  931.     while(*str) {
  932.         *str = tolower(*str);
  933.         ++str;
  934.     }
  935. }
  936.         
  937. uid_t uname2id(char *name) {
  938.     struct passwd *ent;
  939.  
  940.     if(name[0] == '#') 
  941.         return(atoi(&name[1]));
  942.  
  943.     if(!(ent = getpwnam(name))) {
  944.         fprintf(stderr,"httpd: bad user name %s\n",name);
  945.         exit(1);
  946.     }
  947.     else return(ent->pw_uid);
  948. }
  949.  
  950. gid_t gname2id(char *name) {
  951.     struct group *ent;
  952.  
  953.     if(name[0] == '#') 
  954.         return(atoi(&name[1]));
  955.  
  956.     if(!(ent = getgrnam(name))) {
  957.         fprintf(stderr,"httpd: bad group name %s\n",name);
  958.         exit(1);
  959.     }
  960.     else return(ent->gr_gid);
  961. }
  962.  
  963. #if 0
  964. int get_portnum(int sd) {
  965.     struct sockaddr addr;
  966.     int len;
  967.  
  968.     len = sizeof(struct sockaddr);
  969.     if(getsockname(sd,&addr,&len) < 0)
  970.         return -1;
  971.     return ntohs(((struct sockaddr_in *)&addr)->sin_port);
  972. }
  973.  
  974. struct in_addr get_local_addr(int sd) {
  975.     struct sockaddr addr;
  976.     int len;
  977.  
  978.     len = sizeof(struct sockaddr);
  979.     if(getsockname(sd,&addr,&len) < 0) {
  980.         fprintf (stderr, "Can't get local host address!\n");
  981.     perror ("getsockname");
  982.     exit(1);
  983.     }
  984.          
  985.     return ((struct sockaddr_in *)&addr)->sin_addr;
  986. }
  987. #endif
  988.  
  989. /*
  990.  * Parses a host of the form <address>[:port]
  991.  * :port is permitted if 'port' is not NULL
  992.  */
  993. unsigned long get_virthost_addr (char *w, short int *ports) {
  994.     struct hostent *hep;
  995.     unsigned long my_addr;
  996.     char *p;
  997.  
  998.     p = strchr(w, ':');
  999.     if (ports != NULL)
  1000.     {
  1001.     *ports = 0;
  1002.     if (p != NULL && strcmp(p+1, "*") != 0) *ports = atoi(p+1);
  1003.     }
  1004.  
  1005.     if (p != NULL) *p = '\0';
  1006.     if (strcmp(w, "*") == 0)
  1007.     {
  1008.     if (p != NULL) *p = ':';
  1009.     return htonl(INADDR_ANY);
  1010.     }
  1011.     
  1012. #ifdef DGUX
  1013.     my_addr = inet_network(w);
  1014. #else
  1015.     my_addr = inet_addr(w);
  1016. #endif
  1017.     if (my_addr != ((unsigned long) 0xffffffff))
  1018.     {
  1019.     if (p != NULL) *p = ':';
  1020.     return my_addr;
  1021.     }
  1022.  
  1023.     hep = gethostbyname(w);
  1024.         
  1025.     if ((!hep) || (hep->h_addrtype != AF_INET || !hep->h_addr_list[0])) {
  1026.     fprintf (stderr, "Cannot resolve host name %s --- exiting!\n", w);
  1027.     exit(1);
  1028.     }
  1029.         
  1030.     if (hep->h_addr_list[1]) {
  1031.     fprintf(stderr, "Host %s has multiple addresses ---\n", w);
  1032.     fprintf(stderr, "you must choose one explicitly for use as\n");
  1033.     fprintf(stderr, "a virtual host.  Exiting!!!\n");
  1034.     exit(1);
  1035.     }
  1036.         
  1037.     if (p != NULL) *p = ':';
  1038.  
  1039.     return ((struct in_addr *)(hep->h_addr))->s_addr;
  1040. }
  1041.  
  1042.  
  1043. #ifdef NOTDEF    
  1044.     
  1045. char *get_remote_logname(FILE *fd) {
  1046.     int len;
  1047.     char *result;
  1048. #if defined(NEXT) || defined(BSD4_4) || defined(SOLARIS2) || defined(LINUX) || defined(__EMX__)
  1049.     struct sockaddr sa_server, sa_client;
  1050. #else
  1051.     struct sockaddr_in sa_server,sa_client;
  1052. #endif
  1053.  
  1054.     len = sizeof(sa_client);
  1055.     if(getpeername(fileno(stdout),&sa_client,&len) != -1) {
  1056.         len = sizeof(sa_server);
  1057.         if(getsockname(fileno(stdout),&sa_server,&len) == -1)
  1058.             result = "unknown";
  1059.         else
  1060.             result = rfc931((struct sockaddr_in *) & sa_client,
  1061.                                     (struct sockaddr_in *) & sa_server);
  1062.     }
  1063.     else result = "unknown";
  1064.  
  1065.     return result; /* robm=pinhead */
  1066. }
  1067. #endif    
  1068.  
  1069. static char *find_fqdn(pool *a, struct hostent *p) {
  1070.     int x;
  1071.  
  1072.     if(ind(p->h_name,'.') == -1) {
  1073.         for(x=0;p->h_aliases[x];++x) {
  1074.             if((ind(p->h_aliases[x],'.') != -1) && 
  1075.                (!strncmp(p->h_aliases[x],p->h_name,strlen(p->h_name))))
  1076.                 return pstrdup(a, p->h_aliases[x]);
  1077.         }
  1078.         return NULL;
  1079.     } else return pstrdup(a, (void *)p->h_name);
  1080. }
  1081.  
  1082. char *get_local_host(pool *a)
  1083. {
  1084.     char str[128];
  1085.     int len = 128;
  1086.     char *server_hostname;
  1087.  
  1088.     struct hostent *p;
  1089.     gethostname(str, len);
  1090.     if((!(p=gethostbyname(str))) || (!(server_hostname = find_fqdn(a, p)))) {
  1091.         fprintf(stderr,"httpd: cannot determine local host name.\n");
  1092.     fprintf(stderr,"Use ServerName to set it manually.\n");
  1093.     exit(1);
  1094.     }
  1095.  
  1096.     return server_hostname;
  1097. }
  1098.  
  1099. /* aaaack but it's fast and const should make it shared text page. */
  1100. const int pr2six[256]={
  1101.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1102.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
  1103.     52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
  1104.     10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
  1105.     28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
  1106.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1107.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1108.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1109.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1110.     64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
  1111.     64,64,64,64,64,64,64,64,64,64,64,64,64
  1112. };
  1113.  
  1114. char *uudecode(pool *p, char *bufcoded) {
  1115.     int nbytesdecoded;
  1116.     register unsigned char *bufin;
  1117.     register char *bufplain;
  1118.     register unsigned char *bufout;
  1119.     register int nprbytes;
  1120.     
  1121.     /* Strip leading whitespace. */
  1122.     
  1123.     while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
  1124.     
  1125.     /* Figure out how many characters are in the input buffer.
  1126.      * Allocate this many from the per-transaction pool for the result.
  1127.      */
  1128.     bufin = (unsigned char *)bufcoded;
  1129.     while(pr2six[*(bufin++)] <= 63);
  1130.     nprbytes = (char *)bufin - bufcoded - 1;
  1131.     nbytesdecoded = ((nprbytes+3)/4) * 3;
  1132.  
  1133.     bufplain = palloc(p, nbytesdecoded + 1);
  1134.     bufout = (unsigned char *)bufplain;
  1135.     
  1136.     bufin = (unsigned char *)bufcoded;
  1137.     
  1138.     while (nprbytes > 0) {
  1139.         *(bufout++) = 
  1140.             (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
  1141.         *(bufout++) = 
  1142.             (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
  1143.         *(bufout++) = 
  1144.             (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
  1145.         bufin += 4;
  1146.         nprbytes -= 4;
  1147.     }
  1148.     
  1149.     if(nprbytes & 03) {
  1150.         if(pr2six[bufin[-2]] > 63)
  1151.             nbytesdecoded -= 2;
  1152.         else
  1153.             nbytesdecoded -= 1;
  1154.     }
  1155.     bufplain[nbytesdecoded] = '\0';
  1156.     return bufplain;
  1157. }
  1158.  
  1159. #ifdef __EMX__
  1160. void os2pathname(char *path) {
  1161.     char newpath[MAX_STRING_LEN];
  1162.     int loop;
  1163.     int offset;
  1164.  
  1165.     offset = 0;
  1166.     for (loop=0; loop < (strlen(path) + 1); loop++) {
  1167.         if (path[loop] == '/') {
  1168.             newpath[offset] = '\\';
  1169.             /*
  1170.             offset = offset + 1;
  1171.             newpath[offset] = '\\';
  1172.             */
  1173.         } else
  1174.             newpath[offset] = path[loop];
  1175.         offset = offset + 1;
  1176.     };
  1177.     /* Debugging code */
  1178.     /* fprintf(stderr, "%s \n", newpath); */
  1179.  
  1180.     strcpy(path, newpath);
  1181. };
  1182. #endif
  1183.  
  1184.  
  1185. #ifdef NEED_STRERROR
  1186. char *
  1187. strerror (int err) {
  1188.  
  1189.     char *p;
  1190.     extern char *const sys_errlist[];
  1191.  
  1192.     p = sys_errlist[err];
  1193.     return (p);
  1194. }
  1195. #endif
  1196.