Exemple #1
0
APR_DECLARE(apr_status_t) apr_file_pipe_create_ex(apr_file_t **in, 
                                                  apr_file_t **out, 
                                                  apr_int32_t blocking,
                                                  apr_pool_t *pool)
{
    apr_status_t status;

    if ((status = apr_file_pipe_create(in, out, pool)) != APR_SUCCESS)
        return status;

    switch (blocking) {
        case APR_FULL_BLOCK:
            break;
        case APR_READ_BLOCK:
            apr_file_pipe_timeout_set(*out, 0);
            break;
        case APR_WRITE_BLOCK:
            apr_file_pipe_timeout_set(*in, 0);
            break;
        default:
            apr_file_pipe_timeout_set(*out, 0);
            apr_file_pipe_timeout_set(*in, 0);
    }

    return APR_SUCCESS;
}
static void test_pipe_writefull(abts_case *tc, void *data)
{
    int iterations = 1000;
    int i;
    int bytes_per_iteration = 8000;
    char *buf = (char *)malloc(bytes_per_iteration);
    char responsebuf[128];
    apr_size_t nbytes;
    int bytes_processed;
    apr_proc_t proc = {0};
    apr_procattr_t *procattr;
    const char *args[2];
    apr_status_t rv;
    apr_exit_why_e why;
    
    rv = apr_procattr_create(&procattr, p);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);

    rv = apr_procattr_io_set(procattr, APR_CHILD_BLOCK, APR_CHILD_BLOCK,
                             APR_CHILD_BLOCK);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);

    rv = apr_procattr_error_check_set(procattr, 1);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);

    args[0] = "readchild" EXTENSION;
    args[1] = NULL;
    rv = apr_proc_create(&proc, "./readchild" EXTENSION, args, NULL, procattr, p);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);

    rv = apr_file_pipe_timeout_set(proc.in, apr_time_from_sec(10));
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);

    rv = apr_file_pipe_timeout_set(proc.out, apr_time_from_sec(10));
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);

    i = iterations;
    do {
        rv = apr_file_write_full(proc.in, buf, bytes_per_iteration, NULL);
        ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    } while (--i);

    free(buf);

    rv = apr_file_close(proc.in);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    
    nbytes = sizeof(responsebuf);
    rv = apr_file_read(proc.out, responsebuf, &nbytes);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    bytes_processed = (int)apr_strtoi64(responsebuf, NULL, 10);
    ABTS_INT_EQUAL(tc, iterations * bytes_per_iteration, bytes_processed);

    ABTS_ASSERT(tc, "wait for child process",
             apr_proc_wait(&proc, NULL, &why, APR_WAIT) == APR_CHILD_DONE);
    
    ABTS_ASSERT(tc, "child terminated normally", why == APR_PROC_EXIT);
}
Exemple #3
0
static apr_status_t pipe_bucket_read(apr_bucket *a, const char **str,
                                     apr_size_t *len, apr_read_type_e block)
{
    apr_file_t *p = a->data;
    char *buf;
    apr_status_t rv;
    apr_interval_time_t timeout;

    if (block == APR_NONBLOCK_READ) {
        apr_file_pipe_timeout_get(p, &timeout);
        apr_file_pipe_timeout_set(p, 0);
    }

    *str = NULL;
    *len = APR_BUCKET_BUFF_SIZE;
    buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */

    rv = apr_file_read(p, buf, len);

    if (block == APR_NONBLOCK_READ) {
        apr_file_pipe_timeout_set(p, timeout);
    }

    if (rv != APR_SUCCESS && rv != APR_EOF) {
        apr_bucket_free(buf);
        return rv;
    }
    /*
     * If there's more to read we have to keep the rest of the pipe
     * for later.  Otherwise, we'll close the pipe.
     * XXX: Note that more complicated bucket types that 
     * refer to data not in memory and must therefore have a read()
     * function similar to this one should be wary of copying this
     * code because if they have a destroy function they probably
     * want to migrate the bucket's subordinate structure from the
     * old bucket to a raw new one and adjust it as appropriate,
     * rather than destroying the old one and creating a completely
     * new bucket.
     */
    if (*len > 0) {
        apr_bucket_heap *h;
        /* Change the current bucket to refer to what we read */
        a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free);
        h = a->data;
        h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */
        *str = buf;
        APR_BUCKET_INSERT_AFTER(a, apr_bucket_pipe_create(p, a->list));
    }
    else {
        apr_bucket_free(buf);
        a = apr_bucket_immortal_make(a, "", 0);
        *str = a->data;
        if (rv == APR_EOF) {
            apr_file_close(p);
        }
    }
    return APR_SUCCESS;
}
Exemple #4
0
static void test_pipe_writefull(CuTest *tc)
{
    int iterations = 1000;
    int i;
    int bytes_per_iteration = 8000;
    char *buf = (char *)malloc(bytes_per_iteration);
    char responsebuf[128];
    apr_size_t nbytes;
    int bytes_processed;
    apr_proc_t proc = {0};
    apr_procattr_t *procattr;
    const char *args[2];
    apr_status_t rv;
    
    rv = apr_procattr_create(&procattr, p);
    CuAssertIntEquals(tc, APR_SUCCESS, rv);

    rv = apr_procattr_io_set(procattr, APR_CHILD_BLOCK, APR_CHILD_BLOCK,
                             APR_CHILD_BLOCK);
    CuAssertIntEquals(tc, APR_SUCCESS, rv);

    rv = apr_procattr_error_check_set(procattr, 1);
    CuAssertIntEquals(tc, APR_SUCCESS, rv);

    args[0] = "readchild" EXTENSION;
    args[1] = NULL;
    rv = apr_proc_create(&proc, "./readchild" EXTENSION, args, NULL, procattr, p);
    CuAssertIntEquals(tc, APR_SUCCESS, rv);

    rv = apr_file_pipe_timeout_set(proc.in, apr_time_from_sec(10));
    CuAssertIntEquals(tc, APR_SUCCESS, rv);

    rv = apr_file_pipe_timeout_set(proc.out, apr_time_from_sec(10));
    CuAssertIntEquals(tc, APR_SUCCESS, rv);

    i = iterations;
    do {
        rv = apr_file_write_full(proc.in, buf, bytes_per_iteration, NULL);
        CuAssertIntEquals(tc, APR_SUCCESS, rv);
    } while (--i);

    free(buf);

    rv = apr_file_close(proc.in);
    CuAssertIntEquals(tc, APR_SUCCESS, rv);
    
    nbytes = sizeof(responsebuf);
    rv = apr_file_read(proc.out, responsebuf, &nbytes);
    CuAssertIntEquals(tc, APR_SUCCESS, rv);
    bytes_processed = (int)apr_strtoi64(responsebuf, NULL, 10);
    CuAssertIntEquals(tc, iterations * bytes_per_iteration, bytes_processed);
}
Exemple #5
0
/* Implements ra_svn_timeout_fn_t */
static void
file_timeout_cb(void *baton, apr_interval_time_t interval)
{
  apr_file_t *f = baton;

  if (f)
    apr_file_pipe_timeout_set(f, interval);
}
Exemple #6
0
static int pipe_timeout_set(lua_State *L)
{
  lua_apr_file *pipe;
  apr_status_t status;
  apr_interval_time_t timeout;

  pipe = file_check(L, 1, 1);
  if (lua_isnumber(L, 2))
    timeout = luaL_checkinteger(L, 2);
  else
    timeout = lua_toboolean(L, 2) ? -1 : 0;
  status = apr_file_pipe_timeout_set(pipe->handle, timeout);
  return push_file_status(L, pipe, status);
}
Exemple #7
0
AP_DECLARE(apr_status_t) ap_mpm_pod_open(apr_pool_t *p, ap_pod_t **pod)
{
    apr_status_t rv;

    *pod = apr_palloc(p, sizeof(**pod));
    rv = apr_file_pipe_create(&((*pod)->pod_in), &((*pod)->pod_out), p);
    if (rv != APR_SUCCESS) {
        return rv;
    }

    apr_file_pipe_timeout_set((*pod)->pod_in, 0);
    (*pod)->p = p;

    /* close these before exec. */
    apr_file_inherit_unset((*pod)->pod_in);
    apr_file_inherit_unset((*pod)->pod_out);

    return APR_SUCCESS;
}
static void set_timeout(abts_case *tc, void *data)
{
    apr_status_t rv;
    apr_interval_time_t timeout;

    rv = apr_file_pipe_create(&readp, &writep, p);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    ABTS_PTR_NOTNULL(tc, readp);
    ABTS_PTR_NOTNULL(tc, writep);

    rv = apr_file_pipe_timeout_get(readp, &timeout);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    ABTS_ASSERT(tc, "Timeout mismatch, expected -1", timeout == -1);

    rv = apr_file_pipe_timeout_set(readp, apr_time_from_sec(1));
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);

    rv = apr_file_pipe_timeout_get(readp, &timeout);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    ABTS_ASSERT(tc, "Timeout mismatch, expected 1 second", 
                       timeout == apr_time_from_sec(1));
}
static void read_write(abts_case *tc, void *data)
{
    apr_status_t rv;
    char *buf;
    apr_size_t nbytes;
    
    nbytes = strlen("this is a test");
    buf = (char *)apr_palloc(p, nbytes + 1);

    rv = apr_file_pipe_create(&readp, &writep, p);
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
    ABTS_PTR_NOTNULL(tc, readp);
    ABTS_PTR_NOTNULL(tc, writep);

    rv = apr_file_pipe_timeout_set(readp, apr_time_from_sec(1));
    ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);

    if (!rv) {
        rv = apr_file_read(readp, buf, &nbytes);
        ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_TIMEUP(rv));
        ABTS_INT_EQUAL(tc, 0, nbytes);
    }
}
Exemple #10
0
static void read_write(CuTest *tc)
{
    apr_status_t rv;
    char *buf;
    apr_size_t nbytes;
    
    nbytes = strlen("this is a test");
    buf = (char *)apr_palloc(p, nbytes + 1);

    rv = apr_file_pipe_create(&readp, &writep, p);
    CuAssertIntEquals(tc, APR_SUCCESS, rv);
    CuAssertPtrNotNull(tc, readp);
    CuAssertPtrNotNull(tc, writep);

    rv = apr_file_pipe_timeout_set(readp, apr_time_from_sec(1));
    CuAssertIntEquals(tc, APR_SUCCESS, rv);

    rv = apr_file_read(readp, buf, &nbytes);
    if (!rv) {
      CuAssertIntEquals(tc, 1, APR_STATUS_IS_TIMEUP(rv));
      CuAssertIntEquals(tc, 0, nbytes);
    }
}
Exemple #11
0
static void set_timeout(CuTest *tc)
{
    apr_status_t rv;
    apr_file_t *readp = NULL;
    apr_file_t *writep = NULL;
    apr_interval_time_t timeout;

    rv = apr_file_pipe_create(&readp, &writep, p);
    CuAssertIntEquals(tc, APR_SUCCESS, rv);
    CuAssertPtrNotNull(tc, readp);
    CuAssertPtrNotNull(tc, writep);

    rv = apr_file_pipe_timeout_get(readp, &timeout);
    CuAssertIntEquals(tc, APR_SUCCESS, rv);
    CuAssert(tc, "Timeout mismatch, expected -1", timeout == -1);

    rv = apr_file_pipe_timeout_set(readp, apr_time_from_sec(1));
    CuAssertIntEquals(tc, APR_SUCCESS, rv);

    rv = apr_file_pipe_timeout_get(readp, &timeout);
    CuAssertIntEquals(tc, APR_SUCCESS, rv);
    CuAssert(tc, "Timeout mismatch, expected 1 second", 
		     timeout == apr_time_from_sec(1));
}
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. */
}
/* copied from mod_cgi.c and slightly modified
 * to work with fcgi_record types */
static
int fcgi_server_parse_headers(fcgi_request_t *fr, uint16_t request_id,
		char **data)
{
	request_rec *r = fr->r;
	int ret, termarg;

	if ((ret = ap_scan_script_header_err_strs(r, NULL, (const char **)data, &termarg, *data, NULL))) {
		/*
		 * 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;
	}

	const char *location = apr_table_get(r->headers_out, "Location");

#if 0
	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);
	}
#endif

	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;
	}
}
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);
}
int LLProcessLauncher::launch(void)
{
	// If there was already a process associated with this object, kill it.
	kill();
	orphan();
	
	int result = 0;
	int current_wd = -1;
	
	// create an argv vector for the child process
	const char ** fake_argv = new const char *[mLaunchArguments.size() + 2];  // 1 for the executable path, 1 for the NULL terminator

	int i = 0;
	
	// add the executable path
	fake_argv[i++] = mExecutable.c_str();
	
	// and any arguments
	for(int j=0; j < mLaunchArguments.size(); j++)
		fake_argv[i++] = mLaunchArguments[j].c_str();
	
	// terminate with a null pointer
	fake_argv[i] = NULL;
	
	if(!mWorkingDir.empty())
	{
		// save the current working directory
		current_wd = ::open(".", O_RDONLY);
	
		// and change to the one the child will be executed in
		if (::chdir(mWorkingDir.c_str()))
		{
			// chdir failed
		}
	}
		
	pid_t id;
	{
#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING
		// Set up a pipe to the child process for error reporting.
		apr_file_t* in;
		apr_file_t* out;
		LLAPRPool pool;
		pool.create();
#if(APR_VERSION_MAJOR==1 && APR_VERSION_MINOR>=3 || APR_VERSION_MAJOR>1)
		apr_status_t status = apr_file_pipe_create_ex(&in, &out, APR_FULL_BLOCK, pool());
#else
		apr_status_t status = apr_file_pipe_create(&in, &out, pool());
#endif
		assert(status == APR_SUCCESS);
		bool success = (status == APR_SUCCESS);
		if (success)
		{
			apr_interval_time_t const timeout = 10000000;	// 10 seconds.
			status = apr_file_pipe_timeout_set(in, timeout);
			assert(status == APR_SUCCESS);
			success = (status == APR_SUCCESS);
		}
#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING

		// flush all buffers before the child inherits them
		::fflush(NULL);

		id = vfork();
		if (id == 0)
		{
			// child process

#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING
			// Tell parent process we're about to call execv.
			write_pipe(out, "CALLING EXECV");
#ifdef _DEBUG
			char const* display = getenv("DISPLAY");
			std::cerr << "Calling ::execv(\"" << mExecutable << '"';
			for(int j = 0; j < i; ++j)
              std::cerr << ", \"" << fake_argv[j] << '"';
			std::cerr << ") with DISPLAY=\"" << (display ? display : "NULL") << '"' << std::endl;
#endif
#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING

			::execv(mExecutable.c_str(), (char * const *)fake_argv);

#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING
			status = APR_FROM_OS_ERROR(apr_get_os_error());
			char message[256];
			char errbuf[128];
			apr_strerror(status, errbuf, sizeof(errbuf));
			snprintf(message, sizeof(message), "Child process: execv: %s: %s", mExecutable.c_str(), errbuf);
			write_pipe(out, message);
#ifdef _DEBUG
			std::cerr << "::execv() failed." << std::endl;
#endif
#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING

			// If we reach this point, the exec failed.
			// Use _exit() instead of exit() per the vfork man page.
			_exit(0);
		}

		// parent process

#ifdef DEBUG_PIPE_CHILD_ERROR_REPORTING
		// Close unused pipe end.
		apr_file_close(out);

		if (success)
		{
			// Attempt to do error reporting.
			std::string message = read_pipe(in);
			success = (message == "CALLING EXECV");
			assert(success);
			if (success)
			{
				status = apr_file_pipe_timeout_set(in, 2000000);	// Only wait 2 seconds.
				message = read_pipe(in, true);
				if (message != "TIMEOUT" && message != "END OF FILE")
				{
					// Most likely execv failed.
					llwarns << message << llendl;
					assert(false);	// Fail in debug mode.
				}
			}
		}

		// Clean up.
		apr_file_close(in);
#endif // DEBUG_PIPE_CHILD_ERROR_REPORTING

	}

	if(current_wd >= 0)
	{
		// restore the previous working directory
		if (::fchdir(current_wd))
		{
			// chdir failed
		}
		::close(current_wd);
	}
	
	delete[] fake_argv;
	
	mProcessID = id;
	
	// At this point, the child process will have been created (since that's how vfork works -- the child borrowed our execution context until it forked)
	// If the process doesn't exist at this point, the exec failed.
	if(!isRunning())
	{
		result = -1;
	}
	
	return result;
}
Exemple #16
0
static int client(apr_pool_t *p, client_socket_mode_t socket_mode,
                  const char *host, int start_server)
{
    apr_status_t rv, tmprv;
    apr_socket_t *sock;
    char buf[120];
    apr_file_t *f = NULL;
    apr_size_t len;
    apr_size_t expected_len;
    apr_off_t current_file_offset;
    apr_hdtr_t hdtr;
    struct iovec headers[3];
    struct iovec trailers[3];
    apr_size_t bytes_read;
    apr_pollset_t *pset;
    apr_int32_t nsocks;
    int connect_tries = 1;
    int i;
    int family;
    apr_sockaddr_t *destsa;
    apr_proc_t server;
    apr_interval_time_t connect_retry_interval = apr_time_from_msec(50);

    if (start_server) {
        spawn_server(p, &server);
        connect_tries = 5; /* give it a chance to start up */
    }

    create_testfile(p, TESTFILE);

    rv = apr_file_open(&f, TESTFILE, APR_FOPEN_READ, 0, p);
    if (rv != APR_SUCCESS) {
        aprerr("apr_file_open()", rv);
    }

    if (!host) {
        host = "127.0.0.1";
    }
    family = APR_INET;
    rv = apr_sockaddr_info_get(&destsa, host, family, TESTSF_PORT, 0, p);
    if (rv != APR_SUCCESS) {
        aprerr("apr_sockaddr_info_get()", rv);
    }

    while (connect_tries--) {
        apr_setup(p, &sock, &family);
        rv = apr_socket_connect(sock, destsa);
        if (connect_tries && APR_STATUS_IS_ECONNREFUSED(rv)) {
            apr_status_t tmprv = apr_socket_close(sock);
            if (tmprv != APR_SUCCESS) {
                aprerr("apr_socket_close()", tmprv);
            }
            apr_sleep(connect_retry_interval);
            connect_retry_interval *= 2;
        }
        else {
            break;
        }
    }
    if (rv != APR_SUCCESS) {
        aprerr("apr_socket_connect()", rv);
    }

    switch(socket_mode) {
    case BLK:
        /* leave it blocking */
        break;
    case NONBLK:
        /* set it non-blocking */
        rv = apr_socket_opt_set(sock, APR_SO_NONBLOCK, 1);
        if (rv != APR_SUCCESS) {
            aprerr("apr_socket_opt_set(APR_SO_NONBLOCK)", rv);
        }
        break;
    case TIMEOUT:
        /* set a timeout */
        rv = apr_socket_timeout_set(sock, 100 * APR_USEC_PER_SEC);
        if (rv != APR_SUCCESS) {
            aprerr("apr_socket_opt_set(APR_SO_NONBLOCK)", rv);
            exit(1);
        }
        break;
    default:
        assert(1 != 1);
    }

    printf("Sending the file...\n");

    hdtr.headers = headers;
    hdtr.numheaders = 3;
    hdtr.headers[0].iov_base = HDR1;
    hdtr.headers[0].iov_len  = strlen(hdtr.headers[0].iov_base);
    hdtr.headers[1].iov_base = HDR2;
    hdtr.headers[1].iov_len  = strlen(hdtr.headers[1].iov_base);
    hdtr.headers[2].iov_base = malloc(HDR3_LEN);
    assert(hdtr.headers[2].iov_base);
    memset(hdtr.headers[2].iov_base, HDR3_CHAR, HDR3_LEN);
    hdtr.headers[2].iov_len  = HDR3_LEN;

    hdtr.trailers = trailers;
    hdtr.numtrailers = 3;
    hdtr.trailers[0].iov_base = TRL1;
    hdtr.trailers[0].iov_len  = strlen(hdtr.trailers[0].iov_base);
    hdtr.trailers[1].iov_base = TRL2;
    hdtr.trailers[1].iov_len  = strlen(hdtr.trailers[1].iov_base);
    hdtr.trailers[2].iov_base = malloc(TRL3_LEN);
    memset(hdtr.trailers[2].iov_base, TRL3_CHAR, TRL3_LEN);
    assert(hdtr.trailers[2].iov_base);
    hdtr.trailers[2].iov_len  = TRL3_LEN;

    expected_len = 
        strlen(HDR1) + strlen(HDR2) + HDR3_LEN +
        strlen(TRL1) + strlen(TRL2) + TRL3_LEN +
        FILE_LENGTH;
    
    if (socket_mode == BLK) {
        current_file_offset = 0;
        len = FILE_LENGTH;
        rv = apr_socket_sendfile(sock, f, &hdtr, &current_file_offset, &len, 0);
        if (rv != APR_SUCCESS) {
            aprerr("apr_socket_sendfile()", rv);
        }
        
        printf("apr_socket_sendfile() updated offset with %ld\n",
               (long int)current_file_offset);
        
        printf("apr_socket_sendfile() updated len with %ld\n",
               (long int)len);
        
        printf("bytes really sent: %" APR_SIZE_T_FMT "\n",
               expected_len);

        if (len != expected_len) {
            fprintf(stderr, "apr_socket_sendfile() didn't report the correct "
                    "number of bytes sent!\n");
            exit(1);
        }
    }
    else {
        /* non-blocking... wooooooo */
        apr_size_t total_bytes_sent;
        apr_pollfd_t pfd;

        pset = NULL;
        rv = apr_pollset_create(&pset, 1, p, 0);
        assert(!rv);
        pfd.p = p;
        pfd.desc_type = APR_POLL_SOCKET;
        pfd.reqevents = APR_POLLOUT;
        pfd.rtnevents = 0;
        pfd.desc.s = sock;
        pfd.client_data = NULL;

        rv = apr_pollset_add(pset, &pfd);        
        assert(!rv);

        total_bytes_sent = 0;
        current_file_offset = 0;
        len = FILE_LENGTH;
        do {
            apr_size_t tmplen;

            tmplen = len; /* bytes remaining to send from the file */
            printf("Calling apr_socket_sendfile()...\n");
            printf("Headers (%d):\n", hdtr.numheaders);
            for (i = 0; i < hdtr.numheaders; i++) {
                printf("\t%ld bytes (%c)\n",
                       (long)hdtr.headers[i].iov_len,
                       *(char *)hdtr.headers[i].iov_base);
            }
            printf("File: %ld bytes from offset %ld\n",
                   (long)tmplen, (long)current_file_offset);
            printf("Trailers (%d):\n", hdtr.numtrailers);
            for (i = 0; i < hdtr.numtrailers; i++) {
                printf("\t%ld bytes\n",
                       (long)hdtr.trailers[i].iov_len);
            }

            rv = apr_socket_sendfile(sock, f, &hdtr, &current_file_offset, &tmplen, 0);
            printf("apr_socket_sendfile()->%d, sent %ld bytes\n", rv, (long)tmplen);
            if (rv) {
                if (APR_STATUS_IS_EAGAIN(rv)) {
                    assert(tmplen == 0);
                    nsocks = 1;
                    tmprv = apr_pollset_poll(pset, -1, &nsocks, NULL);
                    assert(!tmprv);
                    assert(nsocks == 1);
                    /* continue; */
                }
            }

            total_bytes_sent += tmplen;

            /* Adjust hdtr to compensate for partially-written
             * data.
             */

            /* First, skip over any header data which might have
             * been written.
             */
            while (tmplen && hdtr.numheaders) {
                if (tmplen >= hdtr.headers[0].iov_len) {
                    tmplen -= hdtr.headers[0].iov_len;
                    --hdtr.numheaders;
                    ++hdtr.headers;
                }
                else {
                    hdtr.headers[0].iov_len -= tmplen;
                    hdtr.headers[0].iov_base = 
			(char*) hdtr.headers[0].iov_base + tmplen;
                    tmplen = 0;
                }
            }

            /* Now, skip over any file data which might have been
             * written.
             */

            if (tmplen <= len) {
                current_file_offset += tmplen;
                len -= tmplen;
                tmplen = 0;
            }
            else {
                tmplen -= len;
                len = 0;
                current_file_offset = 0;
            }

            /* Last, skip over any trailer data which might have
             * been written.
             */

            while (tmplen && hdtr.numtrailers) {
                if (tmplen >= hdtr.trailers[0].iov_len) {
                    tmplen -= hdtr.trailers[0].iov_len;
                    --hdtr.numtrailers;
                    ++hdtr.trailers;
                }
                else {
                    hdtr.trailers[0].iov_len -= tmplen;
                    hdtr.trailers[0].iov_base = 
			(char *)hdtr.trailers[0].iov_base + tmplen;
                    tmplen = 0;
                }
            }

        } while (total_bytes_sent < expected_len &&
                 (rv == APR_SUCCESS || 
                 (APR_STATUS_IS_EAGAIN(rv) && socket_mode != TIMEOUT)));
        if (total_bytes_sent != expected_len) {
            fprintf(stderr,
                    "client problem: sent %ld of %ld bytes\n",
                    (long)total_bytes_sent, (long)expected_len);
            exit(1);
        }

        if (rv) {
            fprintf(stderr,
                    "client problem: rv %d\n",
                    rv);
            exit(1);
        }
    }
    
    current_file_offset = 0;
    rv = apr_file_seek(f, APR_CUR, &current_file_offset);
    if (rv != APR_SUCCESS) {
        aprerr("apr_file_seek()", rv);
    }

    printf("After apr_socket_sendfile(), the kernel file pointer is "
           "at offset %ld.\n",
           (long int)current_file_offset);

    rv = apr_socket_shutdown(sock, APR_SHUTDOWN_WRITE);
    if (rv != APR_SUCCESS) {
        aprerr("apr_socket_shutdown()", rv);
    }

    /* in case this is the non-blocking test, set socket timeout;
     * we're just waiting for EOF */

    rv = apr_socket_timeout_set(sock, apr_time_from_sec(3));
    if (rv != APR_SUCCESS) {
        aprerr("apr_socket_timeout_set()", rv);
    }
    
    bytes_read = 1;
    rv = apr_socket_recv(sock, buf, &bytes_read);
    if (rv != APR_EOF) {
        aprerr("apr_socket_recv() (expected APR_EOF)", rv);
    }
    if (bytes_read != 0) {
        fprintf(stderr, "We expected to get 0 bytes read with APR_EOF\n"
                "but instead we read %ld bytes.\n",
                (long int)bytes_read);
        exit(1);
    }

    printf("client: apr_socket_sendfile() worked as expected!\n");

    rv = apr_file_remove(TESTFILE, p);
    if (rv != APR_SUCCESS) {
        aprerr("apr_file_remove()", rv);
    }

    if (start_server) {
        apr_exit_why_e exitwhy;
        apr_size_t nbytes;
        char responsebuf[1024];
        int exitcode;

        rv = apr_file_pipe_timeout_set(server.out, apr_time_from_sec(2));
        if (rv != APR_SUCCESS) {
            aprerr("apr_file_pipe_timeout_set()", rv);
        }
        nbytes = sizeof(responsebuf);
        rv = apr_file_read(server.out, responsebuf, &nbytes);
        if (rv != APR_SUCCESS) {
            aprerr("apr_file_read() messages from server", rv);
        }
        printf("%.*s", (int)nbytes, responsebuf);
        rv = apr_proc_wait(&server, &exitcode, &exitwhy, APR_WAIT);
        if (rv != APR_CHILD_DONE) {
            aprerr("apr_proc_wait() (expected APR_CHILD_DONE)", rv);
        }
        if (exitcode != 0) {
            fprintf(stderr, "sendfile server returned %d\n", exitcode);
            exit(1);
        }
    }

    return 0;
}
Exemple #17
0
static apr_status_t
create_process_manager(server_rec * main_server, apr_pool_t * configpool)
{
    apr_status_t rv;

    g_process_manager =
        (apr_proc_t *) apr_pcalloc(configpool, sizeof(*g_process_manager));
    rv = apr_proc_fork(g_process_manager, configpool);
    if (rv == APR_INCHILD) {
        /* I am the child */
        g_pm_pid = getpid();
        ap_log_error(APLOG_MARK, APLOG_INFO, 0, main_server,
                     "mod_fcgid: Process manager %" APR_PID_T_FMT  " started", getpid());

        if ((rv = init_signal(main_server)) != APR_SUCCESS) {
            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server,
                         "mod_fcgid: can't install signal handler, exiting now");
            exit(DAEMON_STARTUP_ERROR);
        }

        /* If running as root, switch to configured user.
         *
         * When running children via suexec, only the effective uid is
         * switched, so that the PM can return to euid 0 to kill child
         * processes.
         *
         * When running children as the configured user, the real uid
         * is switched.
         */
        if (ap_unixd_config.suexec_enabled) {
            if (getuid() != 0) {
                ap_log_error(APLOG_MARK, APLOG_EMERG, 0, main_server,
                             "mod_fcgid: current user is not root while suexec is enabled, exiting now");
                exit(DAEMON_STARTUP_ERROR);
            }
            suexec_setup_child();
        } else
            ap_unixd_setup_child();
        apr_file_pipe_timeout_set(g_pm_read_pipe,
                                  apr_time_from_sec(g_wakeup_timeout));
        apr_file_close(g_ap_write_pipe);
        apr_file_close(g_ap_read_pipe);

        /* Initialize spawn controler */
        spawn_control_init(main_server, configpool);

        pm_main(main_server, configpool);

        ap_log_error(APLOG_MARK, APLOG_INFO, 0, main_server,
                     "mod_fcgid: Process manager %" APR_PID_T_FMT " stopped", getpid());
        exit(0);
    } else if (rv != APR_INPARENT) {
        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server,
                     "mod_fcgid: Create process manager error");
        exit(1);
    }

    /* I am the parent
       I will send the stop signal in procmgr_stop_procmgr() */
    apr_pool_note_subprocess(configpool, g_process_manager,
                             APR_KILL_ONLY_ONCE);
    apr_proc_other_child_register(g_process_manager, fcgid_maint,
                                  g_process_manager, NULL, configpool);

    return APR_SUCCESS;
}
Exemple #18
0
/* Implements ra_svn_timeout_fn_t */
static void
file_timeout_cb(void *baton, apr_interval_time_t interval)
{
  file_baton_t *b = baton;
  apr_file_pipe_timeout_set(b->out_file, interval);
}
Exemple #19
0
/**
 * Set the timeout value for a pipe or manipulate the blocking state.
 * @param thepipe The pipe we are setting a timeout on.
 * @param timeout The timeout value in microseconds.  Values < 0 mean wait 
 *        forever, 0 means do not wait at all.
 */
SWITCH_DECLARE(switch_status_t) switch_file_pipe_timeout_set(switch_file_t *thepipe, switch_interval_time_t timeout)
{
	return apr_file_pipe_timeout_set((apr_file_t *) thepipe, (apr_interval_time_t) timeout);
}
/**
 * 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;
}
Exemple #21
0
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 ef_unified_filter(ap_filter_t *f, apr_bucket_brigade *bb)
{
    request_rec *r = f->r;
    conn_rec *c = r->connection;
    ef_ctx_t *ctx = f->ctx;
    apr_bucket *b;
    ef_dir_t *dc;
    apr_size_t len;
    const char *data;
    apr_status_t rv;
    char buf[4096];
    apr_bucket *eos = NULL;
    apr_bucket_brigade *bb_tmp;

    dc = ctx->dc;
    bb_tmp = apr_brigade_create(r->pool, c->bucket_alloc);

    for (b = APR_BRIGADE_FIRST(bb);
         b != APR_BRIGADE_SENTINEL(bb);
         b = APR_BUCKET_NEXT(b))
    {
        if (APR_BUCKET_IS_EOS(b)) {
            eos = b;
            break;
        }

        rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
        if (rv != APR_SUCCESS) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "apr_bucket_read()");
            return rv;
        }

        /* Good cast, we just tested len isn't negative */
        if (len > 0 &&
            (rv = pass_data_to_filter(f, data, (apr_size_t)len, bb_tmp))
                != APR_SUCCESS) {
            return rv;
        }
    }

    apr_brigade_cleanup(bb);
    APR_BRIGADE_CONCAT(bb, bb_tmp);
    apr_brigade_destroy(bb_tmp);

    if (eos) {
        /* close the child's stdin to signal that no more data is coming;
         * that will cause the child to finish generating output
         */
        if ((rv = apr_file_close(ctx->proc->in)) != APR_SUCCESS) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                          "apr_file_close(child input)");
            return rv;
        }
        /* since we've seen eos and closed the child's stdin, set the proper pipe
         * timeout; we don't care if we don't return from apr_file_read() for a while...
         */
        rv = apr_file_pipe_timeout_set(ctx->proc->out,
                                       r->server->timeout);
        if (rv) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                          "apr_file_pipe_timeout_set(child output)");
            return rv;
        }
    }

    do {
        len = sizeof(buf);
        rv = apr_file_read(ctx->proc->out,
                      buf,
                      &len);
        if ((rv && !APR_STATUS_IS_EOF(rv) && !APR_STATUS_IS_EAGAIN(rv)) ||
            dc->debug >= DBGLVL_GORY) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,
                          "apr_file_read(child output), len %" APR_SIZE_T_FMT,
                          !rv ? len : -1);
        }
        if (APR_STATUS_IS_EAGAIN(rv)) {
            if (eos) {
                /* should not occur, because we have an APR timeout in place */
                AP_DEBUG_ASSERT(1 != 1);
            }
            return APR_SUCCESS;
        }

        if (rv == APR_SUCCESS) {
            b = apr_bucket_heap_create(buf, len, NULL, c->bucket_alloc);
            APR_BRIGADE_INSERT_TAIL(bb, b);
        }
    } while (rv == APR_SUCCESS);

    if (!APR_STATUS_IS_EOF(rv)) {
        return rv;
    }

    if (eos) {
        b = apr_bucket_eos_create(c->bucket_alloc);
        APR_BRIGADE_INSERT_TAIL(bb, b);
        ctx->hit_eos = 1;
    }

    return APR_SUCCESS;
}
Exemple #23
0
static guint
svn_cat_command_run (AnjutaCommand *command)
{
	SvnCatCommand *self;
	SvnCommand *svn_command;
	svn_opt_revision_t revision;
	svn_opt_revision_t peg_revision;
	svn_stream_t *cat_stream;
	apr_file_t *cat_input;
	apr_file_t *cat_output;
	apr_size_t read_size;
	gchar *line;
	svn_error_t *error;
	apr_status_t apr_error;
	
	self = SVN_CAT_COMMAND (command);
	svn_command = SVN_COMMAND (command);
	
	apr_file_pipe_create (&cat_output, &cat_input, 
						  svn_command_get_pool (svn_command));
	apr_file_pipe_timeout_set (cat_output, 0);
	apr_file_pipe_timeout_set (cat_input, 0);
	cat_stream = svn_stream_from_aprfile2 (cat_input, FALSE, 
										   svn_command_get_pool (svn_command));
	
	revision.kind = svn_opt_revision_number;
	revision.value.number = self->priv->revision;
	peg_revision.kind = svn_opt_revision_unspecified;
	
	error = svn_client_cat2 (cat_stream,
							 self->priv->path,
							 &peg_revision,
							 &revision,
							 svn_command_get_client_context (svn_command),
							 svn_command_get_pool (svn_command));
	
	if (error)
	{
		svn_command_set_error (svn_command, error);
		return 1;
	}
	
	while (apr_file_eof (cat_output) != APR_EOF)
	{
		read_size = 80;
		line = g_new0 (gchar, (read_size + 1));
		
		apr_error = apr_file_read (cat_output, line, &read_size);
		
		if (apr_error)
			break;
		
		if (strlen (line))
		{
			anjuta_async_command_lock (ANJUTA_ASYNC_COMMAND (command));
			g_queue_push_tail (self->priv->output, g_strdup (line));
			anjuta_async_command_unlock (ANJUTA_ASYNC_COMMAND (command));
			
			g_free (line);
			
			anjuta_command_notify_data_arrived (command);
		}
	}
								 
	return 0;
}
Exemple #24
0
static apr_status_t ef_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
{
    request_rec *r = f->r;
    conn_rec *c = r->connection;
    ef_ctx_t *ctx = f->ctx;
    apr_bucket *b;
    ef_dir_t *dc;
    apr_size_t len;
    const char *data;
    apr_status_t rv;
    char buf[4096];
    apr_bucket *eos = NULL;

    if (!ctx) {
        if ((rv = init_filter_instance(f)) != APR_SUCCESS) {
            return rv;
        }
        ctx = f->ctx;
    }
    if (ctx->noop) {
        ap_remove_output_filter(f);
        return ap_pass_brigade(f->next, bb);
    }
    dc = ctx->dc;

    APR_BRIGADE_FOREACH(b, bb) {

        if (APR_BUCKET_IS_EOS(b)) {
            eos = b;
            break;
        }

        rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ);
        if (rv != APR_SUCCESS) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "apr_bucket_read()");
            return rv;
        }

        /* Good cast, we just tested len isn't negative */
        if (len > 0 &&
                (rv = pass_data_to_filter(f, data, (apr_size_t)len))
                != APR_SUCCESS) {
            return rv;
        }
    }

    apr_brigade_destroy(bb);

    /* XXX What we *really* need to do once we've hit eos is create a pipe bucket
     * from the child output pipe and pass down the pipe bucket + eos.
     */
    if (eos) {
        /* close the child's stdin to signal that no more data is coming;
         * that will cause the child to finish generating output
         */
        if ((rv = apr_file_close(ctx->proc->in)) != APR_SUCCESS) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                          "apr_file_close(child input)");
            return rv;
        }
        /* since we've seen eos and closed the child's stdin, set the proper pipe
         * timeout; we don't care if we don't return from apr_file_read() for a while...
         */
        rv = apr_file_pipe_timeout_set(ctx->proc->out,
                                       r->server->timeout);
        if (rv) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                          "apr_file_pipe_timeout_set(child output)");
            return rv;
        }
    }

    do {
        len = sizeof(buf);
        rv = apr_file_read(ctx->proc->out,
                           buf,
                           &len);
        if ((rv && !APR_STATUS_IS_EOF(rv) && !APR_STATUS_IS_EAGAIN(rv)) ||
                dc->debug >= DBGLVL_GORY) {
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r,
                          "apr_file_read(child output), len %" APR_SIZE_T_FMT,
                          !rv ? len : -1);
        }
        if (APR_STATUS_IS_EAGAIN(rv)) {
            if (eos) {
                /* should not occur, because we have an APR timeout in place */
                AP_DEBUG_ASSERT(1 != 1);
            }
            return APR_SUCCESS;
        }

        if (rv == APR_SUCCESS) {
            bb = apr_brigade_create(r->pool, c->bucket_alloc);
            b = apr_bucket_transient_create(buf, len, c->bucket_alloc);
            APR_BRIGADE_INSERT_TAIL(bb, b);
            if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                              "ap_pass_brigade(filtered buffer) failed");
                return rv;
            }
        }
    } while (rv == APR_SUCCESS);

    if (!APR_STATUS_IS_EOF(rv)) {
        return rv;
    }

    if (eos) {
        /* pass down eos */
        bb = apr_brigade_create(r->pool, c->bucket_alloc);
        b = apr_bucket_eos_create(c->bucket_alloc);
        APR_BRIGADE_INSERT_TAIL(bb, b);
        if ((rv = ap_pass_brigade(f->next, bb)) != APR_SUCCESS) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                          "ap_pass_brigade(eos) failed");
            return rv;
        }
    }

    return APR_SUCCESS;
}