Beispiel #1
0
static int proc_detach_set(lua_State *L)
{
  apr_status_t status;
  apr_int32_t detach;
  lua_apr_proc *process;

  process = proc_check(L, 1);
  detach = lua_toboolean(L, 2);
  status = apr_procattr_detach_set(process->attr, detach);

  return push_status(L, status);
}
Beispiel #2
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;
}
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);
}
/* Run an external authentication program using the given method for passing
 * in the data.  The login name is always passed in.   Dataname is "GROUP" or
 * "PASS" and data is the group list or password being checked.  To launch
 * a detached daemon, run this with extmethod=NULL.
 *
 * If the authenticator was run, we return the numeric code from the
 * authenticator, normally 0 if the login was valid, some small positive
 * number if not.  If we were not able to run the authenticator, we log
 * an error message and return a numeric error code:
 *
 *   -1   Could not execute authenticator, usually a path or permission problem
 *   -2   The external authenticator crashed or was killed.
 *   -3   Could not create process attribute structure
 *   -4   apr_proc_wait() did not return a status code.  Should never happen.
 *   -5   apr_proc_wait() returned before child finished.  Should never happen.
 */
static int exec_external(const char *extpath, const char *extmethod,
		const request_rec *r, const char *dataname, const char *data)
{
    conn_rec *c= r->connection;
    apr_pool_t *p= r->pool;
    int isdaemon, usecheck= 0, usepipeout= 0, usepipein= 0;
    apr_procattr_t *procattr;
    apr_proc_t proc;
    apr_status_t rc= APR_SUCCESS;
    char *child_env[12];
    char *child_arg[MAX_ARG+2];
    const char *t;
    int i, status= -4;
    apr_exit_why_e why= APR_PROC_EXIT;
    apr_sigfunc_t *sigchld;

    /* Set various flags based on the execution method */

    isdaemon= (extmethod == NULL);
    if (!isdaemon)
    {
	usecheck= extmethod && !strcasecmp(extmethod, "checkpassword");
	usepipeout= usecheck || (extmethod && !strcasecmp(extmethod, "pipes"));
	usepipein= usepipeout || (extmethod && !strcasecmp(extmethod, "pipe"));
    }

    /* Create the environment for the child.  Daemons don't get these, they
     * just inherit apache's environment variables.
     */

    if (!isdaemon)
    {
	const char *cookie, *host, *remote_host;
	authnz_external_dir_config_rec *dir= (authnz_external_dir_config_rec *)
	    ap_get_module_config(r->per_dir_config, &authnz_external_module);
	i= 0;

	if (!usepipein)
	{
	    /* Put user name and password/group into environment */
	    child_env[i++]= apr_pstrcat(p, ENV_USER"=", r->user, NULL);
	    child_env[i++]= apr_pstrcat(p, dataname, "=", data, NULL);
	}

	child_env[i++]= apr_pstrcat(p, "PATH=", getenv("PATH"), NULL);

	child_env[i++]= apr_pstrcat(p, "AUTHTYPE=", dataname, NULL);

	remote_host= ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST,NULL);
	if (remote_host != NULL)
	    child_env[i++]= apr_pstrcat(p, ENV_HOST"=", remote_host,NULL);

	if (r->useragent_ip)
	    child_env[i++]= apr_pstrcat(p, ENV_IP"=", r->useragent_ip, NULL);

	if (r->uri)
	    child_env[i++]= apr_pstrcat(p, ENV_URI"=", r->uri, NULL);

	if ((host= apr_table_get(r->headers_in, "Host")) != NULL)
	    child_env[i++]= apr_pstrcat(p, ENV_HTTP_HOST"=", host, NULL);

	if (dir->context)
	    child_env[i++]= apr_pstrcat(r->pool, ENV_CONTEXT"=",
	    	dir->context, NULL);

#ifdef ENV_COOKIE
	if ((cookie= apr_table_get(r->headers_in, "Cookie")) != NULL)
	    child_env[i++]= apr_pstrcat(p, ENV_COOKIE"=", cookie, NULL);
#endif
	/* NOTE:  If you add environment variables,
	 *   remember to increase the size of the child_env[] array */

	/* End of environment */
	child_env[i]= NULL;
    }

    /* Construct argument array */
    for (t= extpath, i=0; *t != '\0' && (i <= MAX_ARG + 1);
	 child_arg[i++]= ap_getword_white(p, &t)) {}
    child_arg[i]= NULL;

    /* Create the process attribute structure describing the script we
     * want to run using the Thread/Process functions from the Apache
     * portable runtime library. */

    if (((rc= apr_procattr_create(&procattr, p)) != APR_SUCCESS) ||

	/* should we create pipes to stdin, stdout and stderr? */
        ((rc= apr_procattr_io_set(procattr,
	    (usepipein && !usecheck) ? APR_FULL_BLOCK : APR_NO_PIPE,
	    usepipeout ? APR_FULL_BLOCK : APR_NO_PIPE,
	    (usepipein && usecheck) ? APR_FULL_BLOCK : APR_NO_PIPE))
	       != APR_SUCCESS ) ||

	/* will give full path of program and make a new environment */
	((rc= apr_procattr_cmdtype_set(procattr,
	    isdaemon ? APR_PROGRAM_ENV : APR_PROGRAM)) != APR_SUCCESS) ||

	/* detach the child only if it is a daemon */
	((rc= apr_procattr_detach_set(procattr, isdaemon)) != APR_SUCCESS) ||

	/* function to call if child has error after fork, before exec */
	((rc= apr_procattr_child_errfn_set(procattr, extchilderr)
	      != APR_SUCCESS)))
    {
	/* Failed.  Probably never happens. */
    	ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
	    "could not set child process attributes");
	return -3;
    }

    /* Sometimes other modules wil mess up sigchild.  Need to fix it for
     * the wait call to work correctly.  */
    sigchld= apr_signal(SIGCHLD,SIG_DFL);

    /* Start the child process */
    rc= apr_proc_create(&proc, child_arg[0],
    	(const char * const *)child_arg,
	(const char * const *)child_env, procattr, p);
    if (rc != APR_SUCCESS)
    {
	ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
		"Could not run external authenticator: %d: %s", rc,
		child_arg[0]);
	return -1;
    }

    if (isdaemon) return 0;

    apr_pool_note_subprocess(p, &proc, APR_KILL_AFTER_TIMEOUT);

    if (usepipein)
    {
	/* Select appropriate pipe to write to */
	apr_file_t *pipe= (usecheck ? proc.err : proc.in);

	/* Send the user */
	apr_file_write_full(pipe, r->user, strlen(r->user), NULL);
	apr_file_putc(usecheck ? '\0' : '\n', pipe);

	/* Send the password */
	apr_file_write_full(pipe, data, strlen(data), NULL);
	apr_file_putc(usecheck ? '\0' : '\n', pipe);

	/* Send the uri/path */
	apr_file_write_full(pipe, r->uri, strlen(r->uri), NULL);
	apr_file_putc(usecheck ? '\0' : '\n', pipe);

	/* Send dummy timestamp for checkpassword */
	if (usecheck) apr_file_write_full(pipe, "0", 2, NULL);

	/* Close the file */
	apr_file_close(pipe);
    }

    /* Wait for the child process to terminate, and get status */
    rc= apr_proc_wait(&proc,&status,&why,APR_WAIT);

    /* Restore sigchild to whatever it was before we reset it */
    apr_signal(SIGCHLD,sigchld);

    if (!APR_STATUS_IS_CHILD_DONE(rc))
    {
    	ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
		"Could not get status from child process");
	return -5;
    }
    if (!APR_PROC_CHECK_EXIT(why))
    {
	ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
		"External authenticator died on signal %d",status);
	return -2;
    }

    return status;
}
Beispiel #5
0
LIB_INTERNAL void run_bg_cmd(LOGMANAGER *mp, const char *cmd
	, const char *file_path, TIMESTAMP t)
{
char buf[32];
DECLARE_TPOOL;
apr_procattr_t *attr;
apr_proc_t proc;
const char *args[2];
apr_status_t status;
char errbuf[1024];

NORMALIZE_TIMESTAMP(t);
if (!cmd) return; /* Security */

DEBUG1(mp,1,"Running background command : %s",cmd);

/* Set environment variables */

(void)apr_env_set("LOGMANAGER_FILE_PATH",(file_path ? file_path : "")
	,CHECK_TPOOL());
(void)apr_env_set("LOGMANAGER_BASE_PATH",mp->base_path,CHECK_TPOOL());
(void)apr_env_set("LOGMANAGER_BASE_DIR",mp->base_dir,CHECK_TPOOL());
(void)apr_env_set("LOGMANAGER_LOG_PATH",mp->log_path,CHECK_TPOOL());
(void)apr_env_set("LOGMANAGER_LOG_DIR",mp->log_dir,CHECK_TPOOL());
(void)apr_env_set("LOGMANAGER_COMPRESSION"
	,mp->compress.handler->suffix,CHECK_TPOOL());
(void)apr_env_set("LOGMANAGER_VERSION",PACKAGE_VERSION,CHECK_TPOOL());

(void)apr_snprintf(buf,sizeof(buf),"%" TIMESTAMP_FMT,t);
(void)apr_env_set("LOGMANAGER_TIME",buf,CHECK_TPOOL());

/* Run background process */

(void)apr_procattr_create(&attr,CHECK_TPOOL());

/* APR_NO_FILE is defined in APR 1.3.0 and higher */

#ifdef APR_NO_FILE
#define LMGR_IO_ATTR APR_NO_FILE
#else
#define LMGR_IO_ATTR 0
#endif

/*(void)apr_procattr_io_set(attr,LMGR_IO_ATTR,LMGR_IO_ATTR,LMGR_IO_ATTR);*/
(void)apr_procattr_cmdtype_set(attr,APR_PROGRAM_ENV);
(void)apr_procattr_detach_set(attr,1);
(void)apr_procattr_error_check_set(attr,1);
(void)apr_procattr_child_errfn_set(attr,_proc_create_error_callback);

args[0]=cmd;
args[1]=NULL;

status=apr_proc_create(&proc,cmd,args,NULL, attr,CHECK_TPOOL());
if (status != APR_SUCCESS)
	{
	_proc_create_error(mp,CHECK_TPOOL(),status
		,apr_strerror(status,errbuf,sizeof(errbuf)));
	}

/* The background process lives its own life. Don't care about it anymore */

FREE_TPOOL();
return;
}