akosut 96/08/06 17:15:06
Modified: src mod_include.c
Log:
Add XSSI functionality.
Submitted by: Howard Fear
Reviewed by: Alexei Kosut, Rob Hartill, Randy Terbush
Revision Changes Path
1.13 +936 -78 apache/src/mod_include.c
Index: mod_include.c
===================================================================
RCS file: /export/home/cvs/apache/src/mod_include.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -C3 -r1.12 -r1.13
*** mod_include.c 1996/07/28 19:27:48 1.12
--- mod_include.c 1996/08/07 00:15:03 1.13
***************
*** 68,73 ****
--- 68,78 ----
#include "http_log.h"
#include "http_main.h"
#include "util_script.h"
+ #ifdef HAVE_POSIX_REGEX
+ #include <regex.h>
+ #else
+ #include "regex.h"
+ #endif
#define STARTING_SEQUENCE "<!--#"
#define ENDING_SEQUENCE "-->"
***************
*** 80,85 ****
--- 85,91 ----
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);
+
/* ------------------------ Environment function --------------------------
*/
void add_include_vars(request_rec *r, char *timefmt)
***************
*** 99,105 ****
table_set(e, "USER_NAME", pw->pw_name);
} else {
char uid[16];
! sprintf(uid, "user#%ld", (unsigned long)r->finfo.st_uid);
table_set(e, "USER_NAME", uid);
}
--- 105,111 ----
table_set(e, "USER_NAME", pw->pw_name);
} else {
char uid[16];
! sprintf(uid, "user#%lu", (unsigned long)r->finfo.st_uid);
table_set(e, "USER_NAME", uid);
}
***************
*** 118,124 ****
{ \
int i = getc(f); \
if(feof(f) || ferror(f) || (i == -1)) { \
! pfclose(p, f); \
return r; \
} \
c = (char)i; \
--- 124,130 ----
{ \
int i = getc(f); \
if(feof(f) || ferror(f) || (i == -1)) { \
! pfclose(p,f); \
return r; \
} \
c = (char)i; \
***************
*** 130,136 ****
* matter much, but this is an inner loop...
*/
! int find_string(FILE *in,char *str, request_rec *r) {
int x,l=strlen(str),p;
char c;
--- 136,142 ----
* matter much, but this is an inner loop...
*/
! int find_string(FILE *in,char *str, request_rec *r, int printing) {
int x,l=strlen(str),p;
char c;
***************
*** 145,154 ****
if(r) {
if(p) {
for(x=0;x<p;x++) {
! rputc(str[x],r);
}
}
! rputc(c,r);
}
p=0;
}
--- 151,160 ----
if(r) {
if(p) {
for(x=0;x<p;x++) {
! if (printing) rputc(str[x],r);
}
}
! if (printing) rputc(c,r);
}
p=0;
}
***************
*** 286,292 ****
tag_val = t;
while (isspace(c)) GET_CHAR(in, c, NULL,p); /* space before = */
! if (c != '=') return NULL;
do {
GET_CHAR(in,c,NULL,p); /* space after = */
--- 292,301 ----
tag_val = t;
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 = */
***************
*** 310,316 ****
return pstrdup (p, tag_val);
}
- /* the pool is required to allow GET_CHAR to call pfclose */
static int
get_directive(FILE *in, char *d, pool *p) {
char c;
--- 319,324 ----
***************
*** 332,337 ****
--- 340,417 ----
return 0;
}
+ /*
+ * Do variable substitution on strings
+ */
+ void parse_string(request_rec *r, char *in, char *out, int length)
+ {
+ char ch;
+ char *next = out;
+ int numchars = 0;
+
+ while ((ch = *in++) != '\0') {
+ switch(ch) {
+ case '\\':
+ *next++ = (*in != '\0') ? *in++ : '\0';
+ 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;
+ }
+ 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++;
+ }
+
+ /* Leave single dollar signs like the shell does */
+ val = (char *)NULL;
+ if (*var == '\0') {
+ if (strcmp(vtext, "$") == 0) {
+ var[0]='$', var[1]='\0';
+ val = &var[0];
+ }
+ } else
+ val = table_get (r->subprocess_env, &var[0]);
+ while ((val != (char *)NULL) && (*val != '\0')) {
+ *next++ = *val++;
+ if (++numchars == (length -1)) break;
+ }
+ break;
+ }
+ default:
+ *next++ = ch;
+ break;
+ }
+ if (++numchars == (length -1)) break;
+ }
+ *next = '\0';
+ return;
+ }
+
/* --------------------------- Action handlers ----------------------------
*/
int include_cgi(char *s, request_rec *r)
***************
*** 360,366 ****
if (run_sub_req (rr) == REDIRECT) {
char *location = table_get (rr->headers_out, "Location");
! location = escape_html(rr->pool, location);
rvputs(r,"<A HREF=\"", location, "\">", location, "</A>", NULL);
}
--- 440,446 ----
if (run_sub_req (rr) == REDIRECT) {
char *location = table_get (rr->headers_out, "Location");
! location = escape_html(rr->pool, location);
rvputs(r,"<A HREF=\"", location, "\">", location, "</A>", NULL);
}
***************
*** 371,376 ****
--- 451,457 ----
int handle_include(FILE *in, request_rec *r, char *error, int noexec) {
char tag[MAX_STRING_LEN];
+ char parsed_string[MAX_STRING_LEN];
char *tag_val;
while(1) {
***************
*** 380,395 ****
request_rec *rr=NULL;
char *error_fmt = NULL;
if (tag[0] == 'f')
{ /* be safe; only files in this directory or below allowed */
char tmp[MAX_STRING_LEN+2];
! sprintf(tmp, "/%s/", tag_val);
! if (tag_val[0] == '/' || strstr(tmp, "/../") != NULL)
error_fmt = "unable to include file %s in parsed file %s";
else
! rr = sub_req_lookup_file (tag_val, r);
} else
! rr = sub_req_lookup_uri (tag_val, r);
if (!error_fmt && rr->status != 200)
error_fmt = "unable to include %s in parsed file %s";
--- 461,477 ----
request_rec *rr=NULL;
char *error_fmt = NULL;
+ parse_string(r, tag_val, parsed_string, MAX_STRING_LEN);
if (tag[0] == 'f')
{ /* be safe; only files in this directory or below allowed */
char tmp[MAX_STRING_LEN+2];
! sprintf(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";
***************
*** 398,413 ****
&& (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";
--- 480,494 ----
&& (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";
***************
*** 423,429 ****
return 0;
else {
log_printf(r->server, "unknown parameter %s to tag include in
%s",
! tag, r->filename);
rputs(error, r);
}
}
--- 504,510 ----
return 0;
else {
log_printf(r->server, "unknown parameter %s to tag include in
%s",
! tag, r->filename);
rputs(error, r);
}
}
***************
*** 440,457 ****
char *s = ((include_cmd_arg *)arg)->s;
table *env = r->subprocess_env;
#ifdef DEBUG_INCLUDE_CMD
! #ifdef __EMX__
! /* under OS/2 /dev/tty is referenced as con */
! FILE *dbg = fopen ("con", "w");
! #else
! FILE *dbg = fopen ("/dev/tty", "w");
! #endif
#endif
char err_string [MAX_STRING_LEN];
#ifdef DEBUG_INCLUDE_CMD
fprintf (dbg, "Attempting to include command '%s'\n", s);
#endif
if (r->path_info && r->path_info[0] != '\0')
{
--- 521,538 ----
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
+ #ifdef __EMX__
+ /* under OS/2 /dev/tty is referenced as con */
+ FILE *dbg = fopen ("con", "w");
+ #else
fprintf (dbg, "Attempting to include command '%s'\n", s);
#endif
+ #endif
if (r->path_info && r->path_info[0] != '\0')
{
***************
*** 518,538 ****
char tag[MAX_STRING_LEN];
char *tag_val;
char *file = r->filename;
while(1) {
if(!(tag_val = get_tag (r->pool, in, tag, MAX_STRING_LEN, 1)))
return 1;
if(!strcmp(tag,"cmd")) {
! if(include_cmd(tag_val, r) == -1) {
! log_printf(r->server, "failed command exec %s in %s",
! tag_val, file);
rputs(error, r);
}
/* just in case some stooge changed directories */
chdir_file(r->filename);
}
else if(!strcmp(tag,"cgi")) {
! if(include_cgi(tag_val, r) == -1) {
log_printf(r->server, "invalid CGI ref %s in
%s",tag_val,file);
rputs(error, r);
}
--- 599,622 ----
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)))
return 1;
if(!strcmp(tag,"cmd")) {
! parse_string(r, tag_val, parsed_string, MAX_STRING_LEN);
! if(include_cmd(parsed_string, r) == -1) {
! log_printf(r->server, "unknown parameter %s to tag include
in %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);
! if(include_cgi(parsed_string, r) == -1) {
log_printf(r->server, "invalid CGI ref %s in
%s",tag_val,file);
rputs(error, r);
}
***************
*** 543,549 ****
return 0;
else {
log_printf(r->server, "unknown parameter %s to tag exec in %s",
! tag, file);
rputs(error, r);
}
}
--- 627,633 ----
return 0;
else {
log_printf(r->server, "unknown parameter %s to tag exec in %s",
! tag, file);
rputs(error, r);
}
}
***************
*** 566,572 ****
return 0;
else {
log_printf(r->server, "unknown parameter %s to tag echo in %s",
! tag, r->filename);
rputs(error, r);
}
}
--- 650,656 ----
return 0;
else {
log_printf(r->server, "unknown parameter %s to tag echo in %s",
! tag, r->filename);
rputs(error, r);
}
}
***************
*** 576,581 ****
--- 660,666 ----
int *sizefmt) {
char tag[MAX_STRING_LEN];
char *tag_val;
+ char parsed_string[MAX_STRING_LEN];
table *env = r->subprocess_env;
while(1) {
***************
*** 584,606 ****
if(!strcmp(tag,"errmsg"))
strcpy(error,tag_val);
else if(!strcmp(tag,"timefmt")) {
! time_t date = r->request_time;
! strcpy(tf,tag_val);
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")) {
! decodehtml(tag_val);
! if(!strcmp(tag_val,"bytes"))
*sizefmt = SIZEFMT_BYTES;
! else if(!strcmp(tag_val,"abbrev"))
*sizefmt = SIZEFMT_KMG;
}
else if(!strcmp(tag,"done"))
return 0;
else {
! log_printf(r->server, "unknown parameter %s to tag config in
%s",
tag, r->filename);
rputs(error, r);
}
--- 669,693 ----
if(!strcmp(tag,"errmsg"))
strcpy(error,tag_val);
else if(!strcmp(tag,"timefmt")) {
! time_t date = r->request_time;
! parse_string(r, tag_val, parsed_string, MAX_STRING_LEN);
! strcpy(tf,parsed_string);
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);
! decodehtml(parsed_string);
! if(!strcmp(parsed_string,"bytes"))
*sizefmt = SIZEFMT_BYTES;
! else if(!strcmp(parsed_string,"abbrev"))
*sizefmt = SIZEFMT_KMG;
}
else if(!strcmp(tag,"done"))
return 0;
else {
! log_printf(r->server,"unknown parameter %s to tag config in %s",
tag, r->filename);
rputs(error, r);
}
***************
*** 645,653 ****
}
}
else {
! log_printf(r->server, "unknown parameter %s to tag %s in %s",
tag, directive, r->filename);
! rputs(error, r);
return -1;
}
}
--- 732,740 ----
}
}
else {
! log_printf(r->server,"unknown parameter %s to tag %s in %s",
tag, directive, r->filename);
! rputs(error, r);
return -1;
}
}
***************
*** 658,686 ****
char tag[MAX_STRING_LEN];
char *tag_val;
struct stat finfo;
while(1) {
if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
return 1;
else if(!strcmp(tag,"done"))
return 0;
! else if(!find_file(r,"fsize",tag,tag_val,&finfo,error)) {
! if(sizefmt == SIZEFMT_KMG) {
! send_size(finfo.st_size, r);
! }
! else {
! int l,x;
! #if defined(BSD) && BSD > 199305
! sprintf(tag,"%qd",finfo.st_size);
! #else
! sprintf(tag,"%ld",finfo.st_size);
! #endif
! l = strlen(tag); /* grrr */
! for(x=0;x<l;x++) {
! if(x && (!((l-x) % 3))) {
! rputc(',', r);
}
- rputc (tag[x],r);
}
}
}
--- 745,777 ----
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)))
return 1;
else if(!strcmp(tag,"done"))
return 0;
! else {
! parse_string(r, tag_val, parsed_string, MAX_STRING_LEN);
! if(!find_file(r,"fsize",tag,parsed_string,&finfo,error)) {
! if(sizefmt == SIZEFMT_KMG) {
! send_size(finfo.st_size, r);
! }
! else {
! int l,x;
! #if defined(BSD) && BSD > 199305
! sprintf(tag,"%qd",finfo.st_size);
! #else
! sprintf(tag,"%ld",finfo.st_size);
! #endif
! l = strlen(tag); /* grrr */
! for(x=0;x<l;x++) {
! if(x && (!((l-x) % 3))) {
! rputc(',', r);
! }
! rputc (tag[x],r);
}
}
}
}
***************
*** 692,705 ****
char tag[MAX_STRING_LEN];
char *tag_val;
struct stat finfo;
while(1) {
if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
return 1;
else if(!strcmp(tag,"done"))
return 0;
! else if(!find_file(r,"flastmod",tag,tag_val,&finfo,error))
! rputs(ht_time(r->pool, finfo.st_mtime, tf, 0), r);
}
}
--- 783,1523 ----
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)))
+ return 1;
+ else if(!strcmp(tag,"done"))
+ return 0;
+ else {
+ parse_string(r, tag_val, parsed_string, MAX_STRING_LEN);
+ 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)
+ {
+ regex_t compiled;
+ char err_string[MAX_STRING_LEN];
+ int regex_error;
+
+ regex_error = regcomp(&compiled, rexp, REG_EXTENDED|REG_NOSUB);
+ if (regex_error) {
+ regerror(regex_error, &compiled, err_string,
(size_t)MAX_STRING_LEN);
+ log_printf(r->server,
+ "unable to compile pattern %s [%s]", rexp, &err_string);
+ return -1;
+ }
+ regex_error = regexec(&compiled, string, 0, (regmatch_t *)NULL, 0);
+ regfree(&compiled);
+ return(!regex_error);
+ }
+
+ enum token_type { token_string,
+ token_and, token_or, token_not, token_eq, token_ne,
+ token_rbrace, token_lbrace, token_group
+ };
+ struct token {
+ enum token_type type;
+ char value[MAX_STRING_LEN];
+ };
+
+ char *get_ptoken(request_rec *r, char *string, struct token *token) {
+ char ch;
+ 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;
+
+ switch(ch) {
+ case '(':
+ token->type = token_lbrace;
+ return(string);
+ case ')':
+ token->type = token_rbrace;
+ return(string);
+ case '=':
+ token->type = token_eq;
+ return(string);
+ case '!':
+ if (*string == '=') {
+ token->type = token_ne;
+ return(string+1);
+ } else {
+ token->type = token_not;
+ return(string);
+ }
+ case '\'':
+ token->type = token_string;
+ qs = 1;
+ break;
+ case '|':
+ if (*string == '|') {
+ token->type = token_or;
+ return(string+1);
+ }
+ case '&':
+ if (*string == '&') {
+ token->type = token_and;
+ return(string+1);
+ }
+ default:
+ token->type = token_string;
+ break;
+ }
+ /* We should only be here if we are in a string */
+ 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;
+ 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;
+ }
+ token->value[next++] = ch;
+ } else {
+ if (ch == '\'') { qs=0; ++string; goto TOKEN_DONE; }
+ token->value[next++] = ch;
+ }
+ }
+ TOKEN_DONE:
+ /* If qs is still set, I have an unmatched ' */
+ if (qs) { rputs("\nUnmatched '\n", r); next=0; }
+ token->value[next] = '\0';
+ return(string);
+ }
+
+
+ /*
+ * Hey I still know that goto's are BAD. I don't think that I've ever
+ * used two in the same project, let alone the same file before. But,
+ * I absolutely want to make sure that I clean up the memory in all
+ * 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)
+ {
+ struct parse_node {
+ struct parse_node *left, *right, *parent;
+ struct token token;
+ int value, done;
+ } *root, *current, *new;
+ char *parse;
+ char buffer[MAX_STRING_LEN];
+ struct 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", r->filename);
+ rputs(error, r);
+ return(0);
+ }
+
+ /* 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", r->filename);
+ rputs(error, r);
+ goto RETURN;
+ }
+ new->parent = new->left = new->right = (struct parse_node*)NULL;
+ new->done = 0;
+ if ((parse = get_ptoken(r, parse, &new->token)) == (char *)NULL)
+ break;
+ switch(new->token.type) {
+
+ case token_string:
+ #ifdef DEBUG_INCLUDE
+ rvputs(r," Token: string (", new->token.value, ")\n", NULL);
+ #endif
+ 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-1);
+ strncat(current->token.value, new->token.value,
MAX_STRING_LEN-1);
+ break;
+ case token_eq:
+ case token_ne:
+ case token_and:
+ case token_or:
+ case token_lbrace:
+ case token_not:
+ new->parent = current;
+ current = current->right = new;
+ break;
+ default:
+ log_printf(r->server,
+ "Invalid expression %s", expr, r->filename);
+ rputs(error, r);
+ goto RETURN;
+ }
+ break;
+
+ case token_and:
+ case token_or:
+ #ifdef DEBUG_INCLUDE
+ rputs (" Token: and/or\n", r);
+ #endif
+ if (current == (struct parse_node*)NULL) {
+ log_printf(r->server,
+ "Invalid expression %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:
+ current = current->parent;
+ continue;
+ case token_lbrace:
+ break;
+ default:
+ log_printf(r->server,
+ "Invalid expression %s", expr, r->filename);
+ rputs(error, r);
+ goto RETURN;
+ }
+ break;
+ }
+ if (current == (struct parse_node*)NULL) {
+ new->left = root;
+ new->left->parent = new;
+ new->parent = (struct parse_node*)NULL;
+ root = new;
+ } else {
+ new->left = current->right;
+ current->right = new;
+ new->parent = current;
+ }
+ current = new;
+ break;
+
+ case token_not:
+ #ifdef DEBUG_INCLUDE
+ rputs(" Token: not\n", r);
+ #endif
+ 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:
+ break;
+ default:
+ log_printf(r->server,
+ "Invalid expression %s", expr, r->filename);
+ rputs(error, r);
+ goto RETURN;
+ }
+ break;
+ }
+ if (current == (struct parse_node*)NULL) {
+ new->left = root;
+ new->left->parent = new;
+ new->parent = (struct parse_node*)NULL;
+ root = new;
+ } else {
+ new->left = current->right;
+ current->right = new;
+ new->parent = current;
+ }
+ current = new;
+ break;
+
+ case token_eq:
+ case token_ne:
+ #ifdef DEBUG_INCLUDE
+ rputs(" Token: eq/ne\n", r);
+ #endif
+ if (current == (struct parse_node*)NULL) {
+ log_printf(r->server,
+ "Invalid expression %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:
+ current = current->parent;
+ continue;
+ 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", expr, r->filename);
+ rputs(error, r);
+ goto RETURN;
+ }
+ break;
+ }
+ if (current == (struct parse_node*)NULL) {
+ new->left = root;
+ new->left->parent = new;
+ new->parent = (struct parse_node*)NULL;
+ root = new;
+ } else {
+ new->left = current->right;
+ current->right = new;
+ new->parent = current;
+ }
+ current = new;
+ break;
+
+ case token_rbrace:
+ #ifdef DEBUG_INCLUDE
+ rputs(" Token: rbrace\n", r);
+ #endif
+ 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\n", expr,
r->filename);
+ rputs(error, r);
+ goto RETURN;
+ }
+ break;
+
+ case token_lbrace:
+ #ifdef DEBUG_INCLUDE
+ rputs(" Token: lbrace\n", r);
+ #endif
+ 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:
+ break;
+ case token_string:
+ case token_group:
+ default:
+ log_printf(r->server,
+ "Invalid expression %s", expr, r->filename);
+ rputs(error, r);
+ goto RETURN;
+ }
+ break;
+ }
+ if (current == (struct parse_node*)NULL) {
+ new->left = root;
+ new->left->parent = new;
+ new->parent = (struct parse_node*)NULL;
+ root = new;
+ } else {
+ new->left = current->right;
+ current->right = new;
+ new->parent = current;
+ }
+ current = new;
+ 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);
+ strncpy(current->token.value, buffer, MAX_STRING_LEN-1);
+ current->value = (current->token.value[0] != '\0');
+ current->done = 1;
+ current = current->parent;
+ break;
+
+ case token_and:
+ case token_or:
+ #ifdef DEBUG_INCLUDE
+ 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", expr, r->filename);
+ rputs(error, r);
+ goto RETURN;
+ }
+ if (!current->left->done) {
+ switch(current->left->token.type) {
+ case token_string:
+ parse_string(r, current->left->token.value,
+ buffer, MAX_STRING_LEN);
+ strncpy(current->left->token.value, buffer,
+ MAX_STRING_LEN-1);
+ current->left->done = 1;
+ break;
+ default:
+ current = current->left;
+ continue;
+ }
+ }
+ if (!current->right->done) {
+ switch(current->right->token.type) {
+ case token_string:
+ parse_string(r, current->right->token.value,
+ buffer, MAX_STRING_LEN);
+ strncpy(current->right->token.value, buffer,
+ MAX_STRING_LEN-1);
+ current->right->done = 1;
+ break;
+ 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);
+ #endif
+ 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);
+ #endif
+ current->done = 1;
+ current = current->parent;
+ break;
+
+ case token_eq:
+ case token_ne:
+ #ifdef DEBUG_INCLUDE
+ 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", expr, r->filename);
+ rputs(error, r);
+ goto RETURN;
+ }
+ parse_string(r, current->left->token.value, buffer,
MAX_STRING_LEN);
+ strncpy(current->left->token.value, buffer, MAX_STRING_LEN-1);
+ parse_string(r, current->right->token.value, buffer,
MAX_STRING_LEN);
+ strncpy(current->right->token.value, buffer, MAX_STRING_LEN-1);
+ 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",
+ 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);
+ #endif
+ current->value =
+ re_check(r, current->left->token.value,
+ ¤t->right->token.value[1]);
+ } else {
+ #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) == 0);
+ }
+ if (current->token.type == token_ne)
+ current->value = !current->value;
+ #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) {
+ if (!current->right->done) {
+ current = current->right;
+ continue;
+ }
+ current->value = !current->right->value;
+ } else {
+ current->value = 0;
+ }
+ #ifdef DEBUG_INCLUDE
+ 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) {
+ if (!current->right->done) {
+ current = current->right;
+ continue;
+ }
+ current->value = current->right->value;
+ } else {
+ current->value = 1;
+ }
+ #ifdef DEBUG_INCLUDE
+ 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\n", expr,
r->filename);
+ rputs(error, r);
+ goto RETURN;
+
+ case token_rbrace:
+ log_printf(r->server,"Unmatched ')' in %s\n", expr,
r->filename);
+ rputs(error, r);
+ goto RETURN;
+
+ default:
+ log_printf(r->server,"bad token type");
+ rputs(error, r);
+ goto 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)
+ {
+ char tag[MAX_STRING_LEN];
+ char *tag_val = '\0';
+ char *expr = '\0';
+
+ while(1) {
+ tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 0);
+ if(*tag == '\0')
+ return 1;
+ else if(!strcmp(tag,"done")) {
+ *printing = *conditional_status = parse_expr(r, expr, error);
+ #ifdef DEBUG_INCLUDE
+ rvputs(r,"**** if conditional_status=\"", *conditional_status ? "1" : "0",
"\"\n", NULL);
+ #endif
+ return 0;
+ } else if(!strcmp(tag,"expr")) {
+ expr = tag_val;
+ #ifdef DEBUG_INCLUDE
+ rvputs(r,"**** if expr=\"", expr, "\"\n", NULL);
+ #endif
+ } 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)
+ {
+ char tag[MAX_STRING_LEN];
+ char *tag_val = '\0';
+ char *expr = '\0';
while(1) {
+ tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 0);
+ if(*tag == '\0')
+ return 1;
+ else if(!strcmp(tag,"done")) {
+ #ifdef DEBUG_INCLUDE
+ rvputs(r,"**** elif conditional_status=\"", *conditional_status ? "1" :
"0", "\"\n", NULL);
+ #endif
+ if (*conditional_status) {
+ *printing = 0;
+ return(0);
+ }
+ *printing = *conditional_status = parse_expr(r, expr, error);
+ #ifdef DEBUG_INCLUDE
+ rvputs(r,"**** elif conditional_status=\"", *conditional_status ? "1" :
"0", "\"\n", NULL);
+ #endif
+ return 0;
+ } else if(!strcmp(tag,"expr")) {
+ expr = tag_val;
+ #ifdef DEBUG_INCLUDE
+ rvputs(r,"**** if expr=\"", expr, "\"\n", NULL);
+ #endif
+ } 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)
+ {
+ char tag[MAX_STRING_LEN];
+ char *tag_val;
+
+ if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
+ return 1;
+ else if(!strcmp(tag,"done")) {
+ #ifdef DEBUG_INCLUDE
+ 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);
+ return -1;
+ }
+ }
+
+ int handle_endif(FILE *in, request_rec *r, 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))) {
+ return 1;
+ } else if(!strcmp(tag,"done")) {
+ #ifdef DEBUG_INCLUDE
+ rvputs(r,"**** endif conditional_status=\"", *conditional_status ? "1" :
"0", "\"\n", NULL);
+ #endif
+ *conditional_status = 1;
+ return 0;
+ } else {
+ log_printf(r->server, "endif directive does not take tags");
+ rputs(error, r);
+ return -1;
+ }
+ }
+
+ int handle_set(FILE *in, request_rec *r, char *error)
+ {
+ char tag[MAX_STRING_LEN];
+ char parsed_string[MAX_STRING_LEN];
+ char *tag_val;
+ char *var;
+
+ var = (char *)NULL;
+ while (1) {
if(!(tag_val = get_tag(r->pool, in, tag, MAX_STRING_LEN, 1)))
return 1;
else if(!strcmp(tag,"done"))
return 0;
! else if (!strcmp(tag,"var")) {
! var = tag_val;
! } else if (!strcmp(tag,"value")) {
! if (var == (char *)NULL) {
! log_printf(r->server,
! "variable must precede value in set directive");
! rputs(error, r);
! return -1;
! }
! parse_string(r, tag_val, parsed_string, MAX_STRING_LEN);
! table_set (r->subprocess_env, var, parsed_string);
! }
! }
! }
!
! int handle_printenv(FILE *in, request_rec *r, 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)))
! 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");
! rputs(error, r);
! return -1;
}
}
***************
*** 715,743 ****
char timefmt[MAX_STRING_LEN];
int noexec = allow_options (r) & OPT_INCNOEXEC;
int ret, sizefmt;
strcpy(error,DEFAULT_ERROR_MSG);
strcpy(timefmt,DEFAULT_TIME_FORMAT);
sizefmt = SIZEFMT_KMG;
chdir_file (r->filename);
while(1) {
! if(!find_string(f,STARTING_SEQUENCE,r)) {
if(get_directive(f,directive,r->pool))
return;
if(!strcmp(directive,"exec")) {
if(noexec) {
! log_printf(r->server,
! "httpd: exec used but not allowed in %s",
! r->filename);
! rputs(error, r);
! ret = find_string(f,ENDING_SEQUENCE,NULL);
} else
ret=handle_exec(f, r, error);
! }
! else if(!strcmp(directive,"config"))
ret=handle_config(f, r, error, timefmt, &sizefmt);
else if(!strcmp(directive,"include"))
ret=handle_include(f, r, error, noexec);
else if(!strcmp(directive,"echo"))
--- 1533,1600 ----
char timefmt[MAX_STRING_LEN];
int noexec = allow_options (r) & OPT_INCNOEXEC;
int ret, sizefmt;
+ int if_nesting;
+ int printing;
+ int conditional_status;
strcpy(error,DEFAULT_ERROR_MSG);
strcpy(timefmt,DEFAULT_TIME_FORMAT);
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 */
+ table_set (r->subprocess_env, "QUERY_STRING", r->args);
+ unescape_url (r->args);
+ table_set (r->subprocess_env, "QUERY_STRING_UNESCAPED",
+ escape_shell_cmd (r->pool, r->args));
+ }
while(1) {
! if(!find_string(f,STARTING_SEQUENCE,r,printing)) {
if(get_directive(f,directive,r->pool))
return;
+ if(!strcmp(directive,"if")) {
+ if (!printing) {
+ if_nesting++;
+ } 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);
+ continue;
+ } else if(!strcmp(directive,"elif")) {
+ if (!if_nesting)
+ ret = handle_elif(f, r, error, &conditional_status,
&printing);
+ continue;
+ } else if(!strcmp(directive,"endif")) {
+ if (!if_nesting) {
+ ret=handle_else(f, r, error, &conditional_status,
&printing);
+ printing = 1;
+ } 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,NULL,printing);
} 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"))
***************
*** 746,761 ****
ret=handle_fsize(f, r, error, sizefmt);
else if(!strcmp(directive,"flastmod"))
ret=handle_flastmod(f, r, error, timefmt);
else {
! log_printf(r->server,
! "httpd: unknown directive %s in parsed doc %s",
! directive, r->filename);
! rputs(error, r);
! ret=find_string(f,ENDING_SEQUENCE,NULL);
}
if(ret) {
! log_printf(r->server, "httpd: premature EOF in parsed file
%s",
! r->filename);
return;
}
} else
--- 1603,1620 ----
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);
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,NULL,printing);
}
if(ret) {
! log_printf(r->server,"httpd: premature EOF in parsed file
%s",
! r->filename);
return;
}
} else
***************
*** 865,871 ****
/* 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;
state = (enum xbithack *)get_module_config(r->per_dir_config,
--- 1724,1729 ----
***************
*** 873,879 ****
if (*state == xbithack_off) return DECLINED;
return send_parsed_file (r);
! #endif
}
command_rec includes_cmds[] = {
--- 1731,1737 ----
if (*state == xbithack_off) return DECLINED;
return send_parsed_file (r);
! #endif
}
command_rec includes_cmds[] = {