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[] = {