static void setup_request_object(sl_vm_t* vm, request_rec* r) { struct iter_args ia; sl_request_opts_t opts; opts.method = (char*)r->method; opts.uri = r->uri; opts.path_info = r->path_info; opts.query_string = r->args; opts.remote_addr = r->connection->remote_ip; opts.content_type = (char*)apr_table_get(r->headers_in, "content-type"); ia.count = 0; ia.capacity = 4; ia.kvs = sl_alloc(vm->arena, sizeof(sl_request_key_value_t) * ia.capacity); ia.vm = vm; apr_table_do(iterate_apr_table, &ia, r->headers_in, NULL); opts.header_count = ia.count; opts.headers = ia.kvs; ap_add_common_vars(r); ap_add_cgi_vars(r); ia.count = 0; ia.capacity = 4; ia.kvs = sl_alloc(vm->arena, sizeof(sl_request_key_value_t) * ia.capacity); ia.vm = vm; apr_table_do(iterate_apr_table, &ia, r->subprocess_env, NULL); opts.env_count = ia.count; opts.env = ia.kvs; read_post_data(vm, &opts, r); sl_request_set_opts(vm, &opts); }
/** var env: Hash[String, Tainted[String]] This contains key+value pairs containing the current environment of the server. */ static lily_value *load_var_env(lily_options *options, uint16_t *unused) { request_rec *r = (request_rec *)options->data; ap_add_cgi_vars(r); ap_add_common_vars(r); return bind_table_as(options, r->subprocess_env, "env"); }
mrb_value ap_mrb_init_env(mrb_state *mrb, mrb_value self) { request_rec *r = ap_mrb_get_request(); ap_add_common_vars(r); ap_add_cgi_vars(r); ap_mrb_push_request(r); return self; }
static SV *make_env(request_rec *r, psgi_dir_config *c) { dTHX; HV *env; AV *version; char *url_scheme, *script_name, *vpath, *path_info; SV *input, *errors; env = newHV(); ap_add_cgi_vars(r); ap_add_common_vars(r); /* fix SCRIPT_NAME & PATH_INFO */ if (c->location == NULL || strcmp(c->location, "/") == 0) { script_name = ""; } else { script_name = c->location; } vpath = apr_pstrcat(r->pool, apr_table_get(r->subprocess_env, "SCRIPT_NAME"), apr_table_get(r->subprocess_env, "PATH_INFO"), NULL); path_info = &vpath[strlen(script_name)]; apr_table_set(r->subprocess_env, "PATH_INFO", path_info); apr_table_set(r->subprocess_env, "SCRIPT_NAME", script_name); apr_table_do(copy_env, env, r->subprocess_env, NULL); version = newAV(); av_push(version, newSViv(1)); av_push(version, newSViv(0)); (void) hv_store(env, "psgi.version", 12, newRV_noinc((SV *) version), 0); url_scheme = apr_table_get(r->subprocess_env, "HTTPS") == NULL ? "http" : "https"; (void) hv_store(env, "psgi.url_scheme", 15, newSVpv(url_scheme, 0), 0); input = newRV_noinc(newSV(0)); sv_magic(SvRV(input), NULL, PERL_MAGIC_ext, NULL, 0); mg_find(SvRV(input), PERL_MAGIC_ext)->mg_obj = (void *) r; sv_bless(input, gv_stashpv("ModPSGI::Input", 1)); (void) hv_store(env, "psgi.input", 10, input, 0); errors = newRV_noinc(newSV(0)); sv_magic(SvRV(errors), NULL, PERL_MAGIC_ext, NULL, 0); mg_find(SvRV(errors), PERL_MAGIC_ext)->mg_obj = (void *) r; sv_bless(errors, gv_stashpv("ModPSGI::Errors", 1)); (void) hv_store(env, "psgi.errors", 11, errors, 0); (void) hv_store(env, "psgi.multithread", 16, newSViv(psgi_multithread), 0); (void) hv_store(env, "psgi.multiprocess", 17, newSViv(psgi_multiprocess), 0); (void) hv_store(env, "psgi.run_once", 13, newSViv(0), 0); (void) hv_store(env, "psgi.nonblocking", 16, newSViv(0), 0); return newRV_inc((SV *) env); }
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 apache_bind_server(lily_parse_state *parser, request_rec *r) { int ret = 1; lily_symtab *symtab = parser->symtab; lily_class *package_cls = lily_class_by_id(symtab, SYM_CLASS_PACKAGE); lily_sig *package_sig = lily_try_sig_for_class(symtab, package_cls); lily_var *bound_var = lily_try_new_var(symtab, package_sig, "server", 0); if (bound_var) { lily_var *save_top = symtab->var_top; int save_spot = symtab->next_register_spot; int count = 0; ap_add_cgi_vars(r); ap_add_common_vars(r); bind_table_as(&count, parser, r, r->subprocess_env, "env"); apr_table_t *http_get_args; ap_args_to_table(r, &http_get_args); bind_table_as(&count, parser, r, http_get_args, "get"); bind_post(&count, parser, r); bind_httpmethod(&count, parser, r); if (count != -1) { int ok = 1; make_package(&ok, parser, bound_var, count, save_spot, save_top); if (ok == 0) ret = 0; } else ret = 0; } else ret = 0; return ret; }
static int req_add_env_vars (lua_State *L) { request_rec *r = CHECK_REQUEST_OBJECT(1); int mode = luaL_checkoption(L, 2, "all", add_var_modes); if ((mode == 0 || mode == 3) && ap_find_module) { module* env_module = ap_find_module(r->server, "env_module"); if (env_module) { env_dir_config_rec *sconf = ap_get_module_config(r->per_dir_config, env_module); if (sconf && sconf->vars && apr_table_elts(sconf->vars)->nelts) { r->subprocess_env = apr_table_overlay(r->pool, r->subprocess_env, sconf->vars); } } } if (mode == 1 || mode == 3) ap_add_common_vars(r); if (mode == 2 || mode == 3) ap_add_cgi_vars(r); return 0; }
int isapi_handler (request_rec *r) { LPEXTENSION_CONTROL_BLOCK ecb = ap_pcalloc(r->pool, sizeof(struct _EXTENSION_CONTROL_BLOCK)); HSE_VERSION_INFO *pVer = ap_pcalloc(r->pool, sizeof(HSE_VERSION_INFO)); HINSTANCE isapi_handle; BOOL (*isapi_version)(HSE_VERSION_INFO *); /* entry point 1 */ DWORD (*isapi_entry)(LPEXTENSION_CONTROL_BLOCK); /* entry point 2 */ BOOL (*isapi_term)(DWORD); /* optional entry point 3 */ isapi_cid *cid = ap_pcalloc(r->pool, sizeof(isapi_cid)); table *e = r->subprocess_env; DWORD read; char *p; int retval; int res; /* Use similar restrictions as CGIs */ if (!(ap_allow_options(r) & OPT_EXECCGI)) return FORBIDDEN; if (r->finfo.st_mode == 0) return NOT_FOUND; if (S_ISDIR(r->finfo.st_mode)) return FORBIDDEN; if (!(isapi_handle = ap_os_dso_load(r->filename))) { ap_log_rerror(APLOG_MARK, APLOG_ALERT, r, "ISAPI Could not load DLL: %s", r->filename); return SERVER_ERROR; } if (!(isapi_version = (void *)(ap_os_dso_sym(isapi_handle, "GetExtensionVersion")))) { ap_log_rerror(APLOG_MARK, APLOG_ALERT, r, "DLL could not load GetExtensionVersion(): %s", r->filename); ap_os_dso_unload(isapi_handle); return SERVER_ERROR; } if (!(isapi_entry = (void *)(ap_os_dso_sym(isapi_handle, "HttpExtensionProc")))) { ap_log_rerror(APLOG_MARK, APLOG_ALERT, r, "DLL could not load HttpExtensionProc(): %s", r->filename); ap_os_dso_unload(isapi_handle); return SERVER_ERROR; } isapi_term = (void *)(ap_os_dso_sym(isapi_handle, "TerminateExtension")); /* Run GetExtensionVersion() */ if (!(*isapi_version)(pVer)) { ap_log_rerror(APLOG_MARK, APLOG_ALERT, r, "ISAPI GetExtensionVersion() failed: %s", r->filename); ap_os_dso_unload(isapi_handle); return SERVER_ERROR; } /* Set up variables. There are a couple of special cases for ISAPI. * XXX: These were taken verbatim from GetServerVariable, and should * be reviewed carefully. */ ap_add_common_vars(r); ap_add_cgi_vars(r); ap_table_setn(r->subprocess_env, "UNMAPPED_REMOTE_USER", "REMOTE_USER"); ap_table_setn(r->subprocess_env, "SERVER_PORT_SECURE", "0"); ap_table_setn(r->subprocess_env, "URL", r->uri); /* Set up connection ID */ ecb->ConnID = (HCONN)cid; cid->ecb = ecb; cid->r = r; cid->status = 0; ecb->cbSize = sizeof(struct _EXTENSION_CONTROL_BLOCK); ecb->dwVersion = MAKELONG(0, 2); ecb->dwHttpStatusCode = 0; strcpy(ecb->lpszLogData, ""); ecb->lpszMethod = ap_pstrdup(r->pool, r->method); ecb->lpszQueryString = ap_pstrdup(r->pool, ap_table_get(e, "QUERY_STRING")); ecb->lpszPathInfo = ap_pstrdup(r->pool, ap_table_get(e, "PATH_INFO")); ecb->lpszPathTranslated = ap_pstrdup(r->pool, ap_table_get(e, "PATH_TRANSLATED")); ecb->lpszContentType = ap_pstrdup(r->pool, ap_table_get(e, "CONTENT_TYPE")); /* Set up client input */ if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) { if (isapi_term) (*isapi_term)( 2 /* HSE_TERM_MUST_UNLOAD */); ap_os_dso_unload(isapi_handle); return retval; } if (ap_should_client_block(r)) { /* Time to start reading the appropriate amount of data, * and allow the administrator to tweak the number * TODO: add the httpd.conf option for ReadAheadBuffer. */ if (r->remaining) { ecb->cbTotalBytes = r->remaining; if (ecb->cbTotalBytes > ReadAheadBuffer) ecb->cbAvailable = ReadAheadBuffer; else ecb->cbAvailable = ecb->cbTotalBytes; } else { ecb->cbTotalBytes = 0xffffffff; ecb->cbAvailable = ReadAheadBuffer; } ecb->lpbData = ap_pcalloc(r->pool, ecb->cbAvailable + 1); p = ecb->lpbData; read = 0; while (read < ecb->cbAvailable && ((res = ap_get_client_block(r, ecb->lpbData + read, ecb->cbAvailable - read)) > 0)) { read += res; } if (res < 0) { if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD); ap_os_dso_unload(isapi_handle); return SERVER_ERROR; } /* Although its not to spec, IIS seems to null-terminate * its lpdData string. So we will too. * * XXX: This must be an issue... backing out the null * from the count of bytes. */ if (res == 0) ecb->cbAvailable = ecb->cbTotalBytes = read; else ecb->cbAvailable = read; ecb->lpbData[read] = '\0'; } else { ecb->cbTotalBytes = 0; ecb->cbAvailable = 0; ecb->lpbData = NULL; } /* Set up the callbacks */ ecb->GetServerVariable = &GetServerVariable; ecb->WriteClient = &WriteClient; ecb->ReadClient = &ReadClient; ecb->ServerSupportFunction = &ServerSupportFunction; /* All right... try and load the sucker */ retval = (*isapi_entry)(ecb); /* Set the status (for logging) */ if (ecb->dwHttpStatusCode) r->status = ecb->dwHttpStatusCode; /* Check for a log message - and log it */ if (ecb->lpszLogData && strcmp(ecb->lpszLogData, "")) ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, "ISAPI: %s: %s", ecb->lpszLogData, r->filename); /* Soak up any remaining input */ if (r->remaining > 0) { char argsbuffer[HUGE_STRING_LEN]; while (ap_get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0); } /* All done with the DLL... get rid of it */ if (isapi_term) (*isapi_term)(HSE_TERM_MUST_UNLOAD); ap_os_dso_unload(isapi_handle); switch(retval) { case 0: /* Strange, but MS isapi accepts this as success */ case HSE_STATUS_SUCCESS: case HSE_STATUS_SUCCESS_AND_KEEP_CONN: /* Ignore the keepalive stuff; Apache handles it just fine without * the ISA's "advice". */ if (cid->status) /* We have a special status to return */ return cid->status; return OK; case HSE_STATUS_PENDING: /* We don't support this */ if (LogNotSupported) ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, r, "ISAPI asynchronous I/O not supported: %s", r->filename); case HSE_STATUS_ERROR: default: return SERVER_ERROR; } }
static int aikido_handler(request_rec *r) { apr_bucket_brigade *bb; apr_bucket *b; int seen_eos, child_stopped_reading; apr_pool_t *p; apr_status_t rv; conn_rec *c = r->connection; void *aikidoreq; int inpipes[2]; int outpipes[2]; apr_file_t *infile; apr_file_t *outfile; int e; pthread_t tid; pthread_attr_t attrs; ThreadData tdata; void *tresult; if (aikido == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "mod_aikido failed to initalize"); return HTTP_INTERNAL_SERVER_ERROR; } p = r->main ? r->main->pool : r->pool; if (r->method_number == M_OPTIONS) { r->allowed |= (AP_METHOD_BIT << M_GET); r->allowed |= (AP_METHOD_BIT << M_POST); return DECLINED; } // create the request object aikidoreq = aikido_new_request (r); if (!aikido_check_uri(aikido, aikidoreq)) { aikido_delete_request (aikidoreq); return DECLINED; } e = socketpair (AF_UNIX, SOCK_STREAM, 0, inpipes); e |= socketpair (AF_UNIX, SOCK_STREAM, 0, outpipes); if (e != 0) { perror ("socketpair"); aikido_delete_request (aikidoreq); ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Failed to create pipes"); return HTTP_INTERNAL_SERVER_ERROR; } // redirect the output from the webapp to our outfile apr_os_file_put (&outfile, &outpipes[0], O_RDONLY, r->pool); // open for reading from outpipes pipe // redirect the input to the webapp from out infile apr_os_file_put (&infile, &inpipes[1], O_CREAT | O_WRONLY, r->pool); // open for writing to inpipes pipe ap_add_common_vars(r); ap_add_cgi_vars(r); bb = apr_brigade_create(r->pool, c->bucket_alloc); seen_eos = 0; child_stopped_reading = 0; do { apr_bucket *bucket; rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN); if (rv != APR_SUCCESS) { close (inpipes[0]); close (inpipes[1]); close (outpipes[0]); close (outpipes[1]); aikido_delete_request (aikidoreq); return rv; } bucket = APR_BRIGADE_FIRST(bb); while (bucket != APR_BRIGADE_SENTINEL(bb)) { const char *data; apr_size_t len; if (APR_BUCKET_IS_EOS(bucket)) { seen_eos = 1; break; } /* We can't do much with this. */ if (APR_BUCKET_IS_FLUSH(bucket)) { continue; } /* If the child stopped, we still must read to EOS. */ if (child_stopped_reading) { continue; } /* read */ apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ); /* Keep writing data to the child until done or too much time * elapses with no progress or an error occurs. */ rv = apr_file_write_full(infile, data, len, NULL); if (rv != APR_SUCCESS) { /* silly script stopped reading, soak up remaining message */ child_stopped_reading = 1; } bucket = APR_BUCKET_NEXT(bucket); } apr_brigade_cleanup(bb); } while (!seen_eos); /* Is this flush really needed? */ apr_file_flush(infile); apr_file_close(infile); apr_brigade_cleanup(bb); /* start the reader thread */ e = pthread_attr_init (&attrs); if (e != 0) { close (inpipes[0]); close (inpipes[1]); close (outpipes[0]); close (outpipes[1]); aikido_delete_request (aikidoreq); ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Failed to allocate script thread attributes"); return HTTP_INTERNAL_SERVER_ERROR; } e = pthread_attr_setdetachstate (&attrs, PTHREAD_CREATE_JOINABLE) ; if (e != 0) { close (inpipes[0]); close (inpipes[1]); close (outpipes[0]); close (outpipes[1]); aikido_delete_request (aikidoreq); ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Failed to set script thread attributes"); return HTTP_INTERNAL_SERVER_ERROR; } tdata.req = aikidoreq; tdata.in = inpipes[0]; tdata.out = outpipes[1]; e = pthread_create (&tid, NULL, script_thread, &tdata) ; if (e != 0) { close (inpipes[0]); close (inpipes[1]); close (outpipes[0]); close (outpipes[1]); aikido_delete_request (aikidoreq); ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Failed to run script thread"); return HTTP_INTERNAL_SERVER_ERROR; } /* script thread is now executing script with i/o redirected to the pipes */ /* read the script output from the pipe*/ apr_file_pipe_timeout_set(outfile, 0); b = aikido_bucket_create(r, outfile, c->bucket_alloc); if (b == NULL) { pthread_join (tid, &tresult); /* wait for script to complete */ close (inpipes[0]); close (inpipes[1]); close (outpipes[0]); close (outpipes[1]); aikido_delete_request (aikidoreq); return HTTP_INTERNAL_SERVER_ERROR; } APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); ap_pass_brigade(r->output_filters, bb); /* wait for the script thread to complete */ pthread_join (tid, &tresult); /* terminate script output */ close (inpipes[0]); close (inpipes[1]); close (outpipes[0]); close (outpipes[1]); /* delete the aikido request objects */ aikido_delete_request (aikidoreq); return OK; }
static int suphp_handler(request_rec *r) { suphp_conf *sconf; suphp_conf *dconf; #ifdef SUPHP_USE_USERGROUP char *ud_user = NULL; char *ud_group = NULL; int ud_success = 0; #endif struct stat finfo; int rv; char *auth_user = NULL; char *auth_pass = NULL; pool *p; BUFF *script_in, *script_out, *script_err; const char *handler; sconf = ap_get_module_config(r->server->module_config, &suphp_module); dconf = ap_get_module_config(r->per_dir_config, &suphp_module); p = r->main ? r->main->pool : r->pool; /* only handle request if mod_suphp is active for this handler */ /* check only first byte of value (second has to be \0) */ if (r->handler != NULL) { handler = r->handler; } else { handler = r->content_type; } if ((ap_table_get(dconf->handlers, handler) == NULL)) { if ((ap_table_get(sconf->handlers, handler) == NULL) || (*(ap_table_get(sconf->handlers, handler)) == '0')) { return DECLINED; } } else if (*(ap_table_get(dconf->handlers, handler)) == '0') { return DECLINED; } /* check if suPHP is enabled for this request */ if (((sconf->engine != SUPHP_ENGINE_ON) && (dconf->engine != SUPHP_ENGINE_ON)) || ((sconf->engine == SUPHP_ENGINE_ON) && (dconf->engine == SUPHP_ENGINE_OFF))) return DECLINED; /* check if file is existing and accessible */ rv = stat(ap_pstrdup(p, r->filename), &finfo); if (rv == 0) { ; /* do nothing */ } else if (errno == EACCES) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "access to %s denied", r->filename); return HTTP_FORBIDDEN; } else if (errno == ENOENT || errno == ENOTDIR) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "File does not exist: %s", r->filename); return HTTP_NOT_FOUND; } else { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "could not get fileinfo: %s", r->filename); return HTTP_NOT_FOUND; } #ifdef SUPHP_USE_USERGROUP if ((sconf->target_user == NULL || sconf->target_group == NULL) && (dconf->target_user == NULL || dconf->target_group == NULL)) { /* Identify mod_userdir request As Apache 1.3 does not yet provide a clean way to see whether a request was handled by mod_userdir, we assume this is true for any request beginning with ~ */ int ud_success = 0; /* set to 1 on success */ if (!strncmp("/~", r->uri, 2)) { char *username = ap_pstrdup(r->pool, r->uri + 2); char *pos = strchr(username, '/'); if (pos) { *pos = 0; if (strlen(username)) { struct passwd *pw; struct group *gr; gid_t gid; char *grpname; if ((pw = getpwnam(username)) != NULL) { gid = pw->pw_gid; if ((gr = getgrgid(gid)) != NULL) { grpname = gr->gr_name; } else { if ((grpname = ap_palloc(r->pool, 16)) == NULL) { return HTTP_INTERNAL_SERVER_ERROR; } ap_snprintf(grpname, 16, "#%ld", (long) gid); } ud_user = username; ud_group = grpname; ud_success = 1; } } } } if (!ud_success) { /* This is not a userdir request and user/group are not set, so log the error and return */ ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "No user or group set - set suPHP_UserGroup"); return HTTP_INTERNAL_SERVER_ERROR; } } #endif /* SUPHP_USE_USERGROUP */ /* prepare environment for new process */ ap_add_common_vars(r); ap_add_cgi_vars(r); ap_table_unset(r->subprocess_env, "SUPHP_PHP_CONFIG"); ap_table_unset(r->subprocess_env, "SUPHP_AUTH_USER"); ap_table_unset(r->subprocess_env, "SUPHP_AUTH_PW"); #ifdef SUPHP_USE_USERGROUP ap_table_unset(r->subprocess_env, "SUPHP_USER"); ap_table_unset(r->subprocess_env, "SUPHP_GROUP"); ap_table_unset(r->subprocess_env, "SUPHP_USERDIR_USER"); ap_table_unset(r->subprocess_env, "SUPHP_USERDIR_GROUP"); #endif /* SUPHP_USE_USERGROUP */ if (dconf->php_config) { ap_table_set(r->subprocess_env, "SUPHP_PHP_CONFIG", dconf->php_config); } ap_table_set(r->subprocess_env, "SUPHP_HANDLER", handler); if (r->headers_in) { const char *auth; auth = ap_table_get(r->headers_in, "Authorization"); if (auth && auth[0] != 0 && strncmp(auth, "Basic ", 6) == 0) { char *user; char *pass; user = ap_pbase64decode(p, auth + 6); if (user) { pass = strchr(user, ':'); if (pass) { *pass++ = '\0'; auth_user = ap_pstrdup(p, user); auth_pass = ap_pstrdup(p, pass); } } } } if (auth_user && auth_pass) { ap_table_setn(r->subprocess_env, "SUPHP_AUTH_USER", auth_user); ap_table_setn(r->subprocess_env, "SUPHP_AUTH_PW", auth_pass); } #ifdef SUPHP_USE_USERGROUP if (dconf->target_user) { ap_table_set(r->subprocess_env, "SUPHP_USER", dconf->target_user); } else if (sconf->target_user) { ap_table_set(r->subprocess_env, "SUPHP_USER", sconf->target_user); } else { ap_table_set(r->subprocess_env, "SUPHP_USER", ud_user); } if (dconf->target_group) { ap_table_set(r->subprocess_env, "SUPHP_GROUP", dconf->target_group); } else if (sconf->target_group) { ap_table_set(r->subprocess_env, "SUPHP_GROUP", sconf->target_group); } else { ap_table_set(r->subprocess_env, "SUPHP_GROUP", ud_group); } if (ud_success) { ap_table_set(r->subprocess_env, "SUPHP_USERDIR_USER", ud_user); ap_table_set(r->subprocess_env, "SUPHP_USERDIR_GROUP", ud_group); } #endif /* SUPHP_USE_USERGROUP */ /* Fork child process */ if (!ap_bspawn_child(p, suphp_child, (void *) r, kill_after_timeout, &script_in, &script_out, &script_err)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "couldn't spawn child process for: %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } /* Transfer request body to script */ if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) { /* Call failed, return status */ return rv; } if (ap_should_client_block(r)) { char buffer[HUGE_STRING_LEN]; int len_read; ap_hard_timeout("reading request body", r); while ((len_read = ap_get_client_block(r, buffer, HUGE_STRING_LEN)) > 0) { ap_reset_timeout(r); if (ap_bwrite(script_in, buffer, len_read) < len_read) { /* silly script stopped reading, soak up remaining message */ while (ap_get_client_block(r, buffer, HUGE_STRING_LEN) > 0) { /* dump it */ } break; } } ap_bflush(script_in); ap_kill_timeout(r); } ap_bclose(script_in); /* Transfer output from script to client */ if (script_out) { const char *location; char hbuffer[MAX_STRING_LEN]; char buffer[HUGE_STRING_LEN]; rv = ap_scan_script_header_err_buff(r, script_out, hbuffer); if (rv == HTTP_NOT_MODIFIED) { return rv; } else if (rv) { return HTTP_INTERNAL_SERVER_ERROR; } location = ap_table_get(r->headers_out, "Location"); if (location && r->status == 200) { /* Soak up all the script output */ ap_hard_timeout("reading from script", r); while (ap_bgets(buffer, HUGE_STRING_LEN, script_out) > 0) { continue; } ap_kill_timeout(r); ap_bclose(script_out); ap_bclose(script_err); if (location[0] == '/') { /* Redirect has always GET method */ r->method = ap_pstrdup(p, "GET"); r->method_number = M_GET; /* Remove Content-Length - redirect should not read * * request body */ ap_table_unset(r->headers_in, "Content-Length"); /* Do the redirect */ ap_internal_redirect_handler(location, r); return OK; } else { /* Script did not set status 302 - so it does not want * * to send its own body. Simply set redirect status */ return REDIRECT; } } /* Output headers and body */ ap_send_http_header(r); if (!r->header_only) { ap_send_fb(script_out, r); } ap_bclose(script_out); /* Errors have already been logged by child */ ap_bclose(script_err); } return OK; }
/* ==================================================================== * Here's the real content handler. * ==================================================================== */ static int content_handler(request_rec *r) { long length; wkcfg *cfg; WFILE* env_dict = NULL; int i; char msgbuf[MAX_STRING_LEN]; int conn_attempt = 0; WFILE* whole_dict = NULL; WFILE* int_dict = NULL; const char *value; const char *key; array_header *hdr_arr; table_entry *elts; cfg = ap_get_module_config(r->per_dir_config, &webkit_module); if (cfg == NULL) { log_debug("No cfg", r); cfg = (wkcfg*)wk_create_dir_config(r->pool, "/"); } env_dict = setup_WFILE(r); whole_dict = setup_WFILE(r); int_dict = setup_WFILE(r); if (env_dict == NULL || whole_dict == NULL) { log_error("Couldn't allocate Python data structures", r->server); return HTTP_INTERNAL_SERVER_ERROR; } ap_add_common_vars(r); ap_add_cgi_vars(r); /* not included in the common_vars above */ /* Build the environment dictionary */ hdr_arr = ap_table_elts(r->subprocess_env); elts = (table_entry *)hdr_arr->elts; /* start dictionary */ w_byte(TYPE_DICT, env_dict); for (i = 0; i < hdr_arr->nelts; ++i) { if (!elts[i].key) continue; key = elts[i].key; value = ap_table_get(r->subprocess_env, elts[i].key); write_string(key, env_dict); if (value != NULL) write_string(value, env_dict); else w_byte(TYPE_NONE, env_dict); } hdr_arr = cfg->passheaders; if (hdr_arr) { char **headers = (char **)hdr_arr->elts; for (i = 0; i < hdr_arr->nelts; i++) { key = headers[i]; value = ap_table_get(r->headers_in, key); if (value && *value) { write_string(key, env_dict); write_string(value, env_dict); } } } #ifdef SECURITY_HOLE_PASS_AUTHORIZATION /* Ordinarily Apache only makes the username available to CGI scripts, keeping the password secret. It can be configured to make the complete credential details available, but only by completely rebuilding the server with SECURITY_HOLE_PASS_AUTHORIZATION set (enabling this feature is considered a security risk). By setting the same constant, you can have mod_webkit pass the authorization information to WebKit instead. (suggested by Maximillian Dornseif 2003-10-27) */ key = "Authorization"; value = ap_table_get(r->headers_in, key); if (value && *value) { write_string("X-HTTP_AUTHORIZATION", env_dict); write_string(value, env_dict); } #endif w_byte(TYPE_NULL, env_dict); /* end dictionary */ log_debug("Built env dictionary", r); /* We can start building the full dictionary now */ w_byte(TYPE_DICT, whole_dict); write_string("format", whole_dict); /* key */ write_string("CGI", whole_dict); /* value */ write_string("time", whole_dict); /* key */ w_byte(TYPE_INT, whole_dict); /* value */ /* patch from Ken Lalonde to make the time entry useful */ w_long((long)r->request_time, whole_dict); /* value */ write_string("environ", whole_dict); /* key */ /* copy env_dict into whole_dict */ insert_data(whole_dict, env_dict); /* that should be it */ /* end dictionary */ w_byte(TYPE_NULL, whole_dict); length = whole_dict->ptr - whole_dict->str; write_integer((int)length, int_dict); /* now we try to send it */ for (conn_attempt = 1; conn_attempt <= cfg->retryattempts; conn_attempt++) { int result = transact_with_app_server(r, cfg, whole_dict, int_dict, length); if (result == 0) { return OK; } else if (result == 2) { log_error("error transacting with app server -- giving up.", r->server); return HTTP_INTERNAL_SERVER_ERROR; } sprintf(msgbuf, "Couldn't connect to AppServer, attempt %i of %i", conn_attempt, cfg->retryattempts); log_error(msgbuf, r->server); sleep(cfg->retrydelay); } log_error("error transacting with app server -- giving up.", r->server); return HTTP_INTERNAL_SERVER_ERROR; }
static int cgi_handler(request_rec *r) { int nph; apr_size_t dbpos = 0; const char *argv0; const char *command; const char **argv; char *dbuf = NULL; apr_file_t *script_out = NULL, *script_in = NULL, *script_err = NULL; apr_bucket_brigade *bb; apr_bucket *b; int is_included; int seen_eos, child_stopped_reading; apr_pool_t *p; cgi_server_conf *conf; apr_status_t rv; cgi_exec_info_t e_info; conn_rec *c = r->connection; if(strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) return DECLINED; is_included = !strcmp(r->protocol, "INCLUDED"); p = r->main ? r->main->pool : r->pool; argv0 = apr_filepath_name_get(r->filename); nph = !(strncmp(argv0, "nph-", 4)); conf = ap_get_module_config(r->server->module_config, &cgi_module); if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r)) return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, "Options ExecCGI is off in this directory"); if (nph && is_included) return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, "attempt to include NPH CGI script"); if (r->finfo.filetype == 0) return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, "script not found or unable to stat"); if (r->finfo.filetype == APR_DIR) return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, "attempt to invoke directory as script"); if ((r->used_path_info == AP_REQ_REJECT_PATH_INFO) && r->path_info && *r->path_info) { /* default to accept */ return log_scripterror(r, conf, HTTP_NOT_FOUND, 0, "AcceptPathInfo off disallows user's path"); } /* if (!ap_suexec_enabled) { if (!ap_can_exec(&r->finfo)) return log_scripterror(r, conf, HTTP_FORBIDDEN, 0, "file permissions deny server execution"); } */ ap_add_common_vars(r); ap_add_cgi_vars(r); e_info.process_cgi = 1; e_info.cmd_type = APR_PROGRAM; e_info.detached = 0; e_info.in_pipe = APR_CHILD_BLOCK; e_info.out_pipe = APR_CHILD_BLOCK; e_info.err_pipe = APR_CHILD_BLOCK; e_info.prog_type = RUN_AS_CGI; e_info.bb = NULL; e_info.ctx = NULL; e_info.next = NULL; e_info.addrspace = 0; /* build the command line */ if ((rv = cgi_build_command(&command, &argv, r, p, &e_info)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "don't know how to spawn child process: %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } /* run the script in its own process */ if ((rv = run_cgi_child(&script_out, &script_in, &script_err, command, argv, r, p, &e_info)) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "couldn't spawn child process: %s", r->filename); return HTTP_INTERNAL_SERVER_ERROR; } /* Transfer any put/post args, CERN style... * Note that we already ignore SIGPIPE in the core server. */ bb = apr_brigade_create(r->pool, c->bucket_alloc); seen_eos = 0; child_stopped_reading = 0; if (conf->logname) { dbuf = apr_palloc(r->pool, conf->bufbytes + 1); dbpos = 0; } do { apr_bucket *bucket; rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, HUGE_STRING_LEN); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "Error reading request entity data"); return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); } for (bucket = APR_BRIGADE_FIRST(bb); bucket != APR_BRIGADE_SENTINEL(bb); bucket = APR_BUCKET_NEXT(bucket)) { const char *data; apr_size_t len; if (APR_BUCKET_IS_EOS(bucket)) { seen_eos = 1; break; } /* We can't do much with this. */ if (APR_BUCKET_IS_FLUSH(bucket)) { continue; } /* If the child stopped, we still must read to EOS. */ if (child_stopped_reading) { continue; } /* read */ apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ); if (conf->logname && dbpos < conf->bufbytes) { int cursize; if ((dbpos + len) > conf->bufbytes) { cursize = conf->bufbytes - dbpos; } else { cursize = len; } memcpy(dbuf + dbpos, data, cursize); dbpos += cursize; } /* Keep writing data to the child until done or too much time * elapses with no progress or an error occurs. */ rv = apr_file_write_full(script_out, data, len, NULL); if (rv != APR_SUCCESS) { /* silly script stopped reading, soak up remaining message */ child_stopped_reading = 1; } } apr_brigade_cleanup(bb); } while (!seen_eos); if (conf->logname) { dbuf[dbpos] = '\0'; } /* Is this flush really needed? */ apr_file_flush(script_out); apr_file_close(script_out); AP_DEBUG_ASSERT(script_in != NULL); apr_brigade_cleanup(bb); #if APR_FILES_AS_SOCKETS apr_file_pipe_timeout_set(script_in, 0); apr_file_pipe_timeout_set(script_err, 0); b = cgi_bucket_create(r, script_in, script_err, c->bucket_alloc); #else b = apr_bucket_pipe_create(script_in, c->bucket_alloc); #endif APR_BRIGADE_INSERT_TAIL(bb, b); b = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); /* Handle script return... */ if (!nph) { const char *location; char sbuf[MAX_STRING_LEN]; int ret; if ((ret = ap_scan_script_header_err_brigade(r, bb, sbuf))) { ret = log_script(r, conf, ret, dbuf, sbuf, bb, script_err); /* * ret could be HTTP_NOT_MODIFIED in the case that the CGI script * does not set an explicit status and ap_meets_conditions, which * is called by ap_scan_script_header_err_brigade, detects that * the conditions of the requests are met and the response is * not modified. * In this case set r->status and return OK in order to prevent * running through the error processing stack as this would * break with mod_cache, if the conditions had been set by * mod_cache itself to validate a stale entity. * BTW: We circumvent the error processing stack anyway if the * CGI script set an explicit status code (whatever it is) and * the only possible values for ret here are: * * HTTP_NOT_MODIFIED (set by ap_meets_conditions) * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the * processing of the response of the CGI script, e.g broken headers * or a crashed CGI process). */ if (ret == HTTP_NOT_MODIFIED) { r->status = ret; return OK; } return ret; } location = apr_table_get(r->headers_out, "Location"); if (location && r->status == 200) { /* For a redirect whether internal or not, discard any * remaining stdout from the script, and log any remaining * stderr output, as normal. */ discard_script_output(bb); apr_brigade_destroy(bb); apr_file_pipe_timeout_set(script_err, r->server->timeout); log_script_err(r, script_err); } if (location && location[0] == '/' && r->status == 200) { /* This redirect needs to be a GET no matter what the original * method was. */ r->method = apr_pstrdup(r->pool, "GET"); r->method_number = M_GET; /* We already read the message body (if any), so don't allow * the redirected request to think it has one. We can ignore * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. */ apr_table_unset(r->headers_in, "Content-Length"); ap_internal_redirect_handler(location, r); return OK; } else if (location && r->status == 200) { /* XX Note that if a script wants to produce its own Redirect * body, it now has to explicitly *say* "Status: 302" */ return HTTP_MOVED_TEMPORARILY; } rv = ap_pass_brigade(r->output_filters, bb); } else /* nph */ { struct ap_filter_t *cur; /* get rid of all filters up through protocol... since we * haven't parsed off the headers, there is no way they can * work */ cur = r->proto_output_filters; while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) { cur = cur->next; } r->output_filters = r->proto_output_filters = cur; rv = ap_pass_brigade(r->output_filters, bb); } /* don't soak up script output if errors occurred writing it * out... otherwise, we prolong the life of the script when the * connection drops or we stopped sending output for some other * reason */ if (rv == APR_SUCCESS && !r->connection->aborted) { apr_file_pipe_timeout_set(script_err, r->server->timeout); log_script_err(r, script_err); } apr_file_close(script_err); return OK; /* NOT r->status, even if it has changed. */ }
/* * Send SCGI header block */ static int send_headers(request_rec *r, proxy_conn_rec *conn) { char *buf, *cp, *bodylen; const char *ns_len; const apr_array_header_t *env_table; const apr_table_entry_t *env; int j; apr_size_t len, bodylen_size; apr_size_t headerlen = sizeof(CONTENT_LENGTH) + sizeof(SCGI_MAGIC) + sizeof(SCGI_PROTOCOL_VERSION); ap_add_common_vars(r); ap_add_cgi_vars(r); /* * The header blob basically takes the environment and concatenates * keys and values using 0 bytes. There are special treatments here: * - GATEWAY_INTERFACE and SCGI_MAGIC are dropped * - CONTENT_LENGTH is always set and must be sent as the very first * variable * * Additionally it's wrapped into a so-called netstring (see SCGI spec) */ env_table = apr_table_elts(r->subprocess_env); env = (apr_table_entry_t *)env_table->elts; for (j=0; j<env_table->nelts; ++j) { if ( (!strcmp(env[j].key, GATEWAY_INTERFACE)) || (!strcmp(env[j].key, CONTENT_LENGTH)) || (!strcmp(env[j].key, SCGI_MAGIC))) { continue; } headerlen += strlen(env[j].key) + strlen(env[j].val) + 2; } bodylen = apr_psprintf(r->pool, "%" APR_OFF_T_FMT, r->remaining); bodylen_size = strlen(bodylen) + 1; headerlen += bodylen_size; ns_len = apr_psprintf(r->pool, "%" APR_SIZE_T_FMT ":", headerlen); len = strlen(ns_len); headerlen += len + 1; /* 1 == , */ cp = buf = apr_palloc(r->pool, headerlen); memcpy(cp, ns_len, len); cp += len; memcpy(cp, CONTENT_LENGTH, sizeof(CONTENT_LENGTH)); cp += sizeof(CONTENT_LENGTH); memcpy(cp, bodylen, bodylen_size); cp += bodylen_size; memcpy(cp, SCGI_MAGIC, sizeof(SCGI_MAGIC)); cp += sizeof(SCGI_MAGIC); memcpy(cp, SCGI_PROTOCOL_VERSION, sizeof(SCGI_PROTOCOL_VERSION)); cp += sizeof(SCGI_PROTOCOL_VERSION); for (j=0; j<env_table->nelts; ++j) { if ( (!strcmp(env[j].key, GATEWAY_INTERFACE)) || (!strcmp(env[j].key, CONTENT_LENGTH)) || (!strcmp(env[j].key, SCGI_MAGIC))) { continue; } len = strlen(env[j].key) + 1; memcpy(cp, env[j].key, len); cp += len; len = strlen(env[j].val) + 1; memcpy(cp, env[j].val, len); cp += len; } *cp++ = ','; return sendall(conn, buf, headerlen, r); }
/* 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; }
static int lisp_handler (request_rec * r) { lisp_cfg_t * cfg = (ap_get_module_config ((r->per_dir_config), (&lisp_module))); int content_length = (-1); int keep_socket_p = 0; apr_socket_t * socket; const char * request_content_length = 0; cfg = local_lisp_cfg(cfg); if ((strcmp ((r->handler), "lisp-handler")) != 0) return (DECLINED); /* Open a connection to the Lisp process. */ ML_LOG_DEBUG (r, "open lisp connection"); CVT_ERROR ((open_lisp_socket (cfg)), "opening connection to Lisp"); (SERVER_SOCKET_SAFE_P (cfg)) = 0; socket = (SERVER_SOCKET (cfg)); /* Remove any timeout that might be left over from earlier. */ ML_LOG_DEBUG (r, "clear socket timeout"); CVT_ERROR ((apr_socket_timeout_set (socket, (-1))), "clearing read timeout"); /* Convert environment variables to headers and send them. */ ML_LOG_DEBUG (r, "write env-var headers"); ap_add_cgi_vars (r); ap_add_common_vars (r); if ((r->subprocess_env) != 0) CVT_ERROR ((copy_headers ((r->subprocess_env), map_env_var_to_lisp_header, socket)), "writing to Lisp"); /* Send this before client headers so ASSOC can be used to grab it without worrying about some joker sending a server-id header of his own. (Robert Macomber) */ ML_LOG_DEBUG (r, "write headers"); CVT_ERROR ((write_lisp_header (socket, "server-id", (cfg->server_id))), "writing to Lisp"); CVT_ERROR ((write_lisp_header (socket, "server-baseversion", AP_SERVER_BASEVERSION)), "writing to Lisp"); CVT_ERROR ((write_lisp_header (socket, "modlisp-version", VERSION_STRING)), "writing to Lisp"); CVT_ERROR ((write_lisp_header (socket, "modlisp-major-version", "2")), "writing to Lisp"); /* Send all the remaining headers. */ if ((r->headers_in) != 0) CVT_ERROR ((copy_headers ((r->headers_in), map_header_to_lisp_header, socket)), "writing to Lisp"); request_content_length = apr_table_get(r->headers_in, "Content-Length"); /* Send the end-of-headers marker. */ ML_LOG_DEBUG (r, "write end-of-headers"); CVT_ERROR ((write_lisp_line (socket, "end")), "writing to Lisp"); /* Send the request entity. */ RELAY_HTTP_ERROR (ap_setup_client_block (r, REQUEST_CHUNKED_DECHUNK)); if (ap_should_client_block (r)) { char buffer [4096]; ML_LOG_DEBUG (r, "write entity"); while (1) { long n_read = (ap_get_client_block (r, buffer, (sizeof (buffer)))); if (n_read < 0) { ML_LOG_PERROR (r, "error reading from client"); close_lisp_socket (cfg); return (HTTP_INTERNAL_SERVER_ERROR); } /* for chunked case, when nread == 0, we will write * a terminating 0.*/ { apr_status_t status = APR_SUCCESS; /* if there's no Content-Type header, the data must be chunked */ if (request_content_length == NULL) status = write_lisp_data_chunk (socket, buffer, n_read); else if (n_read != 0) status = write_lisp_data (socket, buffer, n_read); if (APR_SUCCESS != status) { while ((ap_get_client_block (r, buffer, sizeof(buffer))) > 0) ; ML_LOG_ERROR (status, r, "writing to Lisp"); close_lisp_socket (cfg); return (HTTP_INTERNAL_SERVER_ERROR); } } if( n_read == 0) break; } } /* Set up read timeout so we don't hang forever if Lisp is wedged. */ ML_LOG_DEBUG (r, "set socket timeout"); CVT_ERROR ((apr_socket_timeout_set (socket, READ_TIMEOUT)), "setting read timeout"); /* Read the headers and process them. */ ML_LOG_DEBUG (r, "read headers"); while (1) { char header_name [4096]; char header_value [MAX_STRING_LEN]; CVT_ERROR ((read_lisp_line (socket, header_name, (sizeof (header_name)))), "reading from Lisp"); if ((strcasecmp (header_name, "end")) == 0) break; CVT_ERROR ((read_lisp_line (socket, header_value, (sizeof (header_value)))), "reading from Lisp"); if ((strcasecmp (header_name, "content-type")) == 0) { char * tmp = (apr_pstrdup ((r->pool), header_value)); ap_content_type_tolower (tmp); (r->content_type) = tmp; } else if ((strcasecmp (header_name, "status")) == 0) { (r->status) = (atoi (header_value)); (r->status_line) = (apr_pstrdup ((r->pool), header_value)); } else if ((strcasecmp (header_name, "location")) == 0) apr_table_set ((r->headers_out), header_name, header_value); else if ((strcasecmp (header_name, "content-length")) == 0) { apr_table_set ((r->headers_out), header_name, header_value); content_length = (atoi (header_value)); } else if ((strcasecmp (header_name, "lisp-content-length")) == 0) { content_length = (atoi (header_value)); } else if ((strcasecmp (header_name, "last-modified")) == 0) { apr_time_t mtime = (apr_date_parse_http (header_value)); r->mtime = mtime; ap_set_last_modified (r); } else if ((strcasecmp (header_name, "keep-socket")) == 0) keep_socket_p = (atoi (header_value)); else if ((strcasecmp (header_name, "log-emerg")) == 0) ap_log_error (APLOG_MARK, APLOG_EMERG, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-alert")) == 0) ap_log_error (APLOG_MARK, APLOG_ALERT, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-crit")) == 0) ap_log_error (APLOG_MARK, APLOG_CRIT, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-error")) == 0) ap_log_error (APLOG_MARK, APLOG_ERR, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-warning")) == 0) ap_log_error (APLOG_MARK, APLOG_WARNING, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-notice")) == 0) ap_log_error (APLOG_MARK, APLOG_NOTICE, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-info")) == 0) ap_log_error (APLOG_MARK, APLOG_INFO, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log-debug")) == 0) ap_log_error (APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "log")) == 0) ap_log_error (APLOG_MARK, APLOG_ERR, APR_SUCCESS, (r->server), "%s", header_value); else if ((strcasecmp (header_name, "note")) == 0) { char * p = (strchr (header_value, ' ')); if (p != 0) { (*p++) = '\0'; apr_table_setn ((r->notes), (apr_pstrdup ((r->pool), header_value)), (apr_pstrdup ((r->pool), p))); } } else if ((strcasecmp (header_name, "set-cookie")) == 0) { apr_table_add ((r->headers_out), header_name, header_value); } else apr_table_set ((r->headers_out), header_name, header_value); } /* Copy the reply entity from Lisp to the client... */ // if (content_length > 0) { unsigned int n_read = 0; input_buffer_t * buffer; ML_LOG_DEBUG (r, "read entity"); CVT_ERROR ((get_input_buffer (socket, (&buffer))), "reading from Lisp"); while ((buffer->start) <= (buffer->end)) { apr_status_t fill_status; unsigned int n_bytes = ((buffer->end) - (buffer->start)); n_read += n_bytes; if ((content_length >= 0) && (n_read > content_length)) { n_bytes -= (n_read - content_length); n_read -= (n_read - content_length); } /* ...unless it's a HEAD request. */ if (!r->header_only && !write_client_data (r, (buffer->start), n_bytes)) { close_lisp_socket (cfg); return (HTTP_INTERNAL_SERVER_ERROR); } (buffer->start) += n_bytes; if (n_read == content_length) break; fill_status = fill_input_buffer (socket); if ((fill_status == APR_EOF) && (content_length < 0)) break; else CVT_ERROR (fill_status, "reading from Lisp"); } } if ((content_length < 0) || (!keep_socket_p)) CVT_ERROR ((close_lisp_socket (cfg)), "closing connection to Lisp"); else (SERVER_SOCKET_SAFE_P (cfg)) = 1; ML_LOG_DEBUG (r, "request finished"); 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; }
static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r, apr_pool_t *temp_pool, apr_uint16_t request_id) { const apr_array_header_t *envarr; const apr_table_entry_t *elts; struct iovec vec[2]; ap_fcgi_header header; unsigned char farray[AP_FCGI_HEADER_LEN]; char *body; apr_status_t rv; apr_size_t avail_len, len, required_len; int next_elem, starting_elem; char *proxyfilename = r->filename; fcgi_req_config_t *rconf = ap_get_module_config(r->request_config, &proxy_fcgi_module); if (rconf) { if (rconf->need_dirwalk) { ap_directory_walk(r); } } /* Strip balancer prefix */ if (r->filename && !strncmp(r->filename, "proxy:balancer://", 17)) { char *newfname = apr_pstrdup(r->pool, r->filename+17); newfname = ap_strchr(newfname, '/'); r->filename = newfname; } ap_add_common_vars(r); ap_add_cgi_vars(r); r->filename = proxyfilename; /* XXX are there any FastCGI specific env vars we need to send? */ /* XXX mod_cgi/mod_cgid use ap_create_environment here, which fills in * the TZ value specially. We could use that, but it would mean * parsing the key/value pairs back OUT of the allocated env array, * not to mention allocating a totally useless array in the first * place, which would suck. */ envarr = apr_table_elts(r->subprocess_env); elts = (const apr_table_entry_t *) envarr->elts; if (APLOGrtrace8(r)) { int i; for (i = 0; i < envarr->nelts; ++i) { ap_log_rerror(APLOG_MARK, APLOG_TRACE8, 0, r, APLOGNO(01062) "sending env var '%s' value '%s'", elts[i].key, elts[i].val); } } /* Send envvars over in as many FastCGI records as it takes, */ next_elem = 0; /* starting with the first one */ avail_len = 16 * 1024; /* our limit per record, which could have been up * to AP_FCGI_MAX_CONTENT_LEN */ while (next_elem < envarr->nelts) { starting_elem = next_elem; required_len = ap_fcgi_encoded_env_len(r->subprocess_env, avail_len, &next_elem); if (!required_len) { if (next_elem < envarr->nelts) { ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02536) "couldn't encode envvar '%s' in %" APR_SIZE_T_FMT " bytes", elts[next_elem].key, avail_len); /* skip this envvar and continue */ ++next_elem; continue; } /* only an unused element at the end of the array */ break; } body = apr_palloc(temp_pool, required_len); rv = ap_fcgi_encode_env(r, r->subprocess_env, body, required_len, &starting_elem); /* we pre-compute, so we can't run out of space */ ap_assert(rv == APR_SUCCESS); /* compute and encode must be in sync */ ap_assert(starting_elem == next_elem); ap_fcgi_fill_in_header(&header, AP_FCGI_PARAMS, request_id, (apr_uint16_t)required_len, 0); ap_fcgi_header_to_array(&header, farray); vec[0].iov_base = (void *)farray; vec[0].iov_len = sizeof(farray); vec[1].iov_base = body; vec[1].iov_len = required_len; rv = send_data(conn, vec, 2, &len); apr_pool_clear(temp_pool); if (rv) { return rv; } } /* Envvars sent, so say we're done */ ap_fcgi_fill_in_header(&header, AP_FCGI_PARAMS, request_id, 0, 0); ap_fcgi_header_to_array(&header, farray); vec[0].iov_base = (void *)farray; vec[0].iov_len = sizeof(farray); return send_data(conn, vec, 1, &len); }