int fcgi_server_send_params_record(fcgi_request_t *fr, uint16_t request_id, void *record_buffer) { /* add all environment variables to r->subprocess_env */ ap_add_common_vars(fr->r); ap_add_cgi_vars(fr->r); /* build FCGI_PARAMS record based on apache environement */ apr_pool_t *p = fr->r->pool; char **env = ap_create_environment(p, fr->r->subprocess_env); /* TODO: what if params > 64K? */ apr_status_t status; status = fcgi_record_params_build((fcgi_header_t)record_buffer, request_id, env); if (status != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, fr->r, "FastCGI: failed to build params record (id=%u)", request_id); return HTTP_INTERNAL_SERVER_ERROR; } apr_size_t len = fcgi_header_content_length_get((fcgi_header_t)record_buffer) + fcgi_header_padding_length_get((fcgi_header_t)record_buffer) + FCGI_HEADER_LEN; /* send data to the FastCGI server */ ssize_t bytes_sent = socket_send(fr, record_buffer, len); if (bytes_sent == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, fr->r, "FastCGI: failed to write to backend server (id=%u)", request_id); return HTTP_INTERNAL_SERVER_ERROR; } /* build and send VOID FCGI_PARAMS record */ status = fcgi_record_params_build((fcgi_header_t)record_buffer, request_id, NULL); if (status != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, fr->r, "FastCGI: failed to build params record (id=%u)", request_id); return HTTP_INTERNAL_SERVER_ERROR; } /* send data to the FastCGI server */ bytes_sent = socket_send(fr, record_buffer, FCGI_HEADER_LEN); if (bytes_sent == -1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, fr->r, "FastCGI: failed to write to backend server (id=%u)", request_id); return HTTP_INTERNAL_SERVER_ERROR; } return OK; }
static int dirsize(void *rp, child_info *pinfo) { char **env; int child_pid; request_rec *r = (request_rec *) rp; env = ap_create_environment(r->pool, r->subprocess_env); ap_error_log2stderr(r->server); r->filename = "/usr/bin/du"; // fixme: ugly! r->args = ap_pstrcat(r->pool, "-sk+", r->path_info, NULL); ap_cleanup_for_exec(); child_pid = ap_call_exec(r, pinfo, r->filename, env, 0); #ifdef WIN32 return(child_pid); #else ap_log_error(APLOG_MARK, APLOG_ERR, NULL, "exec of %s failed", r->filename); exit(0); return(0); #endif }
int suphp_source_child(void *rp, child_info *cinfo) { request_rec *r = (request_rec *) rp; suphp_conf *conf; pool *p = r->main ? r->main->pool : r->pool; char **argv, **env; table *empty_table = ap_make_table(p, 0); conf = ap_get_module_config(r->server->module_config, &suphp_module); /* We want to log output written to stderr */ ap_error_log2stderr(r->server); /* prepare argv for new process */ argv = ap_palloc(p, 4 * sizeof(char *)); argv[0] = ap_pstrdup(p, conf->php_path); argv[1] = "-s"; argv[2] = ap_pstrdup(p, r->filename); argv[3] = NULL; /* prepare environment */ env = ap_create_environment(p, empty_table); /* We cannot use ap_call_exec because of the interference with suExec */ /* So we do everything ourselves */ /* mandatory cleanup before execution */ ap_cleanup_for_exec(); execve(ap_pstrdup(p, conf->php_path), argv, env); /* We are still here? Okay - exec failed */ ap_log_error(APLOG_MARK, APLOG_ERR, NULL, "exec of %s failed", conf->php_path); exit(0); /* NOT REACHED */ return (0); }
apr_status_t proc_spawn_process(const char *cmdline, fcgid_proc_info *procinfo, fcgid_procnode *procnode) { HANDLE *finish_event, listen_handle; SECURITY_ATTRIBUTES SecurityAttributes; fcgid_server_conf *sconf; apr_procattr_t *proc_attr; apr_status_t rv; apr_file_t *file; const char * const *proc_environ; char sock_path[FCGID_PATH_MAX]; int argc; char const * wargv[APACHE_ARG_MAX + 1], *word; /* For wrapper */ const char *tmp; /* Build wrapper args */ argc = 0; tmp = cmdline; while (1) { word = ap_getword_white(procnode->proc_pool, &tmp); if (word == NULL || *word == '\0') break; if (argc >= APACHE_ARG_MAX) break; wargv[argc++] = word; } wargv[argc] = NULL; memset(&SecurityAttributes, 0, sizeof(SecurityAttributes)); /* Prepare finish event */ finish_event = apr_palloc(procnode->proc_pool, sizeof(HANDLE)); *finish_event = CreateEvent(NULL, TRUE, FALSE, NULL); if (*finish_event == NULL || !SetHandleInformation(*finish_event, HANDLE_FLAG_INHERIT, TRUE)) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: can't create mutex for subprocess"); return APR_ENOLOCK; } apr_pool_cleanup_register(procnode->proc_pool, finish_event, close_finish_event, apr_pool_cleanup_null); /* For proc_kill_gracefully() */ apr_pool_userdata_set(finish_event, FINISH_EVENT_DATA_NAME, NULL, procnode->proc_pool); /* Pass the finish event id to subprocess */ apr_table_setn(procinfo->proc_environ, SHUTDOWN_EVENT_NAME, apr_ltoa(procnode->proc_pool, (long) *finish_event)); /* Prepare the listen namedpipe file name (no check for truncation) */ apr_snprintf(sock_path, sizeof sock_path, "\\\\.\\pipe\\fcgidpipe-%lu.%d", GetCurrentProcessId(), g_process_counter++); /* Prepare the listen namedpipe handle */ SecurityAttributes.bInheritHandle = TRUE; SecurityAttributes.nLength = sizeof(SecurityAttributes); SecurityAttributes.lpSecurityDescriptor = NULL; listen_handle = CreateNamedPipe(sock_path, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 8192, 8192, 0, &SecurityAttributes); if (listen_handle == INVALID_HANDLE_VALUE) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: can't create namedpipe for subprocess"); return APR_ENOSOCKET; } apr_cpystrn(procnode->socket_path, sock_path, sizeof(procnode->socket_path)); apr_cpystrn(procnode->executable_path, wargv[0], sizeof(procnode->executable_path)); /* Build environment variables */ proc_environ = (const char * const *) ap_create_environment(procnode->proc_pool, procinfo->proc_environ); if (!proc_environ) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: can't build environment variables"); return APR_ENOMEM; } /* Create process now */ if ((rv = apr_procattr_create(&proc_attr, procnode->proc_pool)) != APR_SUCCESS || (rv = apr_procattr_dir_set(proc_attr, ap_make_dirstr_parent(procnode->proc_pool, wargv[0]))) != APR_SUCCESS || (rv = apr_procattr_cmdtype_set(proc_attr, APR_PROGRAM)) != APR_SUCCESS || (rv = apr_procattr_detach_set(proc_attr, 1)) != APR_SUCCESS || (rv = apr_procattr_io_set(proc_attr, APR_NO_PIPE, APR_NO_FILE, APR_NO_FILE)) != APR_SUCCESS || (rv = apr_os_file_put(&file, &listen_handle, 0, procnode->proc_pool)) != APR_SUCCESS || (rv = apr_procattr_child_in_set(proc_attr, file, NULL)) != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_WARNING, rv, procinfo->main_server, "mod_fcgid: can't create FastCGI process attribute"); CloseHandle(listen_handle); return APR_ENOPROC; } /* fork and exec now */ rv = apr_proc_create(&(procnode->proc_id), wargv[0], wargv, proc_environ, proc_attr, procnode->proc_pool); /* OK, I created the process, now put it back to idle list */ CloseHandle(listen_handle); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, procinfo->main_server, "mod_fcgid: can't run %s", wargv[0]); return rv; } /* FcgidWin32PreventOrphans feature */ sconf = ap_get_module_config(procinfo->main_server->module_config, &fcgid_module); if (sconf->hJobObjectForAutoCleanup != NULL) { /* Associate cgi process to current process */ if (AssignProcessToJobObject(sconf->hJobObjectForAutoCleanup, procnode->proc_id.hproc) == 0) { ap_log_error(APLOG_MARK, APLOG_WARNING, apr_get_os_error(), procinfo->main_server, "mod_fcgid: unable to assign child process to " "job object"); } } return APR_SUCCESS; }
int suphp_child(void *rp, child_info *cinfo) { request_rec *r = (request_rec *) rp; core_dir_config *core_conf; pool *p = r->main ? r->main->pool : r->pool; char **argv, **env; core_conf = (core_dir_config *) ap_get_module_config( r->per_dir_config, &core_module); /* We want to log output written to stderr */ ap_error_log2stderr(r->server); /* prepare argv for new process */ argv = ap_palloc(p, 2 * sizeof(char *)); argv[0] = SUPHP_PATH_TO_SUPHP; argv[1] = NULL; /* prepare environment */ env = ap_create_environment(p, r->subprocess_env); /* We cannot use ap_call_exec because of the interference with suExec */ /* So we do everything ourselves */ /* Set resource limits from core config */ #ifdef RLIMIT_CPU if (core_conf->limit_cpu != NULL) { if ((setrlimit(RLIMIT_CPU, core_conf->limit_cpu)) != 0) { ap_log_error(APLOG_MARK, APLOG_ERR, r->server, "setrlimit: failed to set CPU usage limit"); } } #endif /* RLIMIT_CPU */ #ifdef RLIMIT_NPROC if (core_conf->limit_nproc != NULL) { if ((setrlimit(RLIMIT_NPROC, core_conf->limit_nproc)) != 0) { ap_log_error(APLOG_MARK, APLOG_ERR, r->server, "setrlimit: failed to set process limit"); } } #endif /* RLIMIT_NPROC */ #ifdef RLIMIT_AS if (core_conf->limit_mem != NULL) { if ((setrlimit(RLIMIT_AS, core_conf->limit_mem)) != 0) { ap_log_error(APLOG_MARK, APLOG_ERR, r->server, "setrlimit: failed to set memory limit"); } } #endif /* RLIMIT_VMEM */ #ifdef RLIMIT_DATA if (core_conf->limit_mem != NULL) { if ((setrlimit(RLIMIT_DATA, core_conf->limit_mem)) != 0) { ap_log_error(APLOG_MARK, APLOG_ERR, r->server, "setrlimit: failed to set memory limit"); } } #endif /* RLIMIT_VMEM */ #ifdef RLIMIT_VMEM if (core_conf->limit_mem != NULL) { if ((setrlimit(RLIMIT_VMEM, core_conf->limit_mem)) != 0) { ap_log_error(APLOG_MARK, APLOG_ERR, r->server, "setrlimit: failed to set memory limit"); } } #endif /* RLIMIT_VMEM */ /* mandatory cleanup before execution */ ap_cleanup_for_exec(); execve(SUPHP_PATH_TO_SUPHP, argv, env); /* We are still here? Okay - exec failed */ ap_log_error(APLOG_MARK, APLOG_ERR, NULL, "exec of %s failed", SUPHP_PATH_TO_SUPHP); exit(0); /* NOT REACHED */ return (0); }
static apr_status_t run_cgi_child(apr_file_t **script_out, apr_file_t **script_in, apr_file_t **script_err, const char *command, const char * const argv[], request_rec *r, apr_pool_t *p, cgi_exec_info_t *e_info) { const char * const *env; apr_procattr_t *procattr; apr_proc_t *procnew; apr_status_t rc = APR_SUCCESS; #if defined(RLIMIT_CPU) || defined(RLIMIT_NPROC) || \ defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined (RLIMIT_AS) core_dir_config *conf = ap_get_module_config(r->per_dir_config, &core_module); #endif #ifdef DEBUG_CGI #ifdef OS2 /* Under OS/2 need to use device con. */ FILE *dbg = fopen("con", "w"); #else FILE *dbg = fopen("/dev/tty", "w"); #endif int i; #endif RAISE_SIGSTOP(CGI_CHILD); #ifdef DEBUG_CGI fprintf(dbg, "Attempting to exec %s as CGI child (argv0 = %s)\n", r->filename, argv[0]); #endif env = (const char * const *)ap_create_environment(p, r->subprocess_env); #ifdef DEBUG_CGI fprintf(dbg, "Environment: \n"); for (i = 0; env[i]; ++i) fprintf(dbg, "'%s'\n", env[i]); #endif /* Transmute ourselves into the script. * NB only ISINDEX scripts get decoded arguments. */ if (((rc = apr_procattr_create(&procattr, p)) != APR_SUCCESS) || ((rc = apr_procattr_io_set(procattr, e_info->in_pipe, e_info->out_pipe, e_info->err_pipe)) != APR_SUCCESS) || ((rc = apr_procattr_dir_set(procattr, ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) || #ifdef RLIMIT_CPU ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_CPU, conf->limit_cpu)) != APR_SUCCESS) || #endif #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_MEM, conf->limit_mem)) != APR_SUCCESS) || #endif #ifdef RLIMIT_NPROC ((rc = apr_procattr_limit_set(procattr, APR_LIMIT_NPROC, conf->limit_nproc)) != APR_SUCCESS) || #endif ((rc = apr_procattr_cmdtype_set(procattr, e_info->cmd_type)) != APR_SUCCESS) || ((rc = apr_procattr_detach_set(procattr, e_info->detached)) != APR_SUCCESS) || ((rc = apr_procattr_addrspace_set(procattr, e_info->addrspace)) != APR_SUCCESS) || ((rc = apr_procattr_child_errfn_set(procattr, cgi_child_errfn)) != APR_SUCCESS)) { /* Something bad happened, tell the world. */ ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, "couldn't set child process attributes: %s", r->filename); } else { procnew = apr_pcalloc(p, sizeof(*procnew)); rc = ap_os_create_privileged_process(r, procnew, command, argv, env, procattr, p); if (rc != APR_SUCCESS) { /* Bad things happened. Everyone should have cleaned up. */ ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, rc, r, "couldn't create child process: %d: %s", rc, apr_filepath_name_get(r->filename)); } else { apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT); *script_in = procnew->out; if (!*script_in) return APR_EBADF; apr_file_pipe_timeout_set(*script_in, r->server->timeout); if (e_info->prog_type == RUN_AS_CGI) { *script_out = procnew->in; if (!*script_out) return APR_EBADF; apr_file_pipe_timeout_set(*script_out, r->server->timeout); *script_err = procnew->err; if (!*script_err) return APR_EBADF; apr_file_pipe_timeout_set(*script_err, r->server->timeout); } } } #ifdef DEBUG_CGI fclose(dbg); #endif return (rc); }
/* init_ext_filter_process: get the external filter process going * This is per-filter-instance (i.e., per-request) initialization. */ static apr_status_t init_ext_filter_process(ap_filter_t *f) { ef_ctx_t *ctx = f->ctx; apr_status_t rc; ef_dir_t *dc = ctx->dc; const char * const *env; ctx->proc = apr_pcalloc(ctx->p, sizeof(*ctx->proc)); rc = apr_procattr_create(&ctx->procattr, ctx->p); ap_assert(rc == APR_SUCCESS); rc = apr_procattr_io_set(ctx->procattr, APR_CHILD_BLOCK, APR_CHILD_BLOCK, APR_CHILD_BLOCK); ap_assert(rc == APR_SUCCESS); rc = set_resource_limits(f->r, ctx->procattr); ap_assert(rc == APR_SUCCESS); if (dc->log_stderr > 0) { rc = apr_procattr_child_err_set(ctx->procattr, f->r->server->error_log, /* stderr in child */ NULL); ap_assert(rc == APR_SUCCESS); } rc = apr_procattr_child_errfn_set(ctx->procattr, child_errfn); ap_assert(rc == APR_SUCCESS); apr_pool_userdata_set(f->r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ctx->p); rc = apr_procattr_error_check_set(ctx->procattr, 1); if (rc != APR_SUCCESS) { return rc; } /* add standard CGI variables as well as DOCUMENT_URI, DOCUMENT_PATH_INFO, * and QUERY_STRING_UNESCAPED */ ap_add_cgi_vars(f->r); ap_add_common_vars(f->r); apr_table_setn(f->r->subprocess_env, "DOCUMENT_URI", f->r->uri); apr_table_setn(f->r->subprocess_env, "DOCUMENT_PATH_INFO", f->r->path_info); if (f->r->args) { /* QUERY_STRING is added by ap_add_cgi_vars */ char *arg_copy = apr_pstrdup(f->r->pool, f->r->args); ap_unescape_url(arg_copy); apr_table_setn(f->r->subprocess_env, "QUERY_STRING_UNESCAPED", ap_escape_shell_cmd(f->r->pool, arg_copy)); } env = (const char * const *) ap_create_environment(ctx->p, f->r->subprocess_env); rc = apr_proc_create(ctx->proc, ctx->filter->command, (const char * const *)ctx->filter->args, env, /* environment */ ctx->procattr, ctx->p); if (rc != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, f->r, "couldn't create child process to run `%s'", ctx->filter->command); return rc; } apr_pool_note_subprocess(ctx->p, ctx->proc, APR_KILL_AFTER_TIMEOUT); /* We don't want the handle to the child's stdin inherited by any * other processes created by httpd. Otherwise, when we close our * handle, the child won't see EOF because another handle will still * be open. */ apr_pool_cleanup_register(ctx->p, ctx->proc->in, apr_pool_cleanup_null, /* other mechanism */ ef_close_file); #if APR_FILES_AS_SOCKETS { apr_pollfd_t pfd = { 0 }; rc = apr_pollset_create(&ctx->pollset, 2, ctx->p, 0); ap_assert(rc == APR_SUCCESS); pfd.p = ctx->p; pfd.desc_type = APR_POLL_FILE; pfd.reqevents = APR_POLLOUT; pfd.desc.f = ctx->proc->in; rc = apr_pollset_add(ctx->pollset, &pfd); ap_assert(rc == APR_SUCCESS); pfd.reqevents = APR_POLLIN; pfd.desc.f = ctx->proc->out; rc = apr_pollset_add(ctx->pollset, &pfd); ap_assert(rc == APR_SUCCESS); } #endif return APR_SUCCESS; }
/* * ic_send_request() * ----------------- * Send the client's page/form request to the Interchange server */ static int ic_send_request(request_rec *r,ic_conf_rec *conf_rec,BUFF *ic_buff) { char **env,**e,*rp; int env_count,rc; char request_uri[MAX_STRING_LEN]; char redirect_url[MAX_STRING_LEN]; /* * send the Interchange-link arg parameter * (this is always empty for a CGI request) */ ap_hard_timeout("ic_send_request",r); if (ap_bputs("arg 0\n",ic_buff) < 0){ ap_log_reason("error writing to Interchange",r->uri,r); return HTTP_INTERNAL_SERVER_ERROR; } ap_reset_timeout(r); /* * initialize the environment to send to Interchange */ ap_add_common_vars(r); ap_add_cgi_vars(r); env = ap_create_environment(r->pool,r->subprocess_env); /* * count the number of environment variables present */ for (e = env,env_count = 0; *e != NULL; e++,env_count++){ if (strncmp(*e,"PATH_INFO=",10) == 0) env_count--; } env_count++; /* * send the environment variable count to Interchange */ if (ap_bprintf(ic_buff,"env %d\n",env_count) < 0){ ap_log_reason("error writing to Interchange",r->uri,r); return HTTP_INTERNAL_SERVER_ERROR; } ap_reset_timeout(r); /* * ignore the PATH_INFO variable and fix the SCRIPT_NAME, * REQUEST_URI and REDIRECT_URL variable content */ request_uri[0] = '\0'; redirect_url[0] = '\0'; for (e = env; *e != NULL; e++){ int len; char tmp[MAX_STRING_LEN]; char *p = *e; if (strncmp(p,"PATH_INFO=",10) == 0) continue; if (strncmp(p,"REDIRECT_URL=",13) == 0){ strncpy(redirect_url,p + 13,MAX_STRING_LEN - 14); continue; } if (strncmp(p,"REQUEST_URI=",12) == 0) strncpy(request_uri,p + 12,MAX_STRING_LEN - 13); else if (strncmp(p,"SCRIPT_NAME=",12) == 0){ p = tmp; strcpy(p,"SCRIPT_NAME="); if (conf_rec->script_name[0]) strcat(p,conf_rec->script_name); else{ strcat(p,"/"); strcat(p,conf_rec->location); } } len = strlen(p); if (len && ap_bprintf(ic_buff,"%d %s\n",len,p) < 0){ ap_log_reason("error writing to Interchange",r->uri,r); return HTTP_INTERNAL_SERVER_ERROR; } } rp = request_uri; while (*rp == '/') rp++; /* * strip the location path from the request_uri string * unless the location is "/" */ if (conf_rec->location[0] != '\0'){ if (strncmp(rp,conf_rec->location,conf_rec->location_len) == 0) rp += conf_rec->location_len; }else{ if (rp != request_uri) rp--; } strncpy(request_uri,rp,MAX_STRING_LEN - 1); request_uri[MAX_STRING_LEN - 1] = '\0'; for (rp = request_uri; *rp != '\0'; rp++){ if (*rp == '?'){ *rp = '\0'; break; } } switch (ap_unescape_url(request_uri)){ case BAD_REQUEST: case NOT_FOUND: ap_log_reason("Bad URI entities found",r->uri,r); return HTTP_INTERNAL_SERVER_ERROR; } /* * send the PATH_INFO variable as our "fixed" REQUEST_URI */ if (ap_bprintf(ic_buff,"%d PATH_INFO=%s\n",strlen(request_uri) + 10,request_uri) < 0){ ap_log_reason("error writing to Interchange",r->uri,r); return HTTP_INTERNAL_SERVER_ERROR; } /* * check if we have a REDIRECT_URL * if so then give it the same "fixes" as PATH_INFO (REQUEST_URI) */ if (redirect_url[0] != '\0'){ rp = redirect_url; while (*rp == '/') rp++; /* * strip the location path from the request_uri string * unless the location is "/" */ if (conf_rec->location[0] != '\0'){ if (strncmp(rp,conf_rec->location,conf_rec->location_len) == 0) rp += conf_rec->location_len; }else{ if (rp != redirect_url) rp--; } strncpy(redirect_url,rp,MAX_STRING_LEN - 1); redirect_url[MAX_STRING_LEN - 1] = '\0'; for (rp = redirect_url; *rp != '\0'; rp++){ if (*rp == '?'){ *rp = '\0'; break; } } switch (ap_unescape_url(redirect_url)){ case BAD_REQUEST: case NOT_FOUND: ap_log_reason("Bad URI entities found",r->uri,r); return HTTP_INTERNAL_SERVER_ERROR; } if (ap_bprintf(ic_buff,"%d REDIRECT_URL=%s\n",strlen(redirect_url) + 13,redirect_url) < 0){ ap_log_reason("error writing to Interchange",r->uri,r); return HTTP_INTERNAL_SERVER_ERROR; } } ap_reset_timeout(r); /* * send the request body, if any */ if (ap_should_client_block(r)){ char buffer[MAX_STRING_LEN]; int len_read; long length = r->remaining; if (ap_bprintf(ic_buff,"entity\n%ld ",length) < 0){ ap_log_reason("error writing to Interchange",r->uri,r); return HTTP_INTERNAL_SERVER_ERROR; } /* * read a block of data from the client and send * it to the Interchange server, until there * is nothing more to read from the client */ while ((len_read = ap_get_client_block(r,buffer,sizeof(buffer))) > 0){ ap_reset_timeout(r); if (ap_bwrite(ic_buff,buffer,len_read) != len_read){ ap_log_reason("error writing client block to Interchange",r->uri,r); return HTTP_INTERNAL_SERVER_ERROR; } ap_reset_timeout(r); } if (len_read < 0){ ap_log_reason("error reading block from client",r->uri,r); return HTTP_INTERNAL_SERVER_ERROR; } /* * send an end of line character to Interchange */ if (ap_bputc('\n',ic_buff) < 0){ ap_log_reason("error writing to Interchange",r->uri,r); return HTTP_INTERNAL_SERVER_ERROR; } } /* * all data has been sent, so send the "end" marker */ ap_reset_timeout(r); if (ap_bputs("end\n",ic_buff) < 0){ ap_log_reason("error writing the end marker to Interchange",r->uri,r); return HTTP_INTERNAL_SERVER_ERROR; } if (ap_bflush(ic_buff) < 0){ ap_log_reason("error flushing data to Interchange",r->uri,r); return HTTP_INTERNAL_SERVER_ERROR; } ap_kill_timeout(r); return OK; }
/** * Execute system command. First line of the output will be returned in * the "output" parameter. */ int apache2_exec(modsec_rec *msr, const char *command, const char **argv, char **output) { apr_procattr_t *procattr = NULL; apr_proc_t *procnew = NULL; apr_status_t rc = APR_SUCCESS; const char *const *env = NULL; apr_file_t *script_out = NULL; request_rec *r = msr->r; if (argv == NULL) { argv = apr_pcalloc(r->pool, 3 * sizeof(char *)); argv[0] = command; argv[1] = NULL; } ap_add_cgi_vars(r); ap_add_common_vars(r); /* PHP hack, getting around its silly security checks. */ apr_table_add(r->subprocess_env, "PATH_TRANSLATED", command); apr_table_add(r->subprocess_env, "REDIRECT_STATUS", "302"); env = (const char * const *)ap_create_environment(r->pool, r->subprocess_env); if (env == NULL) { msr_log(msr, 1, "Exec: Unable to create environment."); return -1; } procnew = apr_pcalloc(r->pool, sizeof(*procnew)); if (procnew == NULL) { msr_log(msr, 1, "Exec: Unable to allocate %lu bytes.", (unsigned long)sizeof(*procnew)); return -1; } apr_procattr_create(&procattr, r->pool); if (procattr == NULL) { msr_log(msr, 1, "Exec: Unable to create procattr."); return -1; } apr_procattr_io_set(procattr, APR_NO_PIPE, APR_FULL_BLOCK, APR_NO_PIPE); apr_procattr_cmdtype_set(procattr, APR_SHELLCMD); if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Exec: %s", log_escape_nq(r->pool, command)); } rc = apr_proc_create(procnew, command, argv, env, procattr, r->pool); if (rc != APR_SUCCESS) { msr_log(msr, 1, "Exec: Execution failed: %s (%s)", log_escape_nq(r->pool, command), get_apr_error(r->pool, rc)); return -1; } apr_pool_note_subprocess(r->pool, procnew, APR_KILL_AFTER_TIMEOUT); script_out = procnew->out; if (!script_out) { msr_log(msr, 1, "Exec: Failed to get script output pipe."); return -1; } apr_file_pipe_timeout_set(script_out, r->server->timeout); /* Now read from the pipe. */ { char buf[260] = ""; char *p = buf; apr_size_t nbytes = 255; apr_status_t rc2; rc2 = apr_file_read(script_out, buf, &nbytes); if (rc2 == APR_SUCCESS) { buf[nbytes] = 0; /* if there is more than one line ignore them */ while(*p != 0) { if (*p == 0x0a) *p = 0; p++; } if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Exec: First line from script output: \"%s\"", log_escape(r->pool, buf)); } if (output != NULL) *output = apr_pstrdup(r->pool, buf); /* Soak up the remaining data. */ nbytes = 255; while(apr_file_read(script_out, buf, &nbytes) == APR_SUCCESS) nbytes = 255; } else { msr_log(msr, 1, "Exec: Execution failed while reading output: %s (%s)", log_escape_nq(r->pool, command), get_apr_error(r->pool, rc2)); return -1; } } apr_proc_wait(procnew, NULL, NULL, APR_WAIT); return 1; }