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 /", ¤t->right->token.value[1], "/\n", NULL);
+ rvputs(r, " Re Compare (", current->left->token.value,
+ ") with /", ¤t->right->token.value[1], "/\n", NULL);
#endif
current->value =
re_check(r, current->left->token.value,
- ¤t->right->token.value[1]);
- } else {
+ ¤t->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 */
};