Received: by taz.hyperreal.com (8.7.5/V2.0) id MAA29960; Tue, 6 Aug 1996 12:31:22 -0700 (PDT) Received: by taz.hyperreal.com (8.7.5/V2.0) id MAA29938; Tue, 6 Aug 1996 12:31:16 -0700 (PDT) Date: Tue, 6 Aug 1996 12:31:16 -0700 (PDT) From: Alexei Kosut Message-Id: <199608061931.MAA29938@taz.hyperreal.com> To: apache-cvs@hyperreal.com Subject: cvs commit: apache/src alloc.c alloc.h http_config.h mod_cgi.c util_script.c util_script.h Sender: owner-apache-cvs@apache.org Precedence: bulk Reply-To: new-httpd@hyperreal.com akosut 96/08/06 12:31:15 Modified: src alloc.c alloc.h http_config.h mod_cgi.c util_script.c util_script.h Log: Add ScriptLog directive to cgi_module, with accompanying hooks in the core code. Reviewed by: Jim Jagielski Revision Changes Path 1.9 +36 -3 apache/src/alloc.c Index: alloc.c =================================================================== RCS file: /export/home/cvs/apache/src/alloc.c,v retrieving revision 1.8 retrieving revision 1.9 diff -C3 -r1.8 -r1.9 *** alloc.c 1996/07/25 19:32:25 1.8 --- alloc.c 1996/08/06 19:31:04 1.9 *************** *** 852,864 **** a->subprocesses = new; } ! int spawn_child (pool *p, void (*func)(void *), void *data, ! enum kill_conditions kill_how, ! FILE **pipe_in, FILE **pipe_out) { int pid; int in_fds[2]; int out_fds[2]; block_alarms(); --- 852,865 ---- a->subprocesses = new; } ! int spawn_child_err (pool *p, void (*func)(void *), void *data, ! enum kill_conditions kill_how, ! FILE **pipe_in, FILE **pipe_out, FILE **pipe_err) { int pid; int in_fds[2]; int out_fds[2]; + int err_fds[2]; block_alarms(); *************** *** 876,881 **** --- 877,893 ---- return 0; } + if (pipe_err && pipe (err_fds) < 0) { + if (pipe_in) { + close (in_fds[0]); close (in_fds[1]); + } + if (pipe_out) { + close (out_fds[0]); close (out_fds[1]); + } + unblock_alarms(); + return 0; + } + if ((pid = fork()) < 0) { if (pipe_in) { close (in_fds[0]); close (in_fds[1]); *************** *** 883,888 **** --- 895,903 ---- if (pipe_out) { close (out_fds[0]); close (out_fds[1]); } + if (pipe_err) { + close (err_fds[0]); close (err_fds[1]); + } unblock_alarms(); return 0; } *************** *** 902,907 **** --- 917,928 ---- close (in_fds[0]); } + if (pipe_err) { + close (err_fds[0]); + dup2 (err_fds[1], STDERR_FILENO); + close (err_fds[1]); + } + /* HP-UX SIGCHLD fix goes here, if someone will remind me what it is... */ signal (SIGCHLD, SIG_DFL); /* Was that it? */ *************** *** 935,940 **** --- 956,973 ---- #endif if (*pipe_in) note_cleanups_for_file (p, *pipe_in); + } + + if (pipe_err) { + close (err_fds[1]); + #ifdef __EMX__ + /* Need binary mode set for OS/2. */ + *pipe_err = fdopen (err_fds[0], "rb"); + #else + *pipe_err = fdopen (err_fds[0], "r"); + #endif + + if (*pipe_err) note_cleanups_for_file (p, *pipe_err); } unblock_alarms(); 1.8 +5 -2 apache/src/alloc.h Index: alloc.h =================================================================== RCS file: /export/home/cvs/apache/src/alloc.h,v retrieving revision 1.7 retrieving revision 1.8 diff -C3 -r1.7 -r1.8 *** alloc.h 1996/07/25 19:32:26 1.7 --- alloc.h 1996/08/06 19:31:05 1.8 *************** *** 228,235 **** enum kill_conditions { kill_never, kill_always, kill_after_timeout, just_wait}; ! int spawn_child (pool *, void (*)(void *), void *, ! enum kill_conditions, FILE **pipe_in, FILE **pipe_out); #ifdef __EMX__ int spawn_child_os2 (pool *, void (*)(void *), void *, enum kill_conditions, FILE **pipe_in, FILE **pipe_out, char *buffer, int lenp); --- 228,238 ---- enum kill_conditions { kill_never, kill_always, kill_after_timeout, just_wait}; ! int spawn_child_err (pool *, void (*)(void *), void *, ! enum kill_conditions, FILE **pipe_in, FILE **pipe_out, ! FILE **pipe_err); ! #define spawn_child(p,f,v,k,in,out) spawn_child_err(p,f,v,k,in,out,NULL) ! #ifdef __EMX__ int spawn_child_os2 (pool *, void (*)(void *), void *, enum kill_conditions, FILE **pipe_in, FILE **pipe_out, char *buffer, int lenp); 1.10 +1 -1 apache/src/http_config.h Index: http_config.h =================================================================== RCS file: /export/home/cvs/apache/src/http_config.h,v retrieving revision 1.9 retrieving revision 1.10 diff -C3 -r1.9 -r1.10 *** http_config.h 1996/07/28 19:27:43 1.9 --- http_config.h 1996/08/06 19:31:05 1.10 *************** *** 201,207 **** * handle it back-compatibly, or at least signal an error). */ ! #define MODULE_MAGIC_NUMBER 19960725 #define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, 0, __FILE__, NULL /* Generic accessors for other modules to get at their own module-specific --- 201,207 ---- * handle it back-compatibly, or at least signal an error). */ ! #define MODULE_MAGIC_NUMBER 19960806 #define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, 0, __FILE__, NULL /* Generic accessors for other modules to get at their own module-specific 1.13 +235 -39 apache/src/mod_cgi.c Index: mod_cgi.c =================================================================== RCS file: /export/home/cvs/apache/src/mod_cgi.c,v retrieving revision 1.12 retrieving revision 1.13 diff -C3 -r1.12 -r1.13 *** mod_cgi.c 1996/07/28 19:27:48 1.12 --- mod_cgi.c 1996/08/06 19:31:06 1.13 *************** *** 51,57 **** * */ - /* * http_script: keeps all script-related ramblings together. * --- 51,56 ---- *************** *** 74,79 **** --- 73,80 ---- #include "http_log.h" #include "util_script.h" + module cgi_module; + /* KLUDGE --- for back-combatibility, we don't have to check ExecCGI * in ScriptAliased directories, which means we need to know if this * request came through ScriptAlias or not... so the Alias module *************** *** 86,91 **** --- 87,264 ---- return t && (!strcmp (t, "cgi-script")); } + /* Configuration stuff */ + + #define DEFAULT_LOGBYTES 10385760 + #define DEFAULT_BUFBYTES 1024 + + typedef struct { + char *logname; + long logbytes; + int bufbytes; + } cgi_server_conf; + + void *create_cgi_config (pool *p, server_rec *s) + { + cgi_server_conf *c = + (cgi_server_conf *)pcalloc (p, sizeof(cgi_server_conf)); + + c->logname = NULL; + c->logbytes = DEFAULT_LOGBYTES; + c->bufbytes = DEFAULT_BUFBYTES; + + return c; + } + + void *merge_cgi_config (pool *p, void *basev, void *overridesv) + { + cgi_server_conf *base = (cgi_server_conf *)basev, + *overrides = (cgi_server_conf *)overrides; + + return overrides->logname ? overrides : base; + } + + char *set_scriptlog (cmd_parms *cmd, void *dummy, char *arg) { + server_rec *s = cmd->server; + cgi_server_conf *conf = + (cgi_server_conf *)get_module_config(s->module_config, &cgi_module); + + conf->logname = arg; + return NULL; + } + + char *set_scriptlog_length (cmd_parms *cmd, void *dummy, char *arg) { + server_rec *s = cmd->server; + cgi_server_conf *conf = + (cgi_server_conf *)get_module_config(s->module_config, &cgi_module); + + conf->logbytes = atol (arg); + return NULL; + } + + char *set_scriptlog_buffer (cmd_parms *cmd, void *dummy, char *arg) { + server_rec *s = cmd->server; + cgi_server_conf *conf = + (cgi_server_conf *)get_module_config(s->module_config, &cgi_module); + + conf->bufbytes = atoi (arg); + return NULL; + } + + command_rec cgi_cmds[] = { + { "ScriptLog", set_scriptlog, NULL, RSRC_CONF, TAKE1, + "the name of a log for script debugging info"}, + { "ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF, TAKE1, + "the maximum length (in bytes) of the script debug log"}, + { "ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF, TAKE1, + "the maximum size (in bytes) to record of a POST request"}, + { NULL} + }; + + int log_scripterror(request_rec *r, cgi_server_conf *conf, int ret, + char *error) + { + FILE *f; + + log_reason(error, r->filename, r); + + if (!conf->logname || + ((stat(server_root_relative(r->pool, conf->logname), &r->finfo) == 0) + && (r->finfo.st_size > conf->logbytes)) || + ((f = pfopen(r->pool, server_root_relative(r->pool, conf->logname), + "a")) == NULL)) { + return ret; + } + + /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */ + fprintf(f, "%%%% [%s] %s %s%s%s %s\n", get_time(), r->method, r->uri, + r->args ? "?" : "", r->args ? r->args : "", r->protocol); + /* "%% 500 /usr/local/etc/httpd/cgi-bin */ + fprintf(f, "%%%% %d %s\n", ret, r->filename); + + fprintf(f, "%%error\n%s\n", error); + + pfclose(r->pool, f); + return ret; + } + + int log_script(request_rec *r, cgi_server_conf *conf, int ret, + char *dbuf, char *sbuf, FILE *script_in, FILE *script_err) + { + table *hdrs_arr = r->headers_in; + table_entry *hdrs = (table_entry *)hdrs_arr->elts; + char argsbuffer[HUGE_STRING_LEN]; + FILE *f; + int i; + + if (!conf->logname || + ((stat(server_root_relative(r->pool, conf->logname), &r->finfo) == 0) + && (r->finfo.st_size > conf->logbytes)) || + ((f = pfopen(r->pool, server_root_relative(r->pool, conf->logname), + "a")) == NULL)) { + /* Soak up script output */ + while (fgets(argsbuffer, MAX_STRING_LEN-1, script_in) != NULL) + continue; + while (fgets(argsbuffer, MAX_STRING_LEN-1, script_err) != NULL) + continue; + return ret; + } + + /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */ + fprintf(f, "%%%% [%s] %s %s%s%s %s\n", get_time(), r->method, r->uri, + r->args ? "?" : "", r->args ? r->args : "", r->protocol); + /* "%% 500 /usr/local/etc/httpd/cgi-bin */ + fprintf(f, "%%%% %d %s\n", ret, r->filename); + + fputs("%request\n", f); + for (i = 0; i < hdrs_arr->nelts; ++i) { + if (!hdrs[i].key) continue; + fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); + } + if ((r->method_number == M_POST || r->method_number == M_PUT) + && *dbuf) { + fprintf(f, "\n%s\n", dbuf); + } + + fputs("%response\n", f); + hdrs_arr = r->err_headers_out; + hdrs = (table_entry *)hdrs_arr->elts; + + for (i = 0; i < hdrs_arr->nelts; ++i) { + if (!hdrs[i].key) continue; + fprintf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val); + } + + if (sbuf && *sbuf) + fprintf(f, "%s\n", sbuf); + + *argsbuffer = '\0'; + fgets(argsbuffer, HUGE_STRING_LEN-1, script_in); + if (*argsbuffer) { + fputs("%stdout\n", f); + fputs(argsbuffer, f); + while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL) + fputs(argsbuffer, f); + fputs("\n", f); + } + + *argsbuffer = '\0'; + fgets(argsbuffer, HUGE_STRING_LEN-1, script_err); + if (*argsbuffer) { + fputs("%stderr\n", f); + fputs(argsbuffer, f); + while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_err) != NULL) + fputs(argsbuffer, f); + fputs("\n", f); + } + + pfclose(r->pool, script_in); + pfclose(r->pool, script_err); + + pfclose(r->pool, f); + return ret; + } + /**************************************************************** * * Actual CGI handling... *************** *** 95,100 **** --- 268,274 ---- struct cgi_child_stuff { request_rec *r; int nph; + int debug; char *argv0; }; *************** *** 132,138 **** #endif chdir_file (r->filename); ! error_log2stderr (r->server); #ifndef __EMX__ if (nph) client_to_stdout (r->connection); --- 306,313 ---- #endif chdir_file (r->filename); ! if (!cld->debug) ! error_log2stderr (r->server); #ifndef __EMX__ if (nph) client_to_stdout (r->connection); *************** *** 165,175 **** int cgi_handler (request_rec *r) { ! int retval, nph; ! char *argv0; ! FILE *script_out, *script_in; char argsbuffer[HUGE_STRING_LEN]; int is_included = !strcmp (r->protocol, "INCLUDED"); struct cgi_child_stuff cld; --- 340,353 ---- int cgi_handler (request_rec *r) { ! int retval, nph, dbpos = 0; ! char *argv0, *dbuf = NULL; ! FILE *script_out, *script_in, *script_err; char argsbuffer[HUGE_STRING_LEN]; int is_included = !strcmp (r->protocol, "INCLUDED"); + void *sconf = r->server->module_config; + cgi_server_conf *conf = + (cgi_server_conf *)get_module_config(sconf, &cgi_module); struct cgi_child_stuff cld; *************** *** 185,217 **** else argv0 = r->filename; nph = !(strncmp(argv0,"nph-",4)); - if (!(allow_options (r) & OPT_EXECCGI) && !is_scriptaliased (r)) { - log_reason("Options ExecCGI is off in this directory", r->filename, r); - return FORBIDDEN; - } - if (nph && is_included) { - log_reason("attempt to include NPH CGI script", r->filename, r); - return FORBIDDEN; - } - - if (S_ISDIR(r->finfo.st_mode)) { - log_reason("attempt to invoke directory as script", r->filename, r); - return FORBIDDEN; - } - if (r->finfo.st_mode == 0) { - log_reason("script not found or unable to stat", r->filename, r); - return NOT_FOUND; - } - if(!can_exec(&r->finfo)) { - log_reason("file permissions deny server execution", r->filename, r); - return FORBIDDEN; - } if ((retval = setup_client_block(r))) return retval; add_common_vars (r); cld.argv0 = argv0; cld.r = r; cld.nph = nph; #ifdef __EMX__ if (should_client_block (r)) { --- 363,392 ---- else argv0 = r->filename; nph = !(strncmp(argv0,"nph-",4)); + + if (!(allow_options (r) & OPT_EXECCGI) && !is_scriptaliased (r)) + return log_scripterror(r, conf, FORBIDDEN, + "Options ExecCGI is off in this directory"); + if (nph && is_included) + return log_scripterror(r, conf, FORBIDDEN, + "attempt to include NPH CGI script"); + + if (S_ISDIR(r->finfo.st_mode)) + return log_scripterror(r, conf, FORBIDDEN, + "attempt to invoke directory as script"); + if (r->finfo.st_mode == 0) + return log_scripterror(r, conf, NOT_FOUND, + "script not found or unable to stat"); + if(!can_exec(&r->finfo)) + return log_scripterror(r, conf, FORBIDDEN, + "file permissions deny server execution"); if ((retval = setup_client_block(r))) return retval; add_common_vars (r); cld.argv0 = argv0; cld.r = r; cld.nph = nph; + cld.debug = conf->logname ? 1 : 0; #ifdef __EMX__ if (should_client_block (r)) { *************** *** 234,242 **** } #else ! if (!spawn_child (r->connection->pool, cgi_child, (void *)&cld, ! nph ? just_wait : kill_after_timeout, ! &script_out, nph ? NULL : &script_in)) { log_reason ("couldn't spawn child process", r->filename, r); return SERVER_ERROR; } --- 409,418 ---- } #else ! if (!spawn_child_err (r->connection->pool, cgi_child, (void *)&cld, ! nph ? just_wait : kill_after_timeout, ! &script_out, nph ? NULL : &script_in, ! &script_err)) { log_reason ("couldn't spawn child process", r->filename, r); return SERVER_ERROR; } *************** *** 254,267 **** #ifndef __EMX__ if (should_client_block(r)) { void (*handler)(); ! int len_read; ! hard_timeout ("copy script args", r); handler = signal (SIGPIPE, SIG_IGN); while ((len_read = read_client_block (r, argsbuffer, HUGE_STRING_LEN))) if (fwrite (argsbuffer, 1, len_read, script_out) == 0) break; fflush (script_out); signal (SIGPIPE, handler); --- 430,457 ---- #ifndef __EMX__ if (should_client_block(r)) { void (*handler)(); ! int dbsize, len_read; ! ! if (conf->logname) { ! dbuf = pcalloc(r->pool, conf->bufbytes+1); ! dbpos = 0; ! } ! hard_timeout ("copy script args", r); handler = signal (SIGPIPE, SIG_IGN); while ((len_read = read_client_block (r, argsbuffer, HUGE_STRING_LEN))) + { if (fwrite (argsbuffer, 1, len_read, script_out) == 0) break; + if (conf->logname) { + if ((dbpos + len_read) > conf->bufbytes) + dbsize = conf->bufbytes - dbpos; + else dbsize = len_read; + strncpy(dbuf + dbpos, argsbuffer, dbsize); + dbpos += dbsize; + } + } fflush (script_out); signal (SIGPIPE, handler); *************** *** 274,293 **** /* Handle script return... */ if (script_in && !nph) { ! char *location; int ret; ! if ((ret = scan_script_header(r, script_in))) ! return ret; location = table_get (r->headers_out, "Location"); if (location && location[0] == '/' && r->status == 200) { ! /* Soak up all the script output */ hard_timeout ("read from script", r); while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL) continue; kill_timeout (r); --- 464,485 ---- /* Handle script return... */ if (script_in && !nph) { ! char *location, sbuf[MAX_STRING_LEN]; int ret; ! if ((ret = scan_script_header_err(r, script_in, sbuf))) ! return log_script(r, conf, ret, dbuf, sbuf, script_in, script_err); location = table_get (r->headers_out, "Location"); if (location && location[0] == '/' && r->status == 200) { ! /* Soak up all the script output */ hard_timeout ("read from script", r); while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_in) != NULL) continue; + while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_err) != NULL) + continue; kill_timeout (r); *************** *** 310,317 **** --- 502,513 ---- hard_timeout ("send script output", r); send_http_header(r); if(!r->header_only) send_fd (script_in, r); + /* Soak up stderr */ + while (fgets(argsbuffer, HUGE_STRING_LEN-1, script_err) != NULL) + continue; kill_timeout (r); pfclose (r->connection->pool, script_in); + pfclose (r->connection->pool, script_err); } #ifdef __EMX__ *************** *** 336,346 **** NULL, /* initializer */ NULL, /* dir config creater */ NULL, /* dir merger --- default is to override */ ! NULL, /* server config */ ! NULL, /* merge server config */ ! NULL, /* command table */ cgi_handlers, /* handlers */ ! NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ --- 532,542 ---- NULL, /* initializer */ NULL, /* dir config creater */ NULL, /* dir merger --- default is to override */ ! create_cgi_config, /* server config */ ! merge_cgi_config, /* merge server config */ ! cgi_cmds, /* command table */ cgi_handlers, /* handlers */ ! NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ 1.19 +11 -6 apache/src/util_script.c Index: util_script.c =================================================================== RCS file: /export/home/cvs/apache/src/util_script.c,v retrieving revision 1.18 retrieving revision 1.19 diff -C3 -r1.18 -r1.19 *** util_script.c 1996/08/06 18:30:38 1.18 --- util_script.c 1996/08/06 19:31:06 1.19 *************** *** 244,255 **** } } ! int scan_script_header(request_rec *r, FILE *f) { ! char w[MAX_STRING_LEN]; ! char *l; int p; hard_timeout ("read script header", r); while(1) { --- 244,258 ---- } } ! int scan_script_header_err(request_rec *r, FILE *f, char *buffer) { ! char x[MAX_STRING_LEN]; ! char *w, *l; int p; + if (buffer) *buffer = '\0'; + w = buffer ? buffer : x; + hard_timeout ("read script header", r); while(1) { *************** *** 279,287 **** char malformed[(sizeof MALFORMED_MESSAGE)+1+MALFORMED_HEADER_LENGTH_TO_SHOW]; strcpy(malformed, MALFORMED_MESSAGE); strncat(malformed, w, MALFORMED_HEADER_LENGTH_TO_SHOW); ! /* Soak up all the script output --- may save an outright kill */ ! while (fgets(w, MAX_STRING_LEN-1, f) != NULL) ! continue; kill_timeout (r); log_reason (malformed, r->filename, r); --- 282,292 ---- char malformed[(sizeof MALFORMED_MESSAGE)+1+MALFORMED_HEADER_LENGTH_TO_SHOW]; strcpy(malformed, MALFORMED_MESSAGE); strncat(malformed, w, MALFORMED_HEADER_LENGTH_TO_SHOW); ! ! if (!buffer) ! /* Soak up all the script output --- may save an outright kill */ ! while (fgets(w, MAX_STRING_LEN-1, f) != NULL) ! continue; kill_timeout (r); log_reason (malformed, r->filename, r); 1.5 +2 -1 apache/src/util_script.h Index: util_script.h =================================================================== RCS file: /export/home/cvs/apache/src/util_script.h,v retrieving revision 1.4 retrieving revision 1.5 diff -C3 -r1.4 -r1.5 *** util_script.h 1996/07/21 20:03:46 1.4 --- util_script.h 1996/08/06 19:31:09 1.5 *************** *** 59,65 **** char **create_environment(pool *p, table *t); void add_cgi_vars(request_rec *r); void add_common_vars(request_rec *r); ! int scan_script_header(request_rec *r, FILE *f); void send_size(size_t size, request_rec *r); void call_exec (request_rec *r, char *argv0, char **env, int shellcmd); --- 59,66 ---- char **create_environment(pool *p, table *t); void add_cgi_vars(request_rec *r); void add_common_vars(request_rec *r); ! #define scan_script_header(a1,a2) scan_script_header_err(a1,a2,NULL) ! int scan_script_header_err(request_rec *r, FILE *f, char *buffer); void send_size(size_t size, request_rec *r); void call_exec (request_rec *r, char *argv0, char **env, int shellcmd);