You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ma...@hyperreal.org on 1998/01/05 21:51:43 UTC

cvs commit: apache/src mod_include.c

marc        98/01/05 12:51:43

  Modified:    src      Tag: APACHE_1_2_X mod_include.c
  Log:
  SECURITY: General mod_include cleanup, including fixing several
  possible buffer overflows and a possible infinite loop.  This
  cleanup was done against 1.3 code and then backported to 1.2.
  
  Dean says:
  
  - There were a few strncpy()s that didn't terminate the string... add
  safe_copy() which does strncpy the way it should be.
  
  - switch many MAX_STRING_LENs with sizeof(foo) for the right foo, just in
  case
  
  - add const liberally to assist diagnosis
  
  - fix two off-by-1 errors in get_tag() (it could be convinced to hammer
  one byte past end of buffer)
  
  - fix buffer overrun in get_directive()
  
  - fix PR#1203 in a way that's fine for 1.2.x, but needs WIN32 support in
  1.3
  
  - test a few more error conditions and report them rather than doing
  something lame
  
  - buffer overrun and infinite loop in parse_string() eliminated
  
  - removed unneeded test of palloc() and make_sub_pool() results against
  NULL
  
  - fix use of strncat which didn't \0 terminate the destination
  
  - handle_else/handle_endif/handle_set/handle_printenv error messages
  didn't include the filename
  
  Submitted by:	Dean Gaudet
  Reviewed by:	Martin Kraemer, Mark J Cox, Marc Slemko, Randy Terbush
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.33.2.8  +1310 -895 apache/src/mod_include.c
  
  Index: mod_include.c
  ===================================================================
  RCS file: /export/home/cvs/apache/src/mod_include.c,v
  retrieving revision 1.33.2.7
  retrieving revision 1.33.2.8
  diff -u -r1.33.2.7 -r1.33.2.8
  --- mod_include.c	1997/11/05 11:46:21	1.33.2.7
  +++ mod_include.c	1998/01/05 20:51:41	1.33.2.8
  @@ -20,7 +20,8 @@
    *
    * 4. The names "Apache Server" and "Apache Group" must not be used to
    *    endorse or promote products derived from this software without
  - *    prior written permission.
  + *    prior written permission. For written permission, please contact
  + *    apache@apache.org.
    *
    * 5. Redistributions of any form whatsoever must retain the following
    *    acknowledgment:
  @@ -91,18 +92,20 @@
   #define STARTING_SEQUENCE "<!--#"
   #define ENDING_SEQUENCE "-->"
   #define DEFAULT_ERROR_MSG "[an error occurred while processing this directive]"
  -#define DEFAULT_TIME_FORMAT "%A, %d-%b-%y %T %Z"
  +#define DEFAULT_TIME_FORMAT "%A, %d-%b-%Y %H:%M:%S %Z"
   #define SIZEFMT_BYTES 0
   #define SIZEFMT_KMG 1
   
  -static void decodehtml(char *s);
  -static char *get_tag(pool *p, FILE *in, char *tag, int tag_len, int dodecode);
  -static int get_directive(FILE *in, char *d, pool *p);
   
  +static void safe_copy(char *dest, const char *src, size_t max_len)
  +{
  +    strncpy(dest, src, max_len - 1);
  +    dest[max_len - 1] = '\0';
  +}
   
   /* ------------------------ Environment function -------------------------- */
   
  -void add_include_vars(request_rec *r, char *timefmt)
  +static void add_include_vars(request_rec *r, char *timefmt)
   {
       struct passwd *pw;
       table *e = r->subprocess_env;
  @@ -111,28 +114,33 @@
   
       table_set(e, "DATE_LOCAL", ht_time(r->pool, date, timefmt, 0));
       table_set(e, "DATE_GMT", ht_time(r->pool, date, timefmt, 1));
  -    table_set(e, "LAST_MODIFIED",ht_time(r->pool,r->finfo.st_mtime,timefmt,0));
  +    table_set(e, "LAST_MODIFIED",
  +              ht_time(r->pool, r->finfo.st_mtime, timefmt, 0));
       table_set(e, "DOCUMENT_URI", r->uri);
       table_set(e, "DOCUMENT_PATH_INFO", r->path_info);
       pw = getpwuid(r->finfo.st_uid);
       if (pw) {
  -      table_set(e, "USER_NAME", pw->pw_name);
  -    } else {
  -      char uid[16];
  -      ap_snprintf(uid, sizeof(uid), "user#%lu", (unsigned long)r->finfo.st_uid);
  -      table_set(e, "USER_NAME", uid);
  +        table_set(e, "USER_NAME", pw->pw_name);
  +    }
  +    else {
  +        char uid[16];
  +        ap_snprintf(uid, sizeof(uid), "user#%lu",
  +                    (unsigned long) r->finfo.st_uid);
  +        table_set(e, "USER_NAME", uid);
       }
   
  -    if((t = strrchr(r->filename, '/')))
  -        table_set (e, "DOCUMENT_NAME", ++t);
  -    else
  -        table_set (e, "DOCUMENT_NAME", r->uri);
  +    if ((t = strrchr(r->filename, '/'))) {
  +        table_set(e, "DOCUMENT_NAME", ++t);
  +    }
  +    else {
  +        table_set(e, "DOCUMENT_NAME", r->uri);
  +    }
       if (r->args) {
  -	char *arg_copy = pstrdup (r->pool, r->args);
  +        char *arg_copy = pstrdup(r->pool, r->args);
   
  -        unescape_url (arg_copy);
  -	  table_set (e, "QUERY_STRING_UNESCAPED",
  -		   escape_shell_cmd (r->pool, arg_copy));
  +        unescape_url(arg_copy);
  +        table_set(e, "QUERY_STRING_UNESCAPED",
  +                  escape_shell_cmd(r->pool, arg_copy));
       }
   }
   
  @@ -148,9 +156,11 @@
    */
   #define PUT_CHAR(c,r) \
    { \
  -   outbuf[outind++] = c; \
  -   if (outind == OUTBUFSIZE) { FLUSH_BUF(r) }; \
  - } 
  +    outbuf[outind++] = c; \
  +    if (outind == OUTBUFSIZE) { \
  +        FLUSH_BUF(r) \
  +    }; \
  + }
   
   /* there SHOULD be some error checking on the return value of
    * rwrite, however it is unclear what the API for rwrite returning
  @@ -176,39 +186,42 @@
   #define GET_CHAR(f,c,ret,r) \
    { \
      int i = getc(f); \
  -   if(i == EOF) { /* either EOF or error -- needs error handling if latter */ \
  -       if (ferror(f)) \
  -	   fprintf(stderr, "encountered error in GET_CHAR macro, mod_include.\n"); \
  +   if (i == EOF) { /* either EOF or error -- needs error handling if latter */ \
  +       if (ferror(f)) { \
  +           fprintf(stderr, "encountered error in GET_CHAR macro, " \
  +                   "mod_include.\n"); \
  +       } \
          FLUSH_BUF(r); \
  -       pfclose(r->pool,f); \
  +       pfclose(r->pool, f); \
          return ret; \
      } \
      c = (char)i; \
    }
   
  -int find_string(FILE *in,char *str, request_rec *r, int printing) {
  -    int x,l=strlen(str),p;
  +static int find_string(FILE *in, const char *str, request_rec *r, int printing)
  +{
  +    int x, l = strlen(str), p;
       char outbuf[OUTBUFSIZE];
       int outind = 0;
       char c;
   
  -    p=0;
  -    while(1) {
  -        GET_CHAR(in,c,1,r);
  -        if(c == str[p]) {
  -            if((++p) == l) {
  -		FLUSH_BUF(r);
  +    p = 0;
  +    while (1) {
  +        GET_CHAR(in, c, 1, r);
  +        if (c == str[p]) {
  +            if ((++p) == l) {
  +                FLUSH_BUF(r);
                   return 0;
  -	    }
  +            }
           }
           else {
               if (printing) {
  -                for(x=0;x<p;x++) {
  -                    PUT_CHAR(str[x],r);
  +                for (x = 0; x < p; x++) {
  +                    PUT_CHAR(str[x], r);
                   }
  -                PUT_CHAR(c,r);
  +                PUT_CHAR(c, r);
               }
  -            p=0;
  +            p = 0;
           }
       }
   }
  @@ -219,10 +232,12 @@
   #define GET_CHAR(f,c,r,p) \
    { \
      int i = getc(f); \
  -   if(i == EOF) { /* either EOF or error -- needs error handling if latter */ \
  -       if (ferror(f)) \
  -	   fprintf(stderr, "encountered error in GET_CHAR macro, mod_include.\n"); \
  -       pfclose(p,f); \
  +   if (i == EOF) { /* either EOF or error -- needs error handling if latter */ \
  +       if (ferror(f)) { \
  +           fprintf(stderr, "encountered error in GET_CHAR macro, " \
  +                   "mod_include.\n"); \
  +       } \
  +       pfclose(p, f); \
          return r; \
      } \
      c = (char)i; \
  @@ -244,69 +259,79 @@
   
   /* The following is a shrinking transformation, therefore safe. */
   
  -static void
  -decodehtml(char *s)
  +static void decodehtml(char *s)
   {
       int val, i, j;
  -    char *p=s;
  -    char *ents;
  -    static char *entlist[MAXENTLEN+1]={
  -	NULL,  /* 0 */
  -	NULL,  /* 1 */
  -	"lt\074gt\076", /* 2 */
  -	"amp\046ETH\320eth\360", /* 3 */
  -	"quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml\353\
  -iuml\357ouml\366uuml\374yuml\377", /* 4 */
  -	"Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc\333\
  +    char *p = s;
  +    const char *ents;
  +    static const char * const entlist[MAXENTLEN + 1] =
  +    {
  +        NULL,                   /* 0 */
  +        NULL,                   /* 1 */
  +        "lt\074gt\076",         /* 2 */
  +        "amp\046ETH\320eth\360",        /* 3 */
  +        "quot\042Auml\304Euml\313Iuml\317Ouml\326Uuml\334auml\344euml\353\
  +iuml\357ouml\366uuml\374yuml\377",      /* 4 */
  +        "Acirc\302Aring\305AElig\306Ecirc\312Icirc\316Ocirc\324Ucirc\333\
   THORN\336szlig\337acirc\342aring\345aelig\346ecirc\352icirc\356ocirc\364\
  -ucirc\373thorn\376", /* 5 */
  -	"Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311\
  +ucirc\373thorn\376",            /* 5 */
  +        "Agrave\300Aacute\301Atilde\303Ccedil\307Egrave\310Eacute\311\
   Igrave\314Iacute\315Ntilde\321Ograve\322Oacute\323Otilde\325Oslash\330\
   Ugrave\331Uacute\332Yacute\335agrave\340aacute\341atilde\343ccedil\347\
   egrave\350eacute\351igrave\354iacute\355ntilde\361ograve\362oacute\363\
  -otilde\365oslash\370ugrave\371uacute\372yacute\375" /* 6 */
  +otilde\365oslash\370ugrave\371uacute\372yacute\375"     /* 6 */
       };
   
       for (; *s != '\0'; s++, p++) {
  -	if (*s != '&') {
  -	    *p = *s;
  -	    continue;
  -	}
  -	/* find end of entity */
  -	for (i=1; s[i] != ';' && s[i] != '\0'; i++)
  -	    continue;
  -
  -	if (s[i] == '\0') {	/* treat as normal data */
  -	    *p = *s;
  -	    continue;
  -	}
  +        if (*s != '&') {
  +            *p = *s;
  +            continue;
  +        }
  +        /* find end of entity */
  +        for (i = 1; s[i] != ';' && s[i] != '\0'; i++) {
  +            continue;
  +        }
   
  -	/* is it numeric ? */
  -	if (s[1] == '#') {
  -	    for (j=2, val=0; j < i && isdigit(s[j]); j++)
  -		val = val * 10 + s[j] - '0';
  -	    s += i;
  -	    if (j < i || val <= 8 || (val >= 11 && val <= 31) ||
  -		(val >= 127 && val <= 160) || val >= 256)
  -		p--;  /* no data to output */
  -	    else
  -		*p = val;
  -	} else{
  -	    j = i-1;
  -	    if (i-1 > MAXENTLEN || entlist[i-1] == NULL) { /* wrong length */
  -		*p = '&';
  -		continue;  /* skip it */
  -	    }
  -	    for (ents=entlist[i-1]; *ents != '\0'; ents += i)
  -		if (strncmp(s+1, ents, i-1) == 0) break;
  +        if (s[i] == '\0') {     /* treat as normal data */
  +            *p = *s;
  +            continue;
  +        }
   
  -	    if (*ents == '\0')
  -		*p = '&';  /* unknown */
  -	    else {
  -		*p = ((const unsigned char *)ents)[i-1];
  -		s += i;
  -	    }
  -	}
  +        /* is it numeric ? */
  +        if (s[1] == '#') {
  +            for (j = 2, val = 0; j < i && isdigit(s[j]); j++) {
  +                val = val * 10 + s[j] - '0';
  +            }
  +            s += i;
  +            if (j < i || val <= 8 || (val >= 11 && val <= 31) ||
  +                (val >= 127 && val <= 160) || val >= 256) {
  +                p--;            /* no data to output */
  +            }
  +            else {
  +                *p = val;
  +            }
  +        }
  +        else {
  +            j = i - 1;
  +            if (i - 1 > MAXENTLEN || entlist[i - 1] == NULL) {
  +                /* wrong length */
  +                *p = '&';
  +                continue;       /* skip it */
  +            }
  +            for (ents = entlist[i - 1]; *ents != '\0'; ents += i) {
  +                if (strncmp(s + 1, ents, i - 1) == 0) {
  +                    break;
  +                }
  +            }
  +
  +            if (*ents == '\0') {
  +                *p = '&';       /* unknown */
  +            }
  +            else {
  +                *p = ((const unsigned char *) ents)[i - 1];
  +                s += i;
  +            }
  +        }
       }
   
       *p = '\0';
  @@ -318,97 +343,117 @@
    * the tag value is html decoded if dodecode is non-zero
    */
   
  -static char *
  -get_tag(pool *p, FILE *in, char *tag, int tagbuf_len, int dodecode) {
  +static char *get_tag(pool *p, FILE *in, char *tag, int tagbuf_len, int dodecode)
  +{
       char *t = tag, *tag_val, c, term;
  -    int n;
   
  -    n = 0;
  +    /* makes code below a little less cluttered */
  +    --tagbuf_len;
   
  -    do { /* skip whitespace */
  -	GET_CHAR(in,c,NULL,p);
  +    do {                        /* skip whitespace */
  +        GET_CHAR(in, c, NULL, p);
       } while (isspace(c));
   
       /* tags can't start with - */
  -    if(c == '-') {
  -        GET_CHAR(in,c,NULL,p);
  -        if(c == '-') {
  +    if (c == '-') {
  +        GET_CHAR(in, c, NULL, p);
  +        if (c == '-') {
               do {
  -		GET_CHAR(in,c,NULL,p);
  -	    } while (isspace(c));
  -            if(c == '>') {
  -                strncpy(tag,"done", tagbuf_len-1);
  -		tag[tagbuf_len-1] = '\0';
  +                GET_CHAR(in, c, NULL, p);
  +            } while (isspace(c));
  +            if (c == '>') {
  +                safe_copy(tag, "done", tagbuf_len);
                   return tag;
               }
           }
  -	return NULL; /* failed */
  +        return NULL;            /* failed */
       }
   
       /* find end of tag name */
  -    while(1) {
  -        if(++n == tagbuf_len) {
  -            t[tagbuf_len - 1] = '\0';
  +    while (1) {
  +        if (t - tag == tagbuf_len) {
  +            *t = '\0';
               return NULL;
           }
  -	if(c == '=' || isspace(c)) break;
  -	*(t++) = tolower(c);
  -        GET_CHAR(in,c,NULL,p);
  +        if (c == '=' || isspace(c)) {
  +            break;
  +        }
  +        *(t++) = tolower(c);
  +        GET_CHAR(in, c, NULL, p);
       }
   
       *t++ = '\0';
       tag_val = t;
   
  -    while (isspace(c)) GET_CHAR(in, c, NULL,p); /* space before = */
  +    while (isspace(c)) {
  +        GET_CHAR(in, c, NULL, p);       /* space before = */
  +    }
       if (c != '=') {
           ungetc(c, in);
           return NULL;
       }
   
       do {
  -	GET_CHAR(in,c,NULL,p);  /* space after = */
  +        GET_CHAR(in, c, NULL, p);       /* space after = */
       } while (isspace(c));
   
       /* we should allow a 'name' as a value */
  -    
  -    if (c != '"' && c != '\'') return NULL;
  +
  +    if (c != '"' && c != '\'') {
  +        return NULL;
  +    }
       term = c;
  -    while(1) {
  -	GET_CHAR(in,c,NULL,p);
  -	if(++n == tagbuf_len) {
  -	    t[tagbuf_len - 1] = '\0';
  -	    return NULL;
  -	}
  +    while (1) {
  +        GET_CHAR(in, c, NULL, p);
  +        if (t - tag == tagbuf_len) {
  +            *t = '\0';
  +            return NULL;
  +        }
   /* Want to accept \" as a valid character within a string. */
  -	if (c == '\\') {
  -	    *(t++) = c; /* Add backslash */
  -	    GET_CHAR(in,c,NULL,p);
  -	    if (c == term) /* Only if */
  -		*(--t) = c; /* Replace backslash ONLY for terminator */
  -	} else if (c == term) break;
  -	*(t++) = c;
  +        if (c == '\\') {
  +            *(t++) = c;         /* Add backslash */
  +            GET_CHAR(in, c, NULL, p);
  +            if (c == term) {    /* Only if */
  +                *(--t) = c;     /* Replace backslash ONLY for terminator */
  +            }
  +        }
  +        else if (c == term) {
  +            break;
  +        }
  +        *(t++) = c;
       }
       *t = '\0';
  -    if (dodecode) decodehtml(tag_val);
  -    return pstrdup (p, tag_val);
  +    if (dodecode) {
  +        decodehtml(tag_val);
  +    }
  +    return pstrdup(p, tag_val);
   }
   
  -static int
  -get_directive(FILE *in, char *d, pool *p) {
  +static int get_directive(FILE *in, char *dest, size_t len, pool *p)
  +{
  +    char *d = dest;
       char c;
   
  +    /* make room for nul terminator */
  +    --len;
  +
       /* skip initial whitespace */
  -    while(1) {
  -        GET_CHAR(in,c,1,p);
  -        if(!isspace(c))
  +    while (1) {
  +        GET_CHAR(in, c, 1, p);
  +        if (!isspace(c)) {
               break;
  +        }
       }
       /* now get directive */
  -    while(1) {
  +    while (1) {
  +	if (d - dest == len) {
  +	    return 1;
  +	}
           *d++ = tolower(c);
  -        GET_CHAR(in,c,1,p);
  -        if(isspace(c))
  +        GET_CHAR(in, c, 1, p);
  +        if (isspace(c)) {
               break;
  +        }
       }
       *d = '\0';
       return 0;
  @@ -417,73 +462,95 @@
   /*
    * Do variable substitution on strings
    */
  -void parse_string(request_rec *r, char *in, char *out, int length,
  -                  int leave_name)
  +static void parse_string(request_rec *r, const char *in, char *out,
  +			size_t length, int leave_name)
   {
       char ch;
       char *next = out;
  -    int numchars = 0;
  +    char *end_out;
  +
  +    /* leave room for nul terminator */
  +    end_out = out + length - 1;
   
       while ((ch = *in++) != '\0') {
  -        switch(ch) {
  -          case '\\':
  -	    if(*in == '$')
  -		*next++=*in++;
  -	    else
  -		*next++=ch;
  -            break;
  -          case '$':
  -          {
  -            char var[MAX_STRING_LEN];
  -            char vtext[MAX_STRING_LEN];
  -            char *val;
  -            int braces=0;
  -            int vlen, vtlen;
  -            /* 
  -             * Keep the $ and { around because we do no substitution
  -             * if the variable isn't found
  -             */
  -            vlen = vtlen = 0;
  -            vtext[vtlen++] = ch;
  -            if (*in == '{') { braces = 1; vtext[vtlen++] = *in++; }
  -            while (*in != '\0') {
  -                if (vlen == (MAX_STRING_LEN - 1)) continue;
  -                if (braces == 1) {
  -                    if (*in == '}') break;
  -                }
  -                else if (! (isalpha((int)*in) || (*in == '_') || isdigit((int)*in)) ) break;
  -                if (vtlen < (MAX_STRING_LEN - 1)) vtext[vtlen++] = *in;
  -                var[vlen++] = *in++;
  -            }
  -            var[vlen] = vtext[vtlen] = '\0';
  -            if (braces == 1) {
  -                if (*in != '}') {
  -                    log_printf(r->server, "Invalid variable \"%s%s\"", vtext,in);
  -                    *next = '\0';
  -                    return;
  -                } else
  -                    in++;
  -            } 
  -
  -            val = (char *)NULL;
  -            if (var[0] == '\0') {
  -                val = &vtext[0];
  -            } else {
  -                val = table_get (r->subprocess_env, &var[0]);
  -                if (!val && leave_name)
  -                    val = &vtext[0];
  -            }
  -            while ((val != (char *)NULL) && (*val != '\0')) {
  -                *next++ = *val++;
  -                if (++numchars == (length -1)) break;
  +        switch (ch) {
  +        case '\\':
  +	    if (next == end_out) {
  +		/* truncated */
  +		*next = '\0';
  +		return;
  +	    }
  +            if (*in == '$') {
  +                *next++ = *in++;
  +            }
  +            else {
  +                *next++ = ch;
               }
               break;
  -          }
  -          default:
  +        case '$':
  +            {
  +		char var[MAX_STRING_LEN];
  +		const char *start_of_var_name;
  +		const char *end_of_var_name;	/* end of var name + 1 */
  +		const char *expansion;
  +		const char *val;
  +		size_t l;
  +
  +		/* guess that the expansion won't happen */
  +		expansion = in - 1;
  +		if (*in == '{') {
  +		    ++in;
  +		    start_of_var_name = in;
  +		    in = strchr(in, '}');
  +		    if (in == NULL) {
  +			log_printf(r->server,
  +				    "Missing '}' on variable \"%s\" in %s",
  +				    expansion, r->filename);
  +                        *next = '\0';
  +                        return;
  +                    }
  +		    end_of_var_name = in;
  +		    ++in;
  +		}
  +		else {
  +		    start_of_var_name = in;
  +		    while (isalnum(*in) || *in == '_') {
  +			++in;
  +		    }
  +		    end_of_var_name = in;
  +		}
  +		/* what a pain, too bad there's no table_getn where you can
  +		 * pass a non-nul terminated string */
  +		l = end_of_var_name - start_of_var_name;
  +		l = (l > sizeof(var) - 1) ? (sizeof(var) - 1) : l;
  +		memcpy(var, start_of_var_name, l);
  +		var[l] = '\0';
  +
  +		val = table_get(r->subprocess_env, var);
  +		if (val) {
  +		    expansion = val;
  +		    l = strlen(expansion);
  +		}
  +		else if (leave_name) {
  +		    l = in - expansion;
  +		}
  +		else {
  +		    break;	/* no expansion to be done */
  +		}
  +		l = (l > end_out - next) ? (end_out - next) : l;
  +		memcpy(next, expansion, l);
  +		next += l;
  +                break;
  +            }
  +        default:
  +	    if (next == end_out) {
  +		/* truncated */
  +		*next = '\0';
  +		return;
  +	    }
               *next++ = ch;
               break;
           }
  -        if (++numchars == (length -1)) break;
       }
       *next = '\0';
       return;
  @@ -491,23 +558,29 @@
   
   /* --------------------------- Action handlers ---------------------------- */
   
  -int include_cgi(char *s, request_rec *r)
  +static int include_cgi(char *s, request_rec *r)
   {
  -    request_rec *rr = sub_req_lookup_uri (s, r);
  +    request_rec *rr = sub_req_lookup_uri(s, r);
       int rr_status;
  -    
  -    if (rr->status != 200) return -1;
  -    
  +
  +    if (rr->status != HTTP_OK) {
  +        return -1;
  +    }
  +
       /* No hardwired path info or query allowed */
  -    
  -    if ((rr->path_info && rr->path_info[0]) || rr->args) return -1;
  -    if (rr->finfo.st_mode == 0) return -1;
  +
  +    if ((rr->path_info && rr->path_info[0]) || rr->args) {
  +        return -1;
  +    }
  +    if (rr->finfo.st_mode == 0) {
  +        return -1;
  +    }
   
       /* Script gets parameters of the *document*, for back compatibility */
  -    
  -    rr->path_info = r->path_info; /* painful to get right; see mod_cgi.c */
  +
  +    rr->path_info = r->path_info;       /* hard to get right; see mod_cgi.c */
       rr->args = r->args;
  -    
  +
       /* Force sub_req to be treated as a CGI request, even if ordinary
        * typing rules would have called it something else.
        */
  @@ -515,77 +588,117 @@
       rr->content_type = CGI_MAGIC_TYPE;
   
       /* Run it. */
  -    
  +
       rr_status = run_sub_req(rr);
       if (is_HTTP_REDIRECT(rr_status)) {
  -        char *location = table_get (rr->headers_out, "Location");
  +        char *location = table_get(rr->headers_out, "Location");
           location = escape_html(rr->pool, location);
  -	rvputs(r,"<A HREF=\"", location, "\">", location, "</A>", NULL);
  +        rvputs(r, "<A HREF=\"", location, "\">", location, "</A>", NULL);
       }
  -    
  -    destroy_sub_req (rr);
  +
  +    destroy_sub_req(rr);
       chdir_file(r->filename);
  -    
  +
       return 0;
   }
   
  -int handle_include(FILE *in, request_rec *r, char *error, int noexec) {
  +/* ensure that path is relative, and does not contain ".." elements
  + * ensentially ensure that it does not match the regex:
  + * (^/|(^|/)\.\.(/|$))
  + * XXX: this needs os abstraction... consider c:..\foo in win32
  + */
  +static int is_only_below(const char *path)
  +{
  +    if (path[0] == '/') {
  +	return 0;
  +    }
  +    if (path[0] == '.' && path[1] == '.'
  +	&& (path[2] == '\0' || path[2] == '/')) {
  +	return 0;
  +    }
  +    while (*path) {
  +	if (*path == '/' && path[1] == '.' && path[2] == '.'
  +	    && (path[3] == '\0' || path[3] == '/')) {
  +	    return 0;
  +	}
  +	++path;
  +    }
  +    return 1;
  +}
  +
  +static int handle_include(FILE *in, request_rec *r, const char *error, int noexec)
  +{
       char tag[MAX_STRING_LEN];
       char parsed_string[MAX_STRING_LEN];
       char *tag_val;
   
  -    while(1) {
  -        if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
  +    while (1) {
  +        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
               return 1;
  -        if(!strcmp(tag,"file") || !strcmp (tag, "virtual")) {
  -	    request_rec *rr=NULL;
  -	    char *error_fmt = NULL;
  -
  -            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
  -	    if (tag[0] == 'f')
  -	    { /* be safe; only files in this directory or below allowed */
  -		char tmp[MAX_STRING_LEN+2];
  -		ap_snprintf(tmp, sizeof(tmp), "/%s/", parsed_string);
  -		if (parsed_string[0] == '/' || strstr(tmp, "/../") != NULL)
  -		    error_fmt = "unable to include file \"%s\" in parsed file %s";
  -		else
  -		    rr = sub_req_lookup_file (parsed_string, r);
  -	    } else
  -		rr = sub_req_lookup_uri (parsed_string, r);
  -	    
  -	    if (!error_fmt && rr->status != 200)
  -	        error_fmt = "unable to include \"%s\" in parsed file %s";
  -
  -	    if (!error_fmt && noexec && rr->content_type
  -		&& (strncmp (rr->content_type, "text/", 5)))
  -	        error_fmt =
  -		  "unable to include potential exec \"%s\" in parsed file %s";
  -            if (error_fmt == NULL)
  -            {
  +        }
  +        if (!strcmp(tag, "file") || !strcmp(tag, "virtual")) {
  +            request_rec *rr = NULL;
  +            char *error_fmt = NULL;
  +
  +            parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
  +            if (tag[0] == 'f') {
  +                /* be safe; only files in this directory or below allowed */
  +		if (!is_only_below(parsed_string)) {
  +                    error_fmt = "unable to include file \"%s\" "
  +                        "in parsed file %s";
  +                }
  +                else {
  +                    rr = sub_req_lookup_file(parsed_string, r);
  +                }
  +            }
  +            else {
  +                rr = sub_req_lookup_uri(parsed_string, r);
  +            }
  +
  +            if (!error_fmt && rr->status != HTTP_OK) {
  +                error_fmt = "unable to include \"%s\" in parsed file %s";
  +            }
  +
  +            if (!error_fmt && noexec && rr->content_type
  +                && (strncmp(rr->content_type, "text/", 5))) {
  +                error_fmt = "unable to include potential exec \"%s\" "
  +                    "in parsed file %s";
  +            }
  +            if (error_fmt == NULL) {
                   request_rec *p;
   
  -                for (p=r; p != NULL; p=p->main)
  -                    if (strcmp(p->filename, rr->filename) == 0) break;
  -                if (p != NULL)
  -                    error_fmt = "Recursive include of \"%s\" in parsed file %s";
  -            }
  -	    
  -	    if (!error_fmt && run_sub_req (rr))
  -	        error_fmt = "unable to include \"%s\" in parsed file %s";
  -	    chdir_file(r->filename);
  -		    
  +                for (p = r; p != NULL; p = p->main) {
  +                    if (strcmp(p->filename, rr->filename) == 0) {
  +                        break;
  +                    }
  +                }
  +                if (p != NULL) {
  +                    error_fmt = "Recursive include of \"%s\" "
  +                        "in parsed file %s";
  +                }
  +            }
  +
  +            if (!error_fmt && run_sub_req(rr)) {
  +                error_fmt = "unable to include \"%s\" in parsed file %s";
  +            }
  +            chdir_file(r->filename);
  +
               if (error_fmt) {
                   log_printf(r->server, error_fmt, tag_val, r->filename);
                   rputs(error, r);
  -            }            
  +            }
   
  -	    if (rr != NULL) destroy_sub_req (rr);
  -        } 
  -        else if(!strcmp(tag,"done"))
  +            if (rr != NULL) {
  +                destroy_sub_req(rr);
  +            }
  +        }
  +        else if (!strcmp(tag, "done")) {
               return 0;
  +        }
           else {
  -            log_printf(r->server, "unknown parameter \"%s\" to tag include in %s",
  -                       tag, r->filename);
  +            log_printf(r->server,
  +                        "unknown parameter \"%s\" to tag include in %s",
  +                        tag, r->filename);
               rputs(error, r);
           }
       }
  @@ -596,170 +709,194 @@
       char *s;
   } include_cmd_arg;
   
  -void include_cmd_child (void *arg)
  +static void include_cmd_child(void *arg)
   {
  -    request_rec *r =  ((include_cmd_arg *)arg)->r;
  -    char *s = ((include_cmd_arg *)arg)->s;
  +    request_rec *r = ((include_cmd_arg *) arg)->r;
  +    char *s = ((include_cmd_arg *) arg)->s;
       table *env = r->subprocess_env;
  -#ifdef DEBUG_INCLUDE_CMD    
  -    FILE *dbg = fopen ("/dev/tty", "w");
  -#endif    
  -    char err_string [MAX_STRING_LEN];
  +#ifdef DEBUG_INCLUDE_CMD
  +    FILE *dbg = fopen("/dev/tty", "w");
  +#endif
  +    char err_string[MAX_STRING_LEN];
   
  -#ifdef DEBUG_INCLUDE_CMD    
  +#ifdef DEBUG_INCLUDE_CMD
   #ifdef __EMX__
       /* under OS/2 /dev/tty is referenced as con */
  -    FILE *dbg = fopen ("con", "w");
  +    FILE *dbg = fopen("con", "w");
   #else
  -    fprintf (dbg, "Attempting to include command '%s'\n", s);
  -#endif    
  -#endif    
  +    fprintf(dbg, "Attempting to include command '%s'\n", s);
  +#endif
  +#endif
   
  -    if (r->path_info && r->path_info[0] != '\0')
  -    {
  -	request_rec *pa_req;
  +    if (r->path_info && r->path_info[0] != '\0') {
  +        request_rec *pa_req;
  +
  +        table_set(env, "PATH_INFO", escape_shell_cmd(r->pool, r->path_info));
   
  -	table_set (env, "PATH_INFO", escape_shell_cmd (r->pool, r->path_info));
  -	
  -	pa_req = sub_req_lookup_uri(escape_uri(r->pool, r->path_info), r);
  -	if (pa_req->filename)
  -	    table_set(env, "PATH_TRANSLATED",
  -		      pstrcat(r->pool, pa_req->filename, pa_req->path_info,
  -			      NULL));
  +        pa_req = sub_req_lookup_uri(escape_uri(r->pool, r->path_info), r);
  +        if (pa_req->filename) {
  +            table_set(env, "PATH_TRANSLATED",
  +                      pstrcat(r->pool, pa_req->filename, pa_req->path_info,
  +                              NULL));
  +        }
       }
   
       if (r->args) {
  -	char *arg_copy = pstrdup (r->pool, r->args);
  +        char *arg_copy = pstrdup(r->pool, r->args);
  +
  +        table_set(env, "QUERY_STRING", r->args);
  +        unescape_url(arg_copy);
  +        table_set(env, "QUERY_STRING_UNESCAPED",
  +                  escape_shell_cmd(r->pool, arg_copy));
  +    }
   
  -        table_set (env, "QUERY_STRING", r->args);
  -	unescape_url (arg_copy);
  -	table_set (env, "QUERY_STRING_UNESCAPED",
  -		   escape_shell_cmd (r->pool, arg_copy));
  -    }
  -    
  -    error_log2stderr (r->server);
  -    
  -#ifdef DEBUG_INCLUDE_CMD    
  -    fprintf (dbg, "Attempting to exec '%s'\n", s);
  -#endif    
  +    error_log2stderr(r->server);
  +
  +#ifdef DEBUG_INCLUDE_CMD
  +    fprintf(dbg, "Attempting to exec '%s'\n", s);
  +#endif
       cleanup_for_exec();
       /* set shellcmd flag to pass arg to SHELL_PATH */
  -    call_exec(r, s, create_environment (r->pool, env), 1);
  -    
  +    call_exec(r, s, create_environment(r->pool, env), 1);
       /* Oh, drat.  We're still here.  The log file descriptors are closed,
        * so we have to whimper a complaint onto stderr...
        */
  -    
  -#ifdef DEBUG_INCLUDE_CMD    
  -    fprintf (dbg, "Exec failed\n");
  -#endif    
  +
  +#ifdef DEBUG_INCLUDE_CMD
  +    fprintf(dbg, "Exec failed\n");
  +#endif
       ap_snprintf(err_string, sizeof(err_string),
  -	"httpd: exec of %s failed, reason: %s (errno = %d)\n",
  -	SHELL_PATH, strerror(errno), errno);
  -    write (2, err_string, strlen(err_string));
  +                "httpd: exec of %s failed, reason: %s (errno = %d)\n",
  +                SHELL_PATH, strerror(errno), errno);
  +    write(STDERR_FILENO, err_string, strlen(err_string));
       exit(0);
   }
   
  -int include_cmd(char *s, request_rec *r) {
  +static int include_cmd(char *s, request_rec *r)
  +{
       include_cmd_arg arg;
       FILE *f;
   
  -    arg.r = r; arg.s = s;
  +    arg.r = r;
  +    arg.s = s;
   
  -    if (!spawn_child (r->pool, include_cmd_child, &arg,
  -		      kill_after_timeout, NULL, &f))
  +    if (!spawn_child(r->pool, include_cmd_child, &arg,
  +                     kill_after_timeout, NULL, &f)) {
           return -1;
  -    
  -    send_fd(f,r);
  -    pfclose(r->pool, f);	/* will wait for zombie when
  -				 * r->pool is cleared
  -				 */
  +    }
  +
  +    send_fd(f, r);
  +    pfclose(r->pool, f);        /* will wait for zombie when
  +                                 * r->pool is cleared
  +                                 */
       return 0;
   }
   
   
  -int handle_exec(FILE *in, request_rec *r, char *error)
  +static int handle_exec(FILE *in, request_rec *r, const char *error)
   {
       char tag[MAX_STRING_LEN];
       char *tag_val;
       char *file = r->filename;
       char parsed_string[MAX_STRING_LEN];
   
  -    while(1) {
  -        if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1)))
  +    while (1) {
  +        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
               return 1;
  -        if(!strcmp(tag,"cmd")) {
  -            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 1);
  -            if(include_cmd(parsed_string, r) == -1) {
  -                log_printf(r->server, "execution failure for parameter \"%s\" to tag exec in file %s", 
  -                tag, r->filename);
  +        }
  +        if (!strcmp(tag, "cmd")) {
  +            parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 1);
  +            if (include_cmd(parsed_string, r) == -1) {
  +                log_printf(r->server,
  +                            "execution failure for parameter \"%s\" "
  +                            "to tag exec in file %s",
  +                            tag, r->filename);
                   rputs(error, r);
               }
               /* just in case some stooge changed directories */
               chdir_file(r->filename);
  -        } 
  -        else if(!strcmp(tag,"cgi")) {
  -            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
  -            if(include_cgi(parsed_string, r) == -1) {
  -                log_printf(r->server, "invalid CGI ref \"%s\" in %s",tag_val,file);
  +        }
  +        else if (!strcmp(tag, "cgi")) {
  +            parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
  +            if (include_cgi(parsed_string, r) == -1) {
  +                log_printf(r->server,
  +                            "invalid CGI ref \"%s\" in %s", tag_val, file);
                   rputs(error, r);
               }
               /* grumble groan */
               chdir_file(r->filename);
           }
  -        else if(!strcmp(tag,"done"))
  +        else if (!strcmp(tag, "done")) {
               return 0;
  +        }
           else {
  -            log_printf(r->server, "unknown parameter \"%s\" to tag exec in %s",
  -                       tag, file);
  +            log_printf(r->server,
  +                        "unknown parameter \"%s\" to tag exec in %s",
  +                        tag, file);
               rputs(error, r);
           }
       }
   
   }
   
  -int handle_echo (FILE *in, request_rec *r, char *error) {
  +static int handle_echo(FILE *in, request_rec *r, const char *error)
  +{
       char tag[MAX_STRING_LEN];
       char *tag_val;
   
  -    while(1) {
  -        if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1)))
  +    while (1) {
  +        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
               return 1;
  -        if(!strcmp(tag,"var")) {
  -	    char *val = table_get (r->subprocess_env, tag_val);
  +        }
  +        if (!strcmp(tag, "var")) {
  +            char *val = table_get(r->subprocess_env, tag_val);
   
  -	    if (val) rputs(val, r);
  -	    else rputs("(none)", r);
  -        } else if(!strcmp(tag,"done"))
  +            if (val) {
  +                rputs(val, r);
  +            }
  +            else {
  +                rputs("(none)", r);
  +            }
  +        }
  +        else if (!strcmp(tag, "done")) {
               return 0;
  +        }
           else {
  -            log_printf(r->server, "unknown parameter \"%s\" to tag echo in %s",
  -                tag, r->filename);
  +            log_printf(r->server,
  +                        "unknown parameter \"%s\" to tag echo in %s",
  +                        tag, r->filename);
               rputs(error, r);
           }
       }
   }
  +
   #ifdef USE_PERL_SSI
  -int handle_perl (FILE *in, request_rec *r, char *error) {
  +static int handle_perl(FILE *in, request_rec *r, const char *error)
  +{
       char tag[MAX_STRING_LEN];
       char *tag_val;
       SV *sub = Nullsv;
  -    AV *av  = newAV();
  +    AV *av = newAV();
   
  -    if (!(allow_options (r) & OPT_INCLUDES)) {
  +    if (!(allow_options(r) & OPT_INCLUDES)) {
           log_printf(r->server,
  -            "httpd: #perl SSI disallowed by IncludesNoExec in %s", r->filename);
  -	return DECLINED;
  +                    "httpd: #perl SSI disallowed by IncludesNoExec in %s",
  +                    r->filename);
  +        return DECLINED;
       }
  -    while(1) {
  -	if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1))) 
  -	    break;
  -	if(strnEQ(tag, "sub", 3)) 
  -	    sub = newSVpv(tag_val,0);
  -	else if(strnEQ(tag, "arg", 3)) 
  -	    av_push(av, newSVpv(tag_val,0));	
  -	else if(strnEQ(tag,"done", 4))
  -	    break;
  +    while (1) {
  +        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
  +            break;
  +        }
  +        if (strnEQ(tag, "sub", 3)) {
  +            sub = newSVpv(tag_val, 0);
  +        }
  +        else if (strnEQ(tag, "arg", 3)) {
  +            av_push(av, newSVpv(tag_val, 0));
  +        }
  +        else if (strnEQ(tag, "done", 4)) {
  +            break;
  +        }
       }
       perl_stdout2client(r);
       perl_call_handler(sub, r, av);
  @@ -770,124 +907,134 @@
   /* error and tf must point to a string with room for at 
    * least MAX_STRING_LEN characters 
    */
  -int handle_config(FILE *in, request_rec *r, char *error, char *tf,
  -                  int *sizefmt) {
  +static int handle_config(FILE *in, request_rec *r, char *error, char *tf,
  +                         int *sizefmt)
  +{
       char tag[MAX_STRING_LEN];
       char *tag_val;
       char parsed_string[MAX_STRING_LEN];
       table *env = r->subprocess_env;
   
  -    while(1) {
  -        if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 0)))
  +    while (1) {
  +        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 0))) {
               return 1;
  -        if(!strcmp(tag,"errmsg")) {
  -            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
  -            strncpy(error,parsed_string,MAX_STRING_LEN-1);
  -	    error[MAX_STRING_LEN-1] = '\0';
  -        } else if(!strcmp(tag,"timefmt")) {
  -  	    time_t date = r->request_time;
  -            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
  -            strncpy(tf,parsed_string,MAX_STRING_LEN-1);
  -	    tf[MAX_STRING_LEN-1] = '\0';
  -            table_set (env, "DATE_LOCAL", ht_time(r->pool,date,tf,0));
  -            table_set (env, "DATE_GMT", ht_time(r->pool,date,tf,1));
  -            table_set (env, "LAST_MODIFIED", ht_time(r->pool,r->finfo.st_mtime,tf,0));
  -        }
  -        else if(!strcmp(tag,"sizefmt")) {
  -            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
  -	    decodehtml(parsed_string);
  -            if(!strcmp(parsed_string,"bytes"))
  +        }
  +        if (!strcmp(tag, "errmsg")) {
  +            parse_string(r, tag_val, error, MAX_STRING_LEN, 0);
  +        }
  +        else if (!strcmp(tag, "timefmt")) {
  +            time_t date = r->request_time;
  +
  +            parse_string(r, tag_val, tf, MAX_STRING_LEN, 0);
  +            table_set(env, "DATE_LOCAL", ht_time(r->pool, date, tf, 0));
  +            table_set(env, "DATE_GMT", ht_time(r->pool, date, tf, 1));
  +            table_set(env, "LAST_MODIFIED",
  +                      ht_time(r->pool, r->finfo.st_mtime, tf, 0));
  +        }
  +        else if (!strcmp(tag, "sizefmt")) {
  +            parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
  +            decodehtml(parsed_string);
  +            if (!strcmp(parsed_string, "bytes")) {
                   *sizefmt = SIZEFMT_BYTES;
  -            else if(!strcmp(parsed_string,"abbrev"))
  +            }
  +            else if (!strcmp(parsed_string, "abbrev")) {
                   *sizefmt = SIZEFMT_KMG;
  -        } 
  -        else if(!strcmp(tag,"done"))
  +            }
  +        }
  +        else if (!strcmp(tag, "done")) {
               return 0;
  +        }
           else {
  -            log_printf(r->server,"unknown parameter \"%s\" to tag config in %s",
  -                    tag, r->filename);
  +            log_printf(r->server,
  +                        "unknown parameter \"%s\" to tag config in %s",
  +                        tag, r->filename);
               rputs(error, r);
           }
       }
   }
   
   
  -
  -int find_file(request_rec *r, char *directive, char *tag, 
  -              char *tag_val, struct stat *finfo, char *error)
  +static int find_file(request_rec *r, const char *directive, const char *tag,
  +                     char *tag_val, struct stat *finfo, const char *error)
   {
  -    char *dir = "./";
       char *to_send;
   
  -    if(!strcmp(tag,"file")) {
  -        getparents(tag_val); /* get rid of any nasties */
  -        to_send = make_full_path (r->pool, dir, tag_val);
  -        if(stat(to_send,finfo) == -1) {
  +    if (!strcmp(tag, "file")) {
  +        getparents(tag_val);    /* get rid of any nasties */
  +        to_send = make_full_path(r->pool, "./", tag_val);
  +        if (stat(to_send, finfo) == -1) {
               log_printf(r->server,
  -                    "unable to get information about \"%s\" in parsed file %s",
  -                    to_send, r->filename);
  +                        "unable to get information about \"%s\" "
  +                        "in parsed file %s",
  +                        to_send, r->filename);
               rputs(error, r);
               return -1;
           }
           return 0;
       }
  -    else if(!strcmp(tag,"virtual")) {
  -	request_rec *rr = sub_req_lookup_uri (tag_val, r);
  -	
  -	if (rr->status == 200 && rr->finfo.st_mode != 0) {
  -	    memcpy ((char*)finfo, (const char *)&rr->finfo, sizeof (struct stat));
  -	    destroy_sub_req (rr);
  -	    return 0;
  -        } else {
  +    else if (!strcmp(tag, "virtual")) {
  +        request_rec *rr = sub_req_lookup_uri(tag_val, r);
  +
  +        if (rr->status == HTTP_OK && rr->finfo.st_mode != 0) {
  +            memcpy((char *) finfo, (const char *) &rr->finfo,
  +                   sizeof(struct stat));
  +            destroy_sub_req(rr);
  +            return 0;
  +        }
  +        else {
               log_printf(r->server,
  -                    "unable to get information about \"%s\" in parsed file %s",
  -                    tag_val, r->filename);
  +                        "unable to get information about \"%s\" "
  +                        "in parsed file %s",
  +                        tag_val, r->filename);
               rputs(error, r);
  -	    destroy_sub_req (rr);
  +            destroy_sub_req(rr);
               return -1;
           }
       }
       else {
  -        log_printf(r->server,"unknown parameter \"%s\" to tag %s in %s",
  -                tag, directive, r->filename);
  +        log_printf(r->server,
  +                    "unknown parameter \"%s\" to tag %s in %s",
  +                    tag, directive, r->filename);
           rputs(error, r);
           return -1;
       }
   }
   
   
  -int handle_fsize(FILE *in, request_rec *r, char *error, int sizefmt) 
  +static int handle_fsize(FILE *in, request_rec *r, const char *error, int sizefmt)
   {
       char tag[MAX_STRING_LEN];
       char *tag_val;
       struct stat finfo;
       char parsed_string[MAX_STRING_LEN];
   
  -    while(1) {
  -        if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
  +    while (1) {
  +        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
               return 1;
  -        else if(!strcmp(tag,"done"))
  +        }
  +        else if (!strcmp(tag, "done")) {
               return 0;
  +        }
           else {
  -            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
  -            if(!find_file(r,"fsize",tag,parsed_string,&finfo,error)) {
  -                if(sizefmt == SIZEFMT_KMG) {
  +            parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
  +            if (!find_file(r, "fsize", tag, parsed_string, &finfo, error)) {
  +                if (sizefmt == SIZEFMT_KMG) {
                       send_size(finfo.st_size, r);
                   }
                   else {
  -                    int l,x;
  +                    int l, x;
   #if defined(BSD) && BSD > 199305
  -		    /* ap_snprintf can't handle %qd */
  -                    sprintf(tag,"%qd", finfo.st_size);
  +                    /* ap_snprintf can't handle %qd */
  +                    sprintf(tag, "%qd", finfo.st_size);
   #else
  -                    ap_snprintf(tag, sizeof(tag), "%ld",finfo.st_size);
  +                    ap_snprintf(tag, sizeof(tag), "%ld", finfo.st_size);
   #endif
  -                    l = strlen(tag); /* grrr */
  -                    for(x=0;x<l;x++) {
  -                        if(x && (!((l-x) % 3))) {
  +                    l = strlen(tag);    /* grrr */
  +                    for (x = 0; x < l; x++) {
  +                        if (x && (!((l - x) % 3))) {
                               rputc(',', r);
                           }
  -                        rputc (tag[x],r);
  +                        rputc(tag[x], r);
                       }
                   }
               }
  @@ -895,136 +1042,204 @@
       }
   }
   
  -int handle_flastmod(FILE *in, request_rec *r, char *error, char *tf) 
  +static int handle_flastmod(FILE *in, request_rec *r, const char *error, const char *tf)
   {
       char tag[MAX_STRING_LEN];
       char *tag_val;
       struct stat finfo;
       char parsed_string[MAX_STRING_LEN];
   
  -    while(1) {
  -        if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
  +    while (1) {
  +        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
               return 1;
  -        else if(!strcmp(tag,"done"))
  +        }
  +        else if (!strcmp(tag, "done")) {
               return 0;
  +        }
           else {
  -            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
  -            if(!find_file(r,"flastmod",tag,parsed_string,&finfo,error))
  +            parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
  +            if (!find_file(r, "flastmod", tag, parsed_string, &finfo, error)) {
                   rputs(ht_time(r->pool, finfo.st_mtime, tf, 0), r);
  +            }
           }
       }
  -}    
  +}
   
  -int re_check(request_rec *r, char *string, char *rexp) 
  +static int re_check(request_rec *r, char *string, char *rexp)
   {
       regex_t *compiled;
       int regex_error;
   
  -    compiled = pregcomp (r->pool, rexp, REG_EXTENDED|REG_NOSUB);
  +    compiled = pregcomp(r->pool, rexp, REG_EXTENDED | REG_NOSUB);
       if (compiled == NULL) {
           log_printf(r->server, "unable to compile pattern \"%s\"", rexp);
           return -1;
       }
  -    regex_error = regexec(compiled, string, 0, (regmatch_t *)NULL, 0);
  -    pregfree (r->pool, compiled);
  -    return(!regex_error);
  +    regex_error = regexec(compiled, string, 0, (regmatch_t *) NULL, 0);
  +    pregfree(r->pool, compiled);
  +    return (!regex_error);
   }
   
  -enum token_type { token_string,
  +enum token_type {
  +    token_string,
       token_and, token_or, token_not, token_eq, token_ne,
  -    token_rbrace, token_lbrace, token_group
  +    token_rbrace, token_lbrace, token_group,
  +    token_ge, token_le, token_gt, token_lt
   };
   struct token {
       enum token_type type;
       char value[MAX_STRING_LEN];
   };
   
  -char *get_ptoken(request_rec *r, char *string, struct token *token) {
  +/* there is an implicit assumption here that string is at most MAX_STRING_LEN-1
  + * characters long...
  + */
  +static const char *get_ptoken(request_rec *r, const char *string, struct token *token)
  +{
       char ch;
  -    int next=0;
  -    int qs=0;
  +    int next = 0;
  +    int qs = 0;
   
       /* Skip leading white space */
  -    if (string == (char *)NULL) return (char *)NULL;
  -    while ((ch = *string++))
  -        if (!isspace(ch)) break;
  -    if (ch == '\0') return (char *)NULL;
  +    if (string == (char *) NULL) {
  +        return (char *) NULL;
  +    }
  +    while ((ch = *string++)) {
  +        if (!isspace(ch)) {
  +            break;
  +        }
  +    }
  +    if (ch == '\0') {
  +        return (char *) NULL;
  +    }
   
  -    switch(ch) {
  -      case '(':
  +    token->type = token_string; /* the default type */
  +    switch (ch) {
  +    case '(':
           token->type = token_lbrace;
  -        return(string);
  -      case ')':
  +        return (string);
  +    case ')':
           token->type = token_rbrace;
  -        return(string);
  -      case '=':
  +        return (string);
  +    case '=':
           token->type = token_eq;
  -        return(string);
  -      case '!':
  +        return (string);
  +    case '!':
           if (*string == '=') {
               token->type = token_ne;
  -            return(string+1);
  -        } else {
  +            return (string + 1);
  +        }
  +        else {
               token->type = token_not;
  -            return(string);
  +            return (string);
           }
  -      case '\'':
  +    case '\'':
           token->type = token_string;
           qs = 1;
           break;
  -      case '|':
  +    case '|':
           if (*string == '|') {
               token->type = token_or;
  -            return(string+1);
  +            return (string + 1);
           }
  -      case '&':
  +        break;
  +    case '&':
           if (*string == '&') {
               token->type = token_and;
  -            return(string+1);
  +            return (string + 1);
  +        }
  +        break;
  +    case '>':
  +        if (*string == '=') {
  +            token->type = token_ge;
  +            return (string + 1);
  +        }
  +        else {
  +            token->type = token_gt;
  +            return (string);
  +        }
  +    case '<':
  +        if (*string == '=') {
  +            token->type = token_le;
  +            return (string + 1);
  +        }
  +        else {
  +            token->type = token_lt;
  +            return (string);
           }
  -      default:
  +    default:
           token->type = token_string;
           break;
       }
       /* We should only be here if we are in a string */
  -    if (!qs) token->value[next++] = ch;
  +    if (!qs) {
  +        token->value[next++] = ch;
  +    }
   
       /* 
        * Yes I know that goto's are BAD.  But, c doesn't allow me to
        * exit a loop from a switch statement.  Yes, I could use a flag,
        * but that is (IMHO) even less readable/maintainable than the goto.
  -     */ 
  +     */
       /* 
        * I used the ++string throughout this section so that string
        * ends up pointing to the next token and I can just return it
  -     */ 
  +     */
       for (ch = *string; ch != '\0'; ch = *++string) {
           if (ch == '\\') {
  -            if ((ch = *++string) == '\0') goto TOKEN_DONE;
  +            if ((ch = *++string) == '\0') {
  +                goto TOKEN_DONE;
  +            }
               token->value[next++] = ch;
               continue;
           }
           if (!qs) {
  -            if (isspace(ch)) goto TOKEN_DONE;
  -            switch(ch) {
  -              case '(': goto TOKEN_DONE;
  -              case ')': goto TOKEN_DONE;
  -              case '=': goto TOKEN_DONE;
  -              case '!': goto TOKEN_DONE;
  -              case '|': if (*(string+1) == '|') goto TOKEN_DONE;
  -              case '&': if (*(string+1) == '&') goto TOKEN_DONE;
  +            if (isspace(ch)) {
  +                goto TOKEN_DONE;
  +            }
  +            switch (ch) {
  +            case '(':
  +                goto TOKEN_DONE;
  +            case ')':
  +                goto TOKEN_DONE;
  +            case '=':
  +                goto TOKEN_DONE;
  +            case '!':
  +                goto TOKEN_DONE;
  +            case '|':
  +                if (*(string + 1) == '|') {
  +                    goto TOKEN_DONE;
  +                }
  +                break;
  +            case '&':
  +                if (*(string + 1) == '&') {
  +                    goto TOKEN_DONE;
  +                }
  +                break;
  +            case '<':
  +                goto TOKEN_DONE;
  +            case '>':
  +                goto TOKEN_DONE;
               }
               token->value[next++] = ch;
  -        } else {
  -            if (ch == '\'') { qs=0; ++string; goto TOKEN_DONE; }
  +        }
  +        else {
  +            if (ch == '\'') {
  +                qs = 0;
  +                ++string;
  +                goto TOKEN_DONE;
  +            }
               token->value[next++] = ch;
           }
       }
  -TOKEN_DONE:
  +  TOKEN_DONE:
       /* If qs is still set, I have an unmatched ' */
  -    if (qs) { rputs("\nUnmatched '\n", r); next=0; }
  +    if (qs) {
  +        rputs("\nUnmatched '\n", r);
  +        next = 0;
  +    }
       token->value[next] = '\0';
  -    return(string);
  +    return (string);
   }
   
   
  @@ -1035,112 +1250,124 @@
    * cases.  And, without rewriting this completely, the easiest way
    * is to just branch to the return code which cleans it up.
    */
  -int parse_expr(request_rec *r, char *expr, char *error)
  +/* there is an implicit assumption here that expr is at most MAX_STRING_LEN-1
  + * characters long...
  + */
  +static int parse_expr(request_rec *r, const char *expr, const char *error)
   {
       struct parse_node {
           struct parse_node *left, *right, *parent;
           struct token token;
           int value, done;
  -    } *root, *current, *new;
  -    char *parse;
  +    }         *root, *current, *new;
  +    const char *parse;
       char buffer[MAX_STRING_LEN];
  -    struct pool *expr_pool;
  +    pool *expr_pool;
       int retval = 0;
   
  -    if ((parse = expr) == (char *)NULL) return(0);
  -    root = current = (struct parse_node*)NULL;
  -    if ((expr_pool = make_sub_pool(r->pool)) == (struct pool *)NULL) {
  -        log_printf(r->server, "out of memory processing file %s", r->filename);
  -        rputs(error, r);
  -        return(0);
  +    if ((parse = expr) == (char *) NULL) {
  +        return (0);
       }
  +    root = current = (struct parse_node *) NULL;
  +    expr_pool = make_sub_pool(r->pool);
   
       /* Create Parse Tree */
       while (1) {
  -        new = (struct parse_node*)palloc(expr_pool, sizeof (struct parse_node));
  -        if (new == (struct parse_node*)NULL) {
  -            log_printf(r->server,"out of memory processing file %s", r->filename);
  -            rputs(error, r);
  -            goto RETURN;
  -        }
  -        new->parent = new->left = new->right = (struct parse_node*)NULL;
  +        new = (struct parse_node *) palloc(expr_pool,
  +                                           sizeof(struct parse_node));
  +        new->parent = new->left = new->right = (struct parse_node *) NULL;
           new->done = 0;
  -        if ((parse = get_ptoken(r, parse, &new->token)) == (char *)NULL)
  +        if ((parse = get_ptoken(r, parse, &new->token)) == (char *) NULL) {
               break;
  -        switch(new->token.type) {
  +        }
  +        switch (new->token.type) {
   
  -          case token_string:
  +        case token_string:
   #ifdef DEBUG_INCLUDE
  -            rvputs(r,"     Token: string (", new->token.value, ")\n", NULL);
  +            rvputs(r, "     Token: string (", new->token.value, ")\n", NULL);
   #endif
  -            if (current == (struct parse_node*)NULL) {
  +            if (current == (struct parse_node *) NULL) {
                   root = current = new;
                   break;
               }
  -            switch(current->token.type) {
  -              case token_string:
  -                if (current->token.value[0] != '\0')
  -                    strncat(current->token.value, " ", 
  -			MAX_STRING_LEN-strlen(current->token.value)-1);
  -                strncat(current->token.value, new->token.value, 
  -			MAX_STRING_LEN-strlen(current->token.value)-1);
  +            switch (current->token.type) {
  +            case token_string:
  +                if (current->token.value[0] != '\0') {
  +                    strncat(current->token.value, " ",
  +                         MAX_STRING_LEN - strlen(current->token.value) - 1);
  +                }
  +                strncat(current->token.value, new->token.value,
  +                        MAX_STRING_LEN - strlen(current->token.value) - 1);
  +		current->token.value[sizeof(current->token.value) - 1] = '\0';
                   break;
  -              case token_eq:
  -              case token_ne:
  -              case token_and:
  -              case token_or:
  -              case token_lbrace:
  -              case token_not:
  +            case token_eq:
  +            case token_ne:
  +            case token_and:
  +            case token_or:
  +            case token_lbrace:
  +            case token_not:
  +            case token_ge:
  +            case token_gt:
  +            case token_le:
  +            case token_lt:
                   new->parent = current;
                   current = current->right = new;
                   break;
  -              default:
  +            default:
                   log_printf(r->server,
  -                    "Invalid expression \"%s\" in file %s", expr, r->filename);
  +                            "Invalid expression \"%s\" in file %s",
  +                            expr, r->filename);
                   rputs(error, r);
                   goto RETURN;
               }
               break;
   
  -          case token_and:
  -          case token_or:
  +        case token_and:
  +        case token_or:
   #ifdef DEBUG_INCLUDE
  -rputs ("     Token: and/or\n", r);
  +            rputs("     Token: and/or\n", r);
   #endif
  -            if (current == (struct parse_node*)NULL) {
  +            if (current == (struct parse_node *) NULL) {
                   log_printf(r->server,
  -                    "Invalid expression \"%s\" in file %s", expr, r->filename);
  +                            "Invalid expression \"%s\" in file %s",
  +                            expr, r->filename);
                   rputs(error, r);
                   goto RETURN;
               }
               /* Percolate upwards */
  -            while (current != (struct parse_node *)NULL) {
  -                switch(current->token.type) {
  -                  case token_string:
  -                  case token_group:
  -                  case token_not:
  -                  case token_eq:
  -                  case token_ne:
  -                  case token_and:
  -                  case token_or:
  +            while (current != (struct parse_node *) NULL) {
  +                switch (current->token.type) {
  +                case token_string:
  +                case token_group:
  +                case token_not:
  +                case token_eq:
  +                case token_ne:
  +                case token_and:
  +                case token_or:
  +                case token_ge:
  +                case token_gt:
  +                case token_le:
  +                case token_lt:
                       current = current->parent;
                       continue;
  -                  case token_lbrace:
  +                case token_lbrace:
                       break;
  -                  default:
  +                default:
                       log_printf(r->server,
  -                        "Invalid expression \"%s\" in file %s", expr, r->filename);
  +                                "Invalid expression \"%s\" in file %s",
  +                                expr, r->filename);
                       rputs(error, r);
                       goto RETURN;
                   }
                   break;
               }
  -            if (current == (struct parse_node*)NULL) {
  +            if (current == (struct parse_node *) NULL) {
                   new->left = root;
                   new->left->parent = new;
  -                new->parent = (struct parse_node*)NULL;
  +                new->parent = (struct parse_node *) NULL;
                   root = new;
  -            } else {
  +            }
  +            else {
                   new->left = current->right;
                   current->right = new;
                   new->parent = current;
  @@ -1148,38 +1375,44 @@
               current = new;
               break;
   
  -          case token_not:
  +        case token_not:
   #ifdef DEBUG_INCLUDE
  -rputs("     Token: not\n", r);
  +            rputs("     Token: not\n", r);
   #endif
  -            if (current == (struct parse_node*)NULL) {
  +            if (current == (struct parse_node *) NULL) {
                   root = current = new;
                   break;
               }
               /* Percolate upwards */
  -            while (current != (struct parse_node *)NULL) {
  -                switch(current->token.type) {
  -                  case token_not:
  -                  case token_eq:
  -                  case token_ne:
  -                  case token_and:
  -                  case token_or:
  -                  case token_lbrace:
  +            while (current != (struct parse_node *) NULL) {
  +                switch (current->token.type) {
  +                case token_not:
  +                case token_eq:
  +                case token_ne:
  +                case token_and:
  +                case token_or:
  +                case token_lbrace:
  +                case token_ge:
  +                case token_gt:
  +                case token_le:
  +                case token_lt:
                       break;
  -                  default:
  +                default:
                       log_printf(r->server,
  -                        "Invalid expression \"%s\" in file %s", expr, r->filename);
  +                                "Invalid expression \"%s\" in file %s",
  +                                expr, r->filename);
                       rputs(error, r);
                       goto RETURN;
                   }
                   break;
               }
  -            if (current == (struct parse_node*)NULL) {
  +            if (current == (struct parse_node *) NULL) {
                   new->left = root;
                   new->left->parent = new;
  -                new->parent = (struct parse_node*)NULL;
  +                new->parent = (struct parse_node *) NULL;
                   root = new;
  -            } else {
  +            }
  +            else {
                   new->left = current->right;
                   current->right = new;
                   new->parent = current;
  @@ -1187,46 +1420,56 @@
               current = new;
               break;
   
  -          case token_eq:
  -          case token_ne:
  +        case token_eq:
  +        case token_ne:
  +        case token_ge:
  +        case token_gt:
  +        case token_le:
  +        case token_lt:
   #ifdef DEBUG_INCLUDE
  -rputs("     Token: eq/ne\n", r);
  +            rputs("     Token: eq/ne/ge/gt/le/lt\n", r);
   #endif
  -            if (current == (struct parse_node*)NULL) {
  +            if (current == (struct parse_node *) NULL) {
                   log_printf(r->server,
  -                    "Invalid expression \"%s\" in file %s", expr, r->filename);
  +                            "Invalid expression \"%s\" in file %s",
  +                            expr, r->filename);
                   rputs(error, r);
                   goto RETURN;
               }
               /* Percolate upwards */
  -            while (current != (struct parse_node *)NULL) {
  -                switch(current->token.type) {
  -                  case token_string:
  -                  case token_group:
  +            while (current != (struct parse_node *) NULL) {
  +                switch (current->token.type) {
  +                case token_string:
  +                case token_group:
                       current = current->parent;
                       continue;
  -                  case token_lbrace:
  -                  case token_and:
  -                  case token_or:
  +                case token_lbrace:
  +                case token_and:
  +                case token_or:
                       break;
  -                  case token_not:
  -                  case token_eq:
  -                  case token_ne:
  -                  default:
  -                    log_printf(r->server, 
  -                        "Invalid expression \"%s\" in file %s", 
  -                        expr, r->filename);
  +                case token_not:
  +                case token_eq:
  +                case token_ne:
  +                case token_ge:
  +                case token_gt:
  +                case token_le:
  +                case token_lt:
  +                default:
  +                    log_printf(r->server,
  +                                "Invalid expression \"%s\" in file %s",
  +                                expr, r->filename);
                       rputs(error, r);
                       goto RETURN;
                   }
                   break;
               }
  -            if (current == (struct parse_node*)NULL) {
  +            if (current == (struct parse_node *) NULL) {
                   new->left = root;
                   new->left->parent = new;
  -                new->parent = (struct parse_node*)NULL;
  +                new->parent = (struct parse_node *) NULL;
                   root = new;
  -            } else {
  +            }
  +            else {
                   new->left = current->right;
                   current->right = new;
                   new->parent = current;
  @@ -1234,422 +1477,536 @@
               current = new;
               break;
   
  -          case token_rbrace:
  +        case token_rbrace:
   #ifdef DEBUG_INCLUDE
  -rputs("     Token: rbrace\n", r);
  +            rputs("     Token: rbrace\n", r);
   #endif
  -            while (current != (struct parse_node*)NULL) {
  +            while (current != (struct parse_node *) NULL) {
                   if (current->token.type == token_lbrace) {
                       current->token.type = token_group;
                       break;
                   }
                   current = current->parent;
               }
  -            if (current == (struct parse_node*)NULL) {
  -                log_printf(r->server,"Unmatched ')' in %s", expr, r->filename);
  +            if (current == (struct parse_node *) NULL) {
  +                log_printf(r->server, "Unmatched ')' in \"%s\" in file %s",
  +			    expr, r->filename);
                   rputs(error, r);
                   goto RETURN;
               }
               break;
   
  -          case token_lbrace:
  +        case token_lbrace:
   #ifdef DEBUG_INCLUDE
  -rputs("     Token: lbrace\n", r);
  +            rputs("     Token: lbrace\n", r);
   #endif
  -            if (current == (struct parse_node*)NULL) {
  +            if (current == (struct parse_node *) NULL) {
                   root = current = new;
                   break;
               }
               /* Percolate upwards */
  -            while (current != (struct parse_node *)NULL) {
  -                switch(current->token.type) {
  -                  case token_not:
  -                  case token_eq:
  -                  case token_ne:
  -                  case token_and:
  -                  case token_or:
  -                  case token_lbrace:
  +            while (current != (struct parse_node *) NULL) {
  +                switch (current->token.type) {
  +                case token_not:
  +                case token_eq:
  +                case token_ne:
  +                case token_and:
  +                case token_or:
  +                case token_lbrace:
  +                case token_ge:
  +                case token_gt:
  +                case token_le:
  +                case token_lt:
                       break;
  -                  case token_string:
  -                  case token_group:
  -                  default:
  +                case token_string:
  +                case token_group:
  +                default:
                       log_printf(r->server,
  -                        "Invalid expression \"%s\" in file %s", 
  -			expr, r->filename);
  +                                "Invalid expression \"%s\" in file %s",
  +                                expr, r->filename);
                       rputs(error, r);
                       goto RETURN;
                   }
                   break;
               }
  -            if (current == (struct parse_node*)NULL) {
  +            if (current == (struct parse_node *) NULL) {
                   new->left = root;
                   new->left->parent = new;
  -                new->parent = (struct parse_node*)NULL;
  +                new->parent = (struct parse_node *) NULL;
                   root = new;
  -            } else {
  +            }
  +            else {
                   new->left = current->right;
                   current->right = new;
                   new->parent = current;
               }
               current = new;
               break;
  -	  default:
  -	    break;
  +        default:
  +            break;
           }
       }
   
       /* Evaluate Parse Tree */
       current = root;
  -    while (current != (struct parse_node *)NULL) {
  -        switch(current->token.type) {
  -          case token_string:
  -#ifdef DEBUG_INCLUDE
  -rputs("     Evaluate string\n", r);
  -#endif
  -            parse_string(r, current->token.value, buffer, MAX_STRING_LEN, 0);
  -            strncpy(current->token.value, buffer, MAX_STRING_LEN-1);
  -	    current->token.value[MAX_STRING_LEN-1] = '\0';
  +    while (current != (struct parse_node *) NULL) {
  +        switch (current->token.type) {
  +        case token_string:
  +#ifdef DEBUG_INCLUDE
  +            rputs("     Evaluate string\n", r);
  +#endif
  +            parse_string(r, current->token.value, buffer, sizeof(buffer), 0);
  +	    safe_copy(current->token.value, buffer, sizeof(current->token.value));
               current->value = (current->token.value[0] != '\0');
               current->done = 1;
               current = current->parent;
               break;
   
  -          case token_and:
  -          case token_or:
  +        case token_and:
  +        case token_or:
   #ifdef DEBUG_INCLUDE
  -rputs("     Evaluate and/or\n", r);
  +            rputs("     Evaluate and/or\n", r);
   #endif
  -            if (current->left == (struct parse_node*)NULL ||
  -                        current->right == (struct parse_node*)NULL) {
  -                log_printf(r->server,
  -                    "Invalid expression \"%s\" in file %s", expr, r->filename);
  +            if (current->left == (struct parse_node *) NULL ||
  +                current->right == (struct parse_node *) NULL) {
  +                log_printf(r->server, "Invalid expression \"%s\" in file %s",
  +                            expr, r->filename);
                   rputs(error, r);
                   goto RETURN;
               }
               if (!current->left->done) {
  -                switch(current->left->token.type) {
  -                  case token_string:
  +                switch (current->left->token.type) {
  +                case token_string:
                       parse_string(r, current->left->token.value,
  -                            buffer, MAX_STRING_LEN, 0);
  -                    strncpy(current->left->token.value, buffer,
  -                            MAX_STRING_LEN-1);
  -		    current->left->token.value[MAX_STRING_LEN-1] = '\0';
  -                  current->left->value = (current->token.value[0] != '\0');
  +                                 buffer, sizeof(buffer), 0);
  +                    safe_copy(current->left->token.value, buffer,
  +                            sizeof(current->left->token.value));
  +		    current->left->value = (current->left->token.value[0] != '\0');
                       current->left->done = 1;
                       break;
  -                  default:
  +                default:
                       current = current->left;
                       continue;
                   }
               }
               if (!current->right->done) {
  -                switch(current->right->token.type) {
  -                  case token_string:
  +                switch (current->right->token.type) {
  +                case token_string:
                       parse_string(r, current->right->token.value,
  -                            buffer, MAX_STRING_LEN, 0);
  -                    strncpy(current->right->token.value, buffer,
  -                            MAX_STRING_LEN-1);
  -		    current->right->token.value[MAX_STRING_LEN-1] = '\0';
  -                  current->right->value = (current->token.value[0] != '\0');
  +                                 buffer, sizeof(buffer), 0);
  +                    safe_copy(current->right->token.value, buffer,
  +                            sizeof(current->right->token.value));
  +		    current->right->value = (current->right->token.value[0] != '\0');
                       current->right->done = 1;
                       break;
  -                  default:
  +                default:
                       current = current->right;
                       continue;
                   }
               }
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"     Left: ", current->left->value ? "1" : "0", "\n", NULL);
  -rvputs(r,"     Right: ", current->right->value ? "1" : "0", "\n", NULL);
  +            rvputs(r, "     Left: ", current->left->value ? "1" : "0",
  +                   "\n", NULL);
  +            rvputs(r, "     Right: ", current->right->value ? "1" : "0",
  +                   "\n", NULL);
   #endif
  -            if (current->token.type == token_and)
  -                current->value =
  -                    current->left->value && current->right->value;
  -            else
  -                current->value =
  -                    current->left->value || current->right->value;
  +            if (current->token.type == token_and) {
  +                current->value = current->left->value && current->right->value;
  +            }
  +            else {
  +                current->value = current->left->value || current->right->value;
  +            }
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"     Returning ", current->value ? "1" : "0", "\n", NULL);
  +            rvputs(r, "     Returning ", current->value ? "1" : "0",
  +                   "\n", NULL);
   #endif
               current->done = 1;
               current = current->parent;
               break;
   
  -          case token_eq:
  -          case token_ne:
  +        case token_eq:
  +        case token_ne:
   #ifdef DEBUG_INCLUDE
  -rputs("     Evaluate eq/ne\n", r);
  +            rputs("     Evaluate eq/ne\n", r);
   #endif
  -            if ((current->left == (struct parse_node*)NULL) ||
  -                        (current->right == (struct parse_node*)NULL) ||
  -                        (current->left->token.type != token_string) ||
  -                        (current->right->token.type != token_string)) {
  -                log_printf(r->server,
  -                    "Invalid expression \"%s\" in file %s", expr, r->filename);
  +            if ((current->left == (struct parse_node *) NULL) ||
  +                (current->right == (struct parse_node *) NULL) ||
  +                (current->left->token.type != token_string) ||
  +                (current->right->token.type != token_string)) {
  +                log_printf(r->server, "Invalid expression \"%s\" in file %s",
  +                            expr, r->filename);
                   rputs(error, r);
                   goto RETURN;
               }
               parse_string(r, current->left->token.value,
  -                         buffer, MAX_STRING_LEN, 0);
  -            strncpy(current->left->token.value, buffer, MAX_STRING_LEN-1);
  -	    current->left->token.value[MAX_STRING_LEN-1] = '\0';
  +                         buffer, sizeof(buffer), 0);
  +            safe_copy(current->left->token.value, buffer,
  +			sizeof(current->left->token.value));
               parse_string(r, current->right->token.value,
  -                         buffer, MAX_STRING_LEN, 0);
  -            strncpy(current->right->token.value, buffer, MAX_STRING_LEN-1);
  -	    current->right->token.value[MAX_STRING_LEN-1] = '\0';
  +                         buffer, sizeof(buffer), 0);
  +            safe_copy(current->right->token.value, buffer,
  +			sizeof(current->right->token.value));
               if (current->right->token.value[0] == '/') {
                   int len;
                   len = strlen(current->right->token.value);
  -                if (current->right->token.value[len-1] == '/') {
  -                    current->right->token.value[len-1] = '\0';
  -                } else {
  -                    log_printf(r->server,"Invalid rexp \"%s\" in file %s",
  -                            current->right->token.value, r->filename);
  +                if (current->right->token.value[len - 1] == '/') {
  +                    current->right->token.value[len - 1] = '\0';
  +                }
  +                else {
  +                    log_printf(r->server, "Invalid rexp \"%s\" in file %s",
  +                                current->right->token.value, r->filename);
                       rputs(error, r);
                       goto RETURN;
                   }
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"     Re Compare (", current->left->token.value,
  -         ") with /", &current->right->token.value[1], "/\n", NULL);
  +                rvputs(r, "     Re Compare (", current->left->token.value,
  +                  ") with /", &current->right->token.value[1], "/\n", NULL);
   #endif
                   current->value =
                       re_check(r, current->left->token.value,
  -                            &current->right->token.value[1]);
  -            } else {
  +                             &current->right->token.value[1]);
  +            }
  +            else {
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"     Compare (", current->left->token.value,
  -         ") with (", current->right->token.value, ")\n", NULL);
  +                rvputs(r, "     Compare (", current->left->token.value,
  +                       ") with (", current->right->token.value, ")\n", NULL);
   #endif
                   current->value =
  -                        (strcmp(current->left->token.value,
  -                         current->right->token.value) == 0);
  +                    (strcmp(current->left->token.value,
  +                            current->right->token.value) == 0);
               }
  -            if (current->token.type == token_ne)
  +            if (current->token.type == token_ne) {
                   current->value = !current->value;
  +            }
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"     Returning ", current->value ? "1" : "0", "\n", NULL);
  +            rvputs(r, "     Returning ", current->value ? "1" : "0",
  +                   "\n", NULL);
  +#endif
  +            current->done = 1;
  +            current = current->parent;
  +            break;
  +        case token_ge:
  +        case token_gt:
  +        case token_le:
  +        case token_lt:
  +#ifdef DEBUG_INCLUDE
  +            rputs("     Evaluate ge/gt/le/lt\n", r);
  +#endif
  +            if ((current->left == (struct parse_node *) NULL) ||
  +                (current->right == (struct parse_node *) NULL) ||
  +                (current->left->token.type != token_string) ||
  +                (current->right->token.type != token_string)) {
  +                log_printf(r->server, "Invalid expression \"%s\" in file %s",
  +                            expr, r->filename);
  +                rputs(error, r);
  +                goto RETURN;
  +            }
  +            parse_string(r, current->left->token.value,
  +                         buffer, sizeof(buffer), 0);
  +            safe_copy(current->left->token.value, buffer,
  +			sizeof(current->left->token.value));
  +            parse_string(r, current->right->token.value,
  +                         buffer, sizeof(buffer), 0);
  +            safe_copy(current->right->token.value, buffer,
  +			sizeof(current->right->token.value));
  +#ifdef DEBUG_INCLUDE
  +            rvputs(r, "     Compare (", current->left->token.value,
  +                   ") with (", current->right->token.value, ")\n", NULL);
  +#endif
  +            current->value =
  +                strcmp(current->left->token.value,
  +                       current->right->token.value);
  +            if (current->token.type == token_ge) {
  +                current->value = current->value >= 0;
  +            }
  +            else if (current->token.type == token_gt) {
  +                current->value = current->value > 0;
  +            }
  +            else if (current->token.type == token_le) {
  +                current->value = current->value <= 0;
  +            }
  +            else if (current->token.type == token_lt) {
  +                current->value = current->value < 0;
  +            }
  +            else {
  +                current->value = 0;     /* Don't return -1 if unknown token */
  +            }
  +#ifdef DEBUG_INCLUDE
  +            rvputs(r, "     Returning ", current->value ? "1" : "0",
  +                   "\n", NULL);
   #endif
               current->done = 1;
               current = current->parent;
               break;
   
  -          case token_not:
  -            if (current->right != (struct parse_node *)NULL) {
  +        case token_not:
  +            if (current->right != (struct parse_node *) NULL) {
                   if (!current->right->done) {
                       current = current->right;
                       continue;
                   }
                   current->value = !current->right->value;
  -            } else {
  +            }
  +            else {
                   current->value = 0;
               }
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"     Evaluate !: ", current->value ? "1" : "0", "\n", NULL);
  +            rvputs(r, "     Evaluate !: ", current->value ? "1" : "0",
  +                   "\n", NULL);
   #endif
               current->done = 1;
               current = current->parent;
               break;
   
  -          case token_group:
  -            if (current->right != (struct parse_node *)NULL) {
  +        case token_group:
  +            if (current->right != (struct parse_node *) NULL) {
                   if (!current->right->done) {
                       current = current->right;
                       continue;
                   }
                   current->value = current->right->value;
  -            } else {
  +            }
  +            else {
                   current->value = 1;
               }
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"     Evaluate (): ", current->value ? "1" : "0", "\n", NULL);
  +            rvputs(r, "     Evaluate (): ", current->value ? "1" : "0",
  +                   "\n", NULL);
   #endif
               current->done = 1;
               current = current->parent;
               break;
   
  -          case token_lbrace:
  -            log_printf(r->server,"Unmatched '(' in %s in file %s", 
  -		expr, r->filename);
  +        case token_lbrace:
  +            log_printf(r->server, "Unmatched '(' in \"%s\" in file %s",
  +                        expr, r->filename);
               rputs(error, r);
               goto RETURN;
   
  -          case token_rbrace:
  -            log_printf(r->server,"Unmatched ')' in %s in file %s\n", 
  -		expr, r->filename);
  +        case token_rbrace:
  +            log_printf(r->server, "Unmatched ')' in \"%s\" in file %s\n",
  +                        expr, r->filename);
               rputs(error, r);
               goto RETURN;
   
  -          default:
  -            log_printf(r->server,"bad token type");
  +        default:
  +            log_printf(r->server, "bad token type");
               rputs(error, r);
               goto RETURN;
           }
       }
   
  -    retval =  (root == (struct parse_node *)NULL) ? 0 : root->value;
  -RETURN:
  +    retval = (root == (struct parse_node *) NULL) ? 0 : root->value;
  +  RETURN:
       destroy_pool(expr_pool);
       return (retval);
  -}    
  +}
   
  -int handle_if(FILE *in, request_rec *r, char *error,
  -              int *conditional_status, int *printing) 
  +static int handle_if(FILE *in, request_rec *r, const char *error,
  +                     int *conditional_status, int *printing)
   {
       char tag[MAX_STRING_LEN];
  -    char *tag_val = '\0';
  -    char *expr = '\0';
  +    char *tag_val;
  +    char *expr;
   
  -    while(1) {
  -        tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 0);
  -        if(*tag == '\0')
  +    expr = NULL;
  +    while (1) {
  +        tag_val = get_tag(r->pool, in, tag, sizeof(tag), 0);
  +        if (*tag == '\0') {
               return 1;
  -        else if(!strcmp(tag,"done")) {
  +        }
  +        else if (!strcmp(tag, "done")) {
  +	    if (expr == NULL) {
  +		log_printf(r->server, "missing expr in if statement: %s",
  +			    r->filename);
  +		rputs(error, r);
  +		return 1;
  +	    }
               *printing = *conditional_status = parse_expr(r, expr, error);
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"**** if conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL);
  +            rvputs(r, "**** if conditional_status=\"",
  +                   *conditional_status ? "1" : "0", "\"\n", NULL);
   #endif
               return 0;
  -        } else if(!strcmp(tag,"expr")) {
  -	    expr = tag_val;
  +        }
  +        else if (!strcmp(tag, "expr")) {
  +            expr = tag_val;
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"**** if expr=\"", expr, "\"\n", NULL);
  +            rvputs(r, "**** if expr=\"", expr, "\"\n", NULL);
   #endif
  -        } else {
  -            log_printf(r->server,"unknown parameter \"%s\" to tag if in %s",
  -                    tag, r->filename);
  +        }
  +        else {
  +            log_printf(r->server, "unknown parameter \"%s\" to tag if in %s",
  +                        tag, r->filename);
               rputs(error, r);
           }
       }
  -}    
  +}
   
  -int handle_elif(FILE *in, request_rec *r, char *error,
  -              int *conditional_status, int *printing) 
  +static int handle_elif(FILE *in, request_rec *r, const char *error,
  +                       int *conditional_status, int *printing)
   {
       char tag[MAX_STRING_LEN];
  -    char *tag_val = '\0';
  -    char *expr = '\0';
  +    char *tag_val;
  +    char *expr;
   
  -    while(1) {
  -        tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 0);
  -        if(*tag == '\0')
  +    expr = NULL;
  +    while (1) {
  +        tag_val = get_tag(r->pool, in, tag, sizeof(tag), 0);
  +        if (*tag == '\0') {
               return 1;
  -        else if(!strcmp(tag,"done")) {
  +        }
  +        else if (!strcmp(tag, "done")) {
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"**** elif conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL);
  +            rvputs(r, "**** elif conditional_status=\"",
  +                   *conditional_status ? "1" : "0", "\"\n", NULL);
   #endif
               if (*conditional_status) {
                   *printing = 0;
  -                return(0);
  +                return (0);
               }
  +	    if (expr == NULL) {
  +		log_printf(r->server, "missing expr in elif statement: %s",
  +			    r->filename);
  +		rputs(error, r);
  +		return 1;
  +	    }
               *printing = *conditional_status = parse_expr(r, expr, error);
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"**** elif conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL);
  +            rvputs(r, "**** elif conditional_status=\"",
  +                   *conditional_status ? "1" : "0", "\"\n", NULL);
   #endif
               return 0;
  -        } else if(!strcmp(tag,"expr")) {
  -	    expr = tag_val;
  +        }
  +        else if (!strcmp(tag, "expr")) {
  +            expr = tag_val;
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"**** if expr=\"", expr, "\"\n", NULL);
  +            rvputs(r, "**** if expr=\"", expr, "\"\n", NULL);
   #endif
  -        } else {
  -            log_printf(r->server,"unknown parameter \"%s\" to tag if in %s",
  -                    tag, r->filename);
  +        }
  +        else {
  +            log_printf(r->server, "unknown parameter \"%s\" to tag if in %s",
  +                        tag, r->filename);
               rputs(error, r);
           }
       }
   }
   
  -int handle_else(FILE *in, request_rec *r, char *error,
  -              int *conditional_status, int *printing) 
  +static int handle_else(FILE *in, request_rec *r, const char *error,
  +                       int *conditional_status, int *printing)
   {
       char tag[MAX_STRING_LEN];
       char *tag_val;
   
  -    if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
  +    if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
           return 1;
  -    else if(!strcmp(tag,"done")) {
  +    }
  +    else if (!strcmp(tag, "done")) {
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"**** else conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL);
  +        rvputs(r, "**** else conditional_status=\"",
  +               *conditional_status ? "1" : "0", "\"\n", NULL);
   #endif
           *printing = !(*conditional_status);
           *conditional_status = 1;
           return 0;
  -    } else {
  -        log_printf(r->server, "else directive does not take tags");
  -        if (*printing) rputs(error, r);
  +    }
  +    else {
  +        log_printf(r->server, "else directive does not take tags in %s",
  +		    r->filename);
  +        if (*printing) {
  +            rputs(error, r);
  +        }
           return -1;
       }
  -}    
  +}
   
  -int handle_endif(FILE *in, request_rec *r, char *error, 
  -              int *conditional_status, int *printing) 
  +static int handle_endif(FILE *in, request_rec *r, const char *error,
  +                        int *conditional_status, int *printing)
   {
       char tag[MAX_STRING_LEN];
       char *tag_val;
   
  -    if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1))) {
  +    if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
           return 1;
  -    } else if(!strcmp(tag,"done")) {
  +    }
  +    else if (!strcmp(tag, "done")) {
   #ifdef DEBUG_INCLUDE
  -rvputs(r,"**** endif conditional_status=\"", *conditional_status ? "1" : "0", "\"\n", NULL);
  +        rvputs(r, "**** endif conditional_status=\"",
  +               *conditional_status ? "1" : "0", "\"\n", NULL);
   #endif
           *printing = 1;
           *conditional_status = 1;
           return 0;
  -    } else {
  -        log_printf(r->server, "endif directive does not take tags");
  +    }
  +    else {
  +        log_printf(r->server, "endif directive does not take tags in %s",
  +		    r->filename);
           rputs(error, r);
           return -1;
       }
  -}    
  +}
   
  -int handle_set(FILE *in, request_rec *r, char *error) 
  +static int handle_set(FILE *in, request_rec *r, const char *error)
   {
       char tag[MAX_STRING_LEN];
       char parsed_string[MAX_STRING_LEN];
       char *tag_val;
       char *var;
   
  -    var = (char *)NULL;
  +    var = (char *) NULL;
       while (1) {
  -        if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
  +        if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
               return 1;
  -        else if(!strcmp(tag,"done"))
  +        }
  +        else if (!strcmp(tag, "done")) {
               return 0;
  -        else if (!strcmp(tag,"var")) {
  +        }
  +        else if (!strcmp(tag, "var")) {
               var = tag_val;
  -        } else if (!strcmp(tag,"value")) {
  -            if (var == (char *)NULL) {
  +        }
  +        else if (!strcmp(tag, "value")) {
  +            if (var == (char *) NULL) {
                   log_printf(r->server,
  -                    "variable must precede value in set directive");
  +                            "variable must precede value in set directive in %s",
  +			    r->filename);
                   rputs(error, r);
                   return -1;
  -            } 
  -            parse_string(r, tag_val, parsed_string, MAX_STRING_LEN, 0);
  -            table_set (r->subprocess_env, var, parsed_string);
  +            }
  +            parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
  +            table_set(r->subprocess_env, var, parsed_string);
  +        }
  +        else {
  +            log_printf(r->server, "Invalid tag for set directive in %s",
  +			r->filename);
  +            rputs(error, r);
  +            return -1;
           }
       }
  -}    
  +}
   
  -int handle_printenv(FILE *in, request_rec *r, char *error) 
  +static int handle_printenv(FILE *in, request_rec *r, const char *error)
   {
       char tag[MAX_STRING_LEN];
       char *tag_val;
       table_entry *elts = (table_entry *) r->subprocess_env->elts;
       int i;
   
  -    if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
  +    if (!(tag_val = get_tag(r->pool, in, tag, sizeof(tag), 1))) {
           return 1;
  -    else if(!strcmp(tag,"done")) {
  -            for (i = 0; i < r->subprocess_env->nelts; ++i)
  -                rvputs(r, elts[i].key, "=", elts[i].val, "\n", NULL);
  -            return 0;
  -    } else {
  -        log_printf(r->server, "printenv directive does not take tags");
  +    }
  +    else if (!strcmp(tag, "done")) {
  +        for (i = 0; i < r->subprocess_env->nelts; ++i) {
  +            rvputs(r, elts[i].key, "=", elts[i].val, "\n", NULL);
  +        }
  +        return 0;
  +    }
  +    else {
  +        log_printf(r->server, "printenv directive does not take tags in %s",
  +		    r->filename);
           rputs(error, r);
           return -1;
       }
  -}    
  +}
   
   
   
  @@ -1657,105 +2014,139 @@
   
   /* This is a stub which parses a file descriptor. */
   
  -void send_parsed_content(FILE *f, request_rec *r)
  +static void send_parsed_content(FILE *f, request_rec *r)
   {
       char directive[MAX_STRING_LEN], error[MAX_STRING_LEN];
       char timefmt[MAX_STRING_LEN];
  -    int noexec = allow_options (r) & OPT_INCNOEXEC;
  +    int noexec = allow_options(r) & OPT_INCNOEXEC;
       int ret, sizefmt;
       int if_nesting;
       int printing;
       int conditional_status;
   
  -    strncpy(error,DEFAULT_ERROR_MSG, sizeof(error)-1);
  -    error[sizeof(error)-1] = '\0';
  -    strncpy(timefmt,DEFAULT_TIME_FORMAT, sizeof(timefmt)-1);
  -    timefmt[sizeof(timefmt)-1] = '\0';
  +    safe_copy(error, DEFAULT_ERROR_MSG, sizeof(error));
  +    safe_copy(timefmt, DEFAULT_TIME_FORMAT, sizeof(timefmt));
       sizefmt = SIZEFMT_KMG;
   
   /*  Turn printing on */
       printing = conditional_status = 1;
       if_nesting = 0;
   
  -    chdir_file (r->filename);
  -    if (r->args) { /* add QUERY stuff to env cause it ain't yet */
  -	char *arg_copy = pstrdup (r->pool, r->args);
  -
  -        table_set (r->subprocess_env, "QUERY_STRING", r->args);
  -        unescape_url (arg_copy);
  -        table_set (r->subprocess_env, "QUERY_STRING_UNESCAPED",
  -                escape_shell_cmd (r->pool, arg_copy));
  +    chdir_file(r->filename);
  +    if (r->args) {              /* add QUERY stuff to env cause it ain't yet */
  +        char *arg_copy = pstrdup(r->pool, r->args);
  +
  +        table_set(r->subprocess_env, "QUERY_STRING", r->args);
  +        unescape_url(arg_copy);
  +        table_set(r->subprocess_env, "QUERY_STRING_UNESCAPED",
  +                  escape_shell_cmd(r->pool, arg_copy));
       }
   
  -    while(1) {
  -        if(!find_string(f,STARTING_SEQUENCE,r,printing)) {
  -            if(get_directive(f,directive,r->pool))
  +    while (1) {
  +        if (!find_string(f, STARTING_SEQUENCE, r, printing)) {
  +            if (get_directive(f, directive, sizeof(directive), r->pool)) {
  +		log_printf(r->server,
  +			    "mod_include: error reading directive in %s",
  +			    r->filename);
  +		rputs(error, r);
                   return;
  -            if(!strcmp(directive,"if")) {
  +            }
  +            if (!strcmp(directive, "if")) {
                   if (!printing) {
                       if_nesting++;
  -                } else {
  -                    ret=handle_if(f, r, error, &conditional_status, &printing);
  +                }
  +                else {
  +                    ret = handle_if(f, r, error, &conditional_status,
  +                                    &printing);
                       if_nesting = 0;
                   }
                   continue;
  -            } else if(!strcmp(directive,"else")) {
  -                if (!if_nesting)
  -                    ret=handle_else(f, r, error, &conditional_status, &printing);
  +            }
  +            else if (!strcmp(directive, "else")) {
  +                if (!if_nesting) {
  +                    ret = handle_else(f, r, error, &conditional_status,
  +                                      &printing);
  +                }
                   continue;
  -            } else if(!strcmp(directive,"elif")) {
  -                if (!if_nesting)
  -                    ret = handle_elif(f, r, error, &conditional_status, &printing);
  +            }
  +            else if (!strcmp(directive, "elif")) {
  +                if (!if_nesting) {
  +                    ret = handle_elif(f, r, error, &conditional_status,
  +                                      &printing);
  +                }
                   continue;
  -            } else if(!strcmp(directive,"endif")) {
  +            }
  +            else if (!strcmp(directive, "endif")) {
                   if (!if_nesting) {
  -                    ret = handle_endif(f, r, error, &conditional_status, &printing);
  -                } else {
  +                    ret = handle_endif(f, r, error, &conditional_status,
  +                                       &printing);
  +                }
  +                else {
                       if_nesting--;
                   }
                   continue;
  -            } 
  -            if (!printing) continue;
  -            if(!strcmp(directive,"exec")) {
  -                if(noexec) {
  -                    log_printf(r->server,"httpd: exec used but not allowed in %s",
  -                            r->filename);
  -                    if (printing) rputs(error, r);
  -                    ret = find_string(f,ENDING_SEQUENCE,r,0);
  -                } else 
  -                    ret=handle_exec(f, r, error);
  -            } else if(!strcmp(directive,"config"))
  -                ret=handle_config(f, r, error, timefmt, &sizefmt);
  -            else if(!strcmp(directive,"set"))
  -                ret=handle_set(f, r, error);
  -            else if(!strcmp(directive,"include"))
  -                ret=handle_include(f, r, error, noexec);
  -            else if(!strcmp(directive,"echo"))
  -                ret=handle_echo(f, r, error);
  -            else if(!strcmp(directive,"fsize"))
  -                ret=handle_fsize(f, r, error, sizefmt);
  -            else if(!strcmp(directive,"flastmod"))
  -                ret=handle_flastmod(f, r, error, timefmt);
  -            else if(!strcmp(directive,"printenv"))
  -                ret=handle_printenv(f, r, error);
  +            }
  +            if (!printing) {
  +                continue;
  +            }
  +            if (!strcmp(directive, "exec")) {
  +                if (noexec) {
  +                    log_printf(r->server,
  +                                "httpd: exec used but not allowed in %s",
  +                                r->filename);
  +                    if (printing) {
  +                        rputs(error, r);
  +                    }
  +                    ret = find_string(f, ENDING_SEQUENCE, r, 0);
  +                }
  +                else {
  +                    ret = handle_exec(f, r, error);
  +                }
  +            }
  +            else if (!strcmp(directive, "config")) {
  +                ret = handle_config(f, r, error, timefmt, &sizefmt);
  +            }
  +            else if (!strcmp(directive, "set")) {
  +                ret = handle_set(f, r, error);
  +            }
  +            else if (!strcmp(directive, "include")) {
  +                ret = handle_include(f, r, error, noexec);
  +            }
  +            else if (!strcmp(directive, "echo")) {
  +                ret = handle_echo(f, r, error);
  +            }
  +            else if (!strcmp(directive, "fsize")) {
  +                ret = handle_fsize(f, r, error, sizefmt);
  +            }
  +            else if (!strcmp(directive, "flastmod")) {
  +                ret = handle_flastmod(f, r, error, timefmt);
  +            }
  +            else if (!strcmp(directive, "printenv")) {
  +                ret = handle_printenv(f, r, error);
  +            }
   #ifdef USE_PERL_SSI
  -            else if(!strcmp(directive,"perl")) 
  -                ret=handle_perl(f, r, error);
  +            else if (!strcmp(directive, "perl")) {
  +                ret = handle_perl(f, r, error);
  +            }
   #endif
               else {
  -                log_printf(r->server,
  -                        "httpd: unknown directive \"%s\" in parsed doc %s",
  -                        directive,r->filename);
  -                if (printing) rputs(error, r);
  -                ret=find_string(f,ENDING_SEQUENCE,r,0);
  +                log_printf(r->server, "httpd: unknown directive \"%s\" "
  +                            "in parsed doc %s",
  +                            directive, r->filename);
  +                if (printing) {
  +                    rputs(error, r);
  +                }
  +                ret = find_string(f, ENDING_SEQUENCE, r, 0);
               }
  -            if(ret) {
  -                log_printf(r->server,"httpd: premature EOF in parsed file %s",
  -			r->filename);
  +            if (ret) {
  +                log_printf(r->server, "httpd: premature EOF in parsed file %s",
  +                            r->filename);
                   return;
               }
  -        } else 
  +        }
  +        else {
               return;
  +        }
       }
   }
   
  @@ -1766,52 +2157,68 @@
    */
   
   module includes_module;
  -enum xbithack { xbithack_off, xbithack_on, xbithack_full };
  +enum xbithack {
  +    xbithack_off, xbithack_on, xbithack_full
  +};
   
  -#ifdef XBITHACK	
  +#ifdef XBITHACK
   #define DEFAULT_XBITHACK xbithack_full
   #else
   #define DEFAULT_XBITHACK xbithack_off
   #endif
   
  -void *create_includes_dir_config (pool *p, char *dummy)
  +static void *create_includes_dir_config(pool *p, char *dummy)
   {
  -    enum xbithack *result = (enum xbithack*)palloc(p, sizeof (enum xbithack));
  +    enum xbithack *result = (enum xbithack *) palloc(p, sizeof(enum xbithack));
       *result = DEFAULT_XBITHACK;
       return result;
   }
   
  -const char *set_xbithack (cmd_parms *cmd, void *xbp, char *arg)
  +static const char *set_xbithack(cmd_parms *cmd, void *xbp, char *arg)
   {
  -   enum xbithack *state = (enum xbithack *)xbp;
  +    enum xbithack *state = (enum xbithack *) xbp;
   
  -   if (!strcasecmp (arg, "off")) *state = xbithack_off;
  -   else if (!strcasecmp (arg, "on")) *state = xbithack_on;
  -   else if (!strcasecmp (arg, "full")) *state = xbithack_full;
  -   else return "XBitHack must be set to Off, On, or Full";
  +    if (!strcasecmp(arg, "off")) {
  +        *state = xbithack_off;
  +    }
  +    else if (!strcasecmp(arg, "on")) {
  +        *state = xbithack_on;
  +    }
  +    else if (!strcasecmp(arg, "full")) {
  +        *state = xbithack_full;
  +    }
  +    else {
  +        return "XBitHack must be set to Off, On, or Full";
  +    }
   
  -   return NULL;
  +    return NULL;
   }
   
  -int send_parsed_file(request_rec *r)
  +static int send_parsed_file(request_rec *r)
   {
       FILE *f;
       enum xbithack *state =
  -	(enum xbithack *)get_module_config(r->per_dir_config,&includes_module);
  +    (enum xbithack *) get_module_config(r->per_dir_config, &includes_module);
       int errstatus;
   
  -    if (!(allow_options (r) & OPT_INCLUDES)) return DECLINED;
  -    if (r->method_number != M_GET) return DECLINED;
  +    if (!(allow_options(r) & OPT_INCLUDES)) {
  +        return DECLINED;
  +    }
  +    if (r->method_number != M_GET) {
  +        return DECLINED;
  +    }
       if (r->finfo.st_mode == 0) {
  -        log_reason("File does not exist",
  -            r->path_info ? pstrcat(r->pool, r->filename, r->path_info, NULL)
  -                : r->filename, r);
  -	return NOT_FOUND;
  +        log_printf(r->server, "File does not exist: %s",
  +                    (r->path_info
  +                     ? pstrcat(r->pool, r->filename, r->path_info, NULL)
  +                     : r->filename));
  +        return HTTP_NOT_FOUND;
       }
   
  -    if(!(f=pfopen(r->pool, r->filename, "r"))) {
  -        log_reason("file permissions deny server access", r->filename, r);
  -	return FORBIDDEN;
  +    if (!(f = pfopen(r->pool, r->filename, "r"))) {
  +        log_printf(r->server,
  +                    "file permissions deny server access: %s", r->filename);
  +        return HTTP_FORBIDDEN;
       }
   
       if (*state == xbithack_full
  @@ -1825,84 +2232,92 @@
       send_http_header(r);
   
       if (r->header_only) {
  -	pfclose (r->pool, f);
  -	return OK;
  +        pfclose(r->pool, f);
  +        return OK;
       }
  -   
  +
       if (r->main) {
  -	/* Kludge --- for nested includes, we want to keep the
  -	 * subprocess environment of the base document (for compatibility);
  -	 * that means torquing our own last_modified date as well so that
  -	 * the LAST_MODIFIED variable gets reset to the proper value if
  -	 * the nested document resets <!--#config timefmt-->
  -	 */
  -	r->subprocess_env = r->main->subprocess_env;
  -	r->finfo.st_mtime= r->main->finfo.st_mtime;
  -    } else { 
  -	add_common_vars (r);
  -	add_cgi_vars(r);
  -	add_include_vars (r, DEFAULT_TIME_FORMAT);
  +        /* Kludge --- for nested includes, we want to keep the
  +         * subprocess environment of the base document (for compatibility);
  +         * that means torquing our own last_modified date as well so that
  +         * the LAST_MODIFIED variable gets reset to the proper value if
  +         * the nested document resets <!--#config timefmt-->
  +         */
  +        r->subprocess_env = r->main->subprocess_env;
  +        r->finfo.st_mtime = r->main->finfo.st_mtime;
  +    }
  +    else {
  +        add_common_vars(r);
  +        add_cgi_vars(r);
  +        add_include_vars(r, DEFAULT_TIME_FORMAT);
       }
       hard_timeout("send SSI", r);
   
  -    send_parsed_content (f, r);
  -    
  -    kill_timeout (r);
  +    send_parsed_content(f, r);
  +
  +    kill_timeout(r);
       return OK;
   }
   
  -int send_shtml_file (request_rec *r)
  +static int send_shtml_file(request_rec *r)
   {
       r->content_type = "text/html";
       return send_parsed_file(r);
   }
   
  -int xbithack_handler (request_rec *r)
  +static int xbithack_handler(request_rec *r)
   {
  -    enum xbithack *state;
  -	
   #ifdef __EMX__
       /* OS/2 dosen't currently support the xbithack. This is being worked on. */
       return DECLINED;
   #else
  -    if (!(r->finfo.st_mode & S_IXUSR)) return DECLINED;
  +    enum xbithack *state;
  +
  +    if (!(r->finfo.st_mode & S_IXUSR)) {
  +        return DECLINED;
  +    }
  +
  +    state = (enum xbithack *) get_module_config(r->per_dir_config,
  +                                                &includes_module);
   
  -    state = (enum xbithack *)get_module_config(r->per_dir_config,
  -					       &includes_module);
  -    
  -    if (*state == xbithack_off) return DECLINED;
  -    return send_parsed_file (r);
  +    if (*state == xbithack_off) {
  +        return DECLINED;
  +    }
  +    return send_parsed_file(r);
   #endif
   }
   
  -command_rec includes_cmds[] = {
  -{ "XBitHack", set_xbithack, NULL, OR_OPTIONS, TAKE1, "Off, On, or Full" },
  -{ NULL }    
  +static command_rec includes_cmds[] =
  +{
  +    {"XBitHack", set_xbithack, NULL, OR_OPTIONS, TAKE1, "Off, On, or Full"},
  +    {NULL}
   };
   
  -handler_rec includes_handlers[] = {
  -{ INCLUDES_MAGIC_TYPE, send_shtml_file },
  -{ INCLUDES_MAGIC_TYPE3, send_shtml_file },
  -{ "server-parsed", send_parsed_file },
  -{ "text/html", xbithack_handler },
  -{ NULL }
  +static handler_rec includes_handlers[] =
  +{
  +    {INCLUDES_MAGIC_TYPE, send_shtml_file},
  +    {INCLUDES_MAGIC_TYPE3, send_shtml_file},
  +    {"server-parsed", send_parsed_file},
  +    {"text/html", xbithack_handler},
  +    {NULL}
   };
   
  -module includes_module = {
  -   STANDARD_MODULE_STUFF,
  -   NULL,			/* initializer */
  -   create_includes_dir_config,	/* dir config creater */
  -   NULL,			/* dir merger --- default is to override */
  -   NULL,			/* server config */
  -   NULL,			/* merge server config */
  -   includes_cmds,		/* command table */
  -   includes_handlers,		/* handlers */
  -   NULL,			/* filename translation */
  -   NULL,			/* check_user_id */
  -   NULL,			/* check auth */
  -   NULL,			/* check access */
  -   NULL,			/* type_checker */
  -   NULL,			/* fixups */
  -   NULL,			/* logger */
  -   NULL				/* header parser */
  +module includes_module =
  +{
  +    STANDARD_MODULE_STUFF,
  +    NULL,                       /* initializer */
  +    create_includes_dir_config, /* dir config creater */
  +    NULL,                       /* dir merger --- default is to override */
  +    NULL,                       /* server config */
  +    NULL,                       /* merge server config */
  +    includes_cmds,              /* command table */
  +    includes_handlers,          /* handlers */
  +    NULL,                       /* filename translation */
  +    NULL,                       /* check_user_id */
  +    NULL,                       /* check auth */
  +    NULL,                       /* check access */
  +    NULL,                       /* type_checker */
  +    NULL,                       /* fixups */
  +    NULL,                       /* logger */
  +    NULL                        /* header parser */
   };