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;
}
Exemple #2
0
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
}
Exemple #3
0
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);
}
Exemple #4
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;
}
Exemple #5
0
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;
}