Ejemplo n.º 1
0
void jaxer_add_env_vars(request_rec * r)
{
    /* 
     * Add additonal vars that are needed by jaxer.
     * REMOTE_USER
     * REMOTE_HOST
     * STATUS_CODE
     * HTTPS
     */
	apr_table_t *env = r->subprocess_env;
    jaxer_dir_conf *config =
		ap_get_module_config(r->per_dir_config, &jaxer_module);

    int is_ip;
    int ssl_on;
    const char * ru = ap_get_remote_logname(r);
#ifndef APACHE1_3
    const char * rh = ap_get_remote_host(r->connection, config, REMOTE_NAME, &is_ip);
#else
    const char * rh = ap_get_remote_host(r->connection, config, REMOTE_NAME);
#endif

    if (ru)
        apr_table_setn(env, "REMOTE_USER", ru);
    // else
    //    apr_table_setn(env, "REMOTE_USER", "");

    if (rh && !is_ip)
        ap_table_setn(env, "REMOTE_HOST", rh);

    ap_table_setn(env, "STATUS_CODE", ap_psprintf(r->pool, "%d", r->status));

    ssl_on = jaxer_conn_is_https(r->connection);
    ap_table_setn(env, "HTTPS", ap_psprintf(r->pool, "%s", (ssl_on != 0)? "on" : "off" ));
}
Ejemplo n.º 2
0
void ssl_scache_shmht_status(server_rec *s, pool *p, void (*func)(char *, void *), void *arg)
{
    SSLModConfigRec *mc = myModConfig();
    void *vpKey;
    void *vpData;
    int nKey;
    int nData;
    int nElem;
    int nSize;
    int nAverage;

    nElem = 0;
    nSize = 0;
    ssl_mutex_on(s);
    if (table_first(mc->tSessionCacheDataTable,
                    &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE) {
        do {
            if (vpKey == NULL || vpData == NULL)
                continue;
            nElem += 1;
            nSize += nData;
        } while (table_next(mc->tSessionCacheDataTable,
                            &vpKey, &nKey, &vpData, &nData) == TABLE_ERROR_NONE);
    }
    ssl_mutex_off(s);
    if (nSize > 0 && nElem > 0)
        nAverage = nSize / nElem;
    else
        nAverage = 0;
    func(ap_psprintf(p, "cache type: <b>SHMHT</b>, maximum size: <b>%d</b> bytes<br>", mc->nSessionCacheDataSize), arg);
    func(ap_psprintf(p, "current sessions: <b>%d</b>, current size: <b>%d</b> bytes<br>", nElem, nSize), arg);
    func(ap_psprintf(p, "average session size: <b>%d</b> bytes<br>", nAverage), arg);
    return;
}
Ejemplo n.º 3
0
const char *
fcgi_util_fs_is_path_ok(pool * const p, const char * const fs_path, struct stat *finfo)
{
    const char *err;

    if (finfo == NULL) {
        finfo = (struct stat *)ap_palloc(p, sizeof(struct stat));	        
        if (stat(fs_path, finfo) < 0)
            return ap_psprintf(p, "stat(%s) failed: %s", fs_path, strerror(errno));
    }
    
    if (finfo->st_mode == 0) 
        return ap_psprintf(p, "script not found or unable to stat()");

    if (S_ISDIR(finfo->st_mode)) 
        return ap_psprintf(p, "script is a directory!");
    
    /* Let the wrapper determine what it can and can't execute */
    if (! fcgi_wrapper)
    {
#ifdef WIN32
        err = fcgi_util_check_access(p, fs_path, finfo, _S_IEXEC, fcgi_user_id, fcgi_group_id);
#else
        err = fcgi_util_check_access(p, fs_path, finfo, X_OK, fcgi_user_id, fcgi_group_id);
#endif
        if (err) {
            return ap_psprintf(p,
                "access for server (uid %ld, gid %ld) not allowed: %s",
                (long)fcgi_user_id, (long)fcgi_group_id, err);
        }
    }
    
    return NULL;
}
Ejemplo n.º 4
0
/*******************************************************************************
 * Create a directory to hold Unix/Domain sockets.
 */
const char *fcgi_config_make_dir(pool *tp, char *path)
{
    struct stat finfo;
    const char *err = NULL;

    /* Is the directory spec'd correctly */
    if (*path != '/') {
        return "path is not absolute (it must start with a \"/\")";
    }
    else {
        int i = strlen(path) - 1;

        /* Strip trailing "/"s */
        while(i > 0 && path[i] == '/') path[i--] = '\0';
    }

    /* Does it exist? */
    if (stat(path, &finfo) != 0) {
        /* No, but maybe we can create it */
#ifdef WIN32
        if (mkdir(path) != 0) 
#else
        if (mkdir(path, S_IRWXU) != 0)
#endif
        {
            return ap_psprintf(tp,
                "doesn't exist and can't be created: %s",
                strerror(errno));
        }

#ifndef WIN32
        /* If we're root, we're gonna setuid/setgid so we need to chown */
        if (geteuid() == 0 && chown(path, ap_user_id, ap_group_id) != 0) {
            return ap_psprintf(tp,
                "can't chown() to the server (uid %ld, gid %ld): %s",
                (long)ap_user_id, (long)ap_group_id, strerror(errno));
        }
#endif
    }
    else {
        /* Yes, is it a directory? */
        if (!S_ISDIR(finfo.st_mode))
            return "isn't a directory!";

        /* Can we RWX in there? */
#ifdef WIN32
        err = fcgi_util_check_access(tp, NULL, &finfo, _S_IREAD | _S_IWRITE | _S_IEXEC, fcgi_user_id, fcgi_group_id);
#else
        err = fcgi_util_check_access(tp, NULL, &finfo, R_OK | W_OK | X_OK,
                          fcgi_user_id, fcgi_group_id);
#endif
        if (err != NULL) {
            return ap_psprintf(tp,
                "access for server (uid %ld, gid %ld) failed: %s",
                (long)fcgi_user_id, (long)fcgi_group_id, err);
        }
    }
    return NULL;
}
Ejemplo n.º 5
0
static void save_conn_info(request_rec *r)
{
    conn_rec *c = r->connection;
    local_addr =  ap_psprintf(c->pool, "%pI", &c->local_addr);
    remote_addr = ap_psprintf(c->pool, "%pI", &c->remote_addr);

    ap_register_cleanup(c->pool, NULL, clear_conn_info, ap_null_cleanup);
}
Ejemplo n.º 6
0
/**
 * gets request URL
 */
static char *get_request_url(request_rec *r)
{
    const char *args = r->args;

    if ((args != NULL) && (args[0] != '\0')) {
	am_web_log_debug("query args :%s", args);
	return ap_psprintf(r->pool, "%s://%s:%u%s?%s", ap_http_method(r),
	    r->hostname, r->server->port, r->uri, args);
    } else {
	return ap_psprintf(r->pool, "%s://%s:%u%s", ap_http_method(r),
	    r->hostname, r->server->port, r->uri);
    }
}
Ejemplo n.º 7
0
/*******************************************************************************
 * Get the next configuration directive argument, & return an u_short.
 * The pool arg should be temporary storage.
 */
static const char *get_u_short(pool *p, const char **arg,
        u_short *num, u_short min)
{
    char *ptr;
	long tmp;
    const char *txt = ap_getword_conf(p, arg);

    if (*txt == '\0') {
		return "\"\"";
	}

    tmp = strtol(txt, &ptr, 10);

    if (*ptr != '\0') {
        return ap_pstrcat(p, "\"", txt, "\" must be a positive integer", NULL);
	}
    
	if (tmp < min || tmp > USHRT_MAX) {
        return ap_psprintf(p, "\"%u\" must be >= %u and < %u", *num, min, USHRT_MAX);
	}

	*num = (u_short) tmp;

    return NULL;
}
Ejemplo n.º 8
0
static void aurora_init(server_rec *s, pool *p) {
  STRLEN len = 0;
  SV *version;
  char *serverstring;
  version = perl_get_sv("Aurora::VERSION", TRUE | GV_ADDMULTI);
  serverstring = ap_psprintf(p, "Aurora/%s", SvPV(version, len));
  ap_add_version_component(serverstring);
}
Ejemplo n.º 9
0
/*
** dav_fs_save_locknull_list:  Saves contents of pbuf into the
**    locknull file for dirpath.
*/
static dav_error * dav_fs_save_locknull_list(pool *p, const char *dirpath,
					     dav_buffer *pbuf)
{
    const char *pathname;
    int fd;
    dav_error *err = NULL;

    if (pbuf->buf == NULL)
	return NULL;

    dav_fs_ensure_state_dir(p, dirpath);
    pathname = ap_pstrcat(p,
			  dirpath,
			  dirpath[strlen(dirpath) - 1] == '/' ? "" : "/",
			  DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE,
			  NULL);

    if (pbuf->cur_len == 0) {
	/* delete the file if cur_len == 0 */
	if (remove(pathname) != 0) {
	    return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
				 ap_psprintf(p,
					     "Error removing %s", pathname));
	}
	return NULL;
    }

    if ((fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
		   DAV_FS_MODE_FILE)) == -1) {
	return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
			     ap_psprintf(p,
					 "Error opening %s for writing",
					 pathname));
    }

    if (write(fd, pbuf->buf, pbuf->cur_len) != pbuf->cur_len) {
	err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
			    ap_psprintf(p,
					"Error writing %i bytes to %s",
					pbuf->cur_len, pathname));
    }

    close(fd);
    return err;
}
Ejemplo n.º 10
0
const char *fcgi_config_new_auth_server(cmd_parms * cmd,
    void * dircfg, const char *fs_path, const char * compat)
{
    fcgi_dir_config * dir_config = (fcgi_dir_config *) dircfg;
    pool * const tp = cmd->temp_pool;
    char * auth_server;

#ifdef APACHE2
    if (apr_filepath_merge(&auth_server, "", fs_path, 0, cmd->pool))
        return ap_psprintf(tp, "%s %s: invalid filepath", cmd->cmd->name, fs_path);
#else
    auth_server = (char *) ap_os_canonical_filename(cmd->pool, fs_path);
#endif

    auth_server = ap_server_root_relative(cmd->pool, auth_server);

    /* Make sure its already configured or at least a candidate for dynamic */
    if (fcgi_util_fs_get_by_id(auth_server, fcgi_util_get_server_uid(cmd->server),
                               fcgi_util_get_server_gid(cmd->server)) == NULL) 
    {
        const char *err = fcgi_util_fs_is_path_ok(tp, auth_server, NULL);
        if (err)
            return ap_psprintf(tp, "%s: \"%s\" %s", cmd->cmd->name, auth_server, err);
    }

    if (compat && strcasecmp(compat, "-compat"))
        return ap_psprintf(cmd->temp_pool, "%s: unknown option: \"%s\"", cmd->cmd->name, compat);

    switch((long)cmd->info) {
        case FCGI_AUTH_TYPE_AUTHENTICATOR:
            dir_config->authenticator = auth_server;
            dir_config->authenticator_options |= (compat) ? FCGI_COMPAT : 0;
            break;
        case FCGI_AUTH_TYPE_AUTHORIZER:
            dir_config->authorizer = auth_server;
            dir_config->authorizer_options |= (compat) ? FCGI_COMPAT : 0;
            break;
        case FCGI_AUTH_TYPE_ACCESS_CHECKER:
            dir_config->access_checker = auth_server;
            dir_config->access_checker_options |= (compat) ? FCGI_COMPAT : 0;
            break;
    }

    return NULL;
}
Ejemplo n.º 11
0
/*
** dav_fs_load_locknull_list:  Returns a dav_buffer dump of the locknull file
**    for the given directory.
*/
static dav_error * dav_fs_load_locknull_list(pool *p, const char *dirpath,
					     dav_buffer *pbuf) 
{
    struct stat finfo;
    int fd;
    dav_error *err = NULL;

    dav_buffer_init(p, pbuf, dirpath);

    if (pbuf->buf[pbuf->cur_len - 1] == '/')
	pbuf->buf[--pbuf->cur_len] = '\0';

    dav_buffer_place(p, pbuf, "/" DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE);

    /* reset this in case we leave w/o reading into the buffer */
    pbuf->cur_len = 0;

    if ((fd = open(pbuf->buf, O_RDONLY | O_BINARY)) == -1) {
	return NULL;
    }

    if (fstat(fd, &finfo) == -1) {
	err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
			    ap_psprintf(p,
					"Opened but could not stat file %s",
					pbuf->buf));
	goto loaderror;
    }

    dav_set_bufsize(p, pbuf, finfo.st_size);
    if (read(fd, pbuf->buf, finfo.st_size) != finfo.st_size) {
	err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
			    ap_psprintf(p,
					"Failure reading locknull file "
					"for %s", dirpath));

	/* just in case the caller disregards the returned error */
	pbuf->cur_len = 0;
	goto loaderror;
    }

  loaderror:
    close(fd);
    return err;
}
Ejemplo n.º 12
0
static const char *log_bytes_sent(request_rec *r, char *a)
{
    if (!r->sent_bodyct) {
        return "0";
    }
    else {
        long int bs;
        ap_bgetopt(r->connection->client, BO_BYTECT, &bs);
	return ap_psprintf(r->pool, "%ld", bs);
    }
}
Ejemplo n.º 13
0
/*******************************************************************************
 * Configure uid, gid, user, group, username for wrapper.
 */
const char *
fcgi_util_fs_set_uid_n_gid(pool *p, fcgi_server *s, uid_t uid, gid_t gid)
{
#ifndef WIN32

    struct passwd *pw;
    struct group  *gr;

    if (fcgi_wrapper == NULL)
        return NULL;

    if (uid == 0 || gid == 0) {
        return "invalid uid or gid, see the -user and -group options";
    }

    s->uid = uid;
    pw = getpwuid(uid);
    if (pw == NULL) {
        return ap_psprintf(p,
            "getpwuid() couldn't determine the username for uid '%ld', "
            "you probably need to modify the User directive: %s",
            (long)uid, strerror(errno));
    }
    s->user = ap_pstrdup(p, pw->pw_name);
    s->username = s->user;

    s->gid = gid;
    gr = getgrgid(gid);
    if (gr == NULL) {
        return ap_psprintf(p,
            "getgrgid() couldn't determine the group name for gid '%ld', "
            "you probably need to modify the Group directive: %s",
            (long)gid, strerror(errno));
    }
    s->group = ap_pstrdup(p, gr->gr_name);

#endif /* !WIN32 */

    return NULL;
}
Ejemplo n.º 14
0
/*******************************************************************************
 * Get the next configuration directive argument, & return a float.
 * The pool arg should be temporary storage.
 */
static const char *get_float(pool *p, const char **arg,
        float *num, float min, float max)
{
    char *ptr;
    const char *val = ap_getword_conf(p, arg);

    if (*val == '\0')
        return "\"\"";
    *num = (float) strtod(val, &ptr);

    if (*ptr != '\0')
        return ap_pstrcat(p, "\"", val, "\" is not a floating point number", NULL);
    if (*num < min || *num > max)
        return ap_psprintf(p, "\"%f\" is not between %f and %f", *num, min, max);
    return NULL;
}
Ejemplo n.º 15
0
/*******************************************************************************
 * Get the next configuration directive argument, & return an u_int.
 * The pool arg should be temporary storage.
 */
static const char *get_u_int(pool *p, const char **arg,
        u_int *num, u_int min)
{
    char *ptr;
    const char *val = ap_getword_conf(p, arg);

    if (*val == '\0')
        return "\"\"";
    *num = (u_int)strtol(val, &ptr, 10);

    if (*ptr != '\0')
        return ap_pstrcat(p, "\"", val, "\" must be a positive integer", NULL);
    else if (*num < min)
        return ap_psprintf(p, "\"%u\" must be >= %u", *num, min);
    return NULL;
}
Ejemplo n.º 16
0
static const char *get_int(pool *p, const char **arg, int *num, int min)
{
    char *cp;
    const char *val = ap_getword_conf(p, arg);

    if (*val == '\0')
    {
        return "\"\"";
    }

    *num = (int) strtol(val, &cp, 10);

    if (*cp != '\0')
    {
        return ap_pstrcat(p, "can't parse ", "\"", val, "\"", NULL);
    }
    else if (*num < min)
    {
        return ap_psprintf(p, "\"%d\" must be >= %d", *num, min);
    }
            
    return NULL;
}
Ejemplo n.º 17
0
char *ApacheUtil_expires(pool *p, char *time_str, int type)
{
    time_t when;
    struct tm *tms;
    int sep = (type == EXPIRES_HTTP) ? ' ' : '-';

    if (!time_str) {
	return NULL;
    }

    when = expire_calc(time_str);

    if (!when) {
	return ap_pstrdup(p, time_str);
    }

    tms = gmtime(&when);
    return ap_psprintf(p,
		       "%s, %.2d%c%s%c%.2d %.2d:%.2d:%.2d GMT",
		       ap_day_snames[tms->tm_wday],
		       tms->tm_mday, sep, ap_month_snames[tms->tm_mon], sep,
		       tms->tm_year + 1900,
		       tms->tm_hour, tms->tm_min, tms->tm_sec);
}
Ejemplo n.º 18
0
/*******************************************************************************
 * Enable, disable, or specify the path to a wrapper used to invoke all
 * FastCGI applications.
 */
const char *fcgi_config_set_wrapper(cmd_parms *cmd, void *dummy, const char *arg)
{
#ifdef WIN32
    return ap_psprintf(cmd->temp_pool, 
        "the %s directive is not supported on WIN", cmd->cmd->name);
#else

    const char *err = NULL;
    const char * const name = cmd->cmd->name;
    pool * const tp = cmd->temp_pool;
    char * wrapper = NULL;

    err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
    if (err)
    {
        return err;
    }

    if (fcgi_wrapper)
    {
        return ap_psprintf(tp, "%s was already set to \"%s\"",
                           name, fcgi_wrapper);
    }

    err = fcgi_config_set_fcgi_uid_n_gid(1);
    if (err != NULL)
        return ap_psprintf(tp, "%s %s: %s", name, arg, err);

    if (fcgi_servers != NULL) {
        return ap_psprintf(tp,
            "The %s command must preceed static FastCGI server definitions", name);
    }

    if (strcasecmp(arg, "Off") == 0) {
        fcgi_wrapper = NULL;
        return NULL;
    }

    if (strcasecmp(arg, "On") == 0) 
    {
        wrapper = SUEXEC_BIN;
    }
    else
    {
#ifdef APACHE2
        if (apr_filepath_merge(&wrapper, "", arg, 0, cmd->pool))
            return ap_psprintf(tp, "%s %s: invalid filepath", name, arg);
#else
        wrapper = ap_os_canonical_filename(cmd->pool, (char *) arg);
#endif

        wrapper = ap_server_root_relative(cmd->pool, wrapper);
    }

    err = fcgi_util_check_access(tp, wrapper, NULL, X_OK, fcgi_user_id, fcgi_group_id);
    if (err) 
    {
        return ap_psprintf(tp, "%s: \"%s\" execute access for server "
                           "(uid %ld, gid %ld) failed: %s", name, wrapper,
                           (long) fcgi_user_id, (long) fcgi_group_id, err);
    }

    fcgi_wrapper = wrapper;

    return NULL;
#endif /* !WIN32 */
}
Ejemplo n.º 19
0
static PyObject *req_add_handler(requestobject *self, PyObject *args)
{
    char *handler;
    char *function;
    const char *dir = NULL;
    const char *currhand;

    if (! PyArg_ParseTuple(args, "ss|s", &handler, &function, &dir)) 
        return NULL;

    if (! valid_handler(handler)) {
	PyErr_SetString(PyExc_IndexError, 
			ap_psprintf(self->request_rec->pool,
				    "Invalid handler: %s", handler));
	return NULL;
    }
    
    /* which handler are we processing? */
    currhand = ap_table_get(self->request_rec->notes, "python_handler");

    if (strcmp(currhand, handler) == 0) {

	/* if it's the same as what's being added, then just append to hstack */
	self->hstack = ap_pstrcat(self->request_rec->pool, self->hstack, 
				  function, NULL);
        
	if (dir) 
            ap_table_set(self->request_rec->notes, 
			 ap_pstrcat(self->request_rec->pool, handler, "_dir", NULL), 
			 dir);
    }
    else {

	const char *existing;

	/* is there a handler like this in the notes already? */
	existing = ap_table_get(self->request_rec->notes, handler);

	if (existing) {

	    /* append the function to the list using the request pool */
	    ap_table_set(self->request_rec->notes, handler, 
			 ap_pstrcat(self->request_rec->pool, existing, " ", 
				    function, NULL));

	    if (dir) {
		char *s = ap_pstrcat(self->request_rec->pool, handler, "_dir", NULL);
		ap_table_set(self->request_rec->notes, s, dir);
	    }

	}
	else {

	    char *s;

	    /* a completely new handler */
	    ap_table_set(self->request_rec->notes, handler, function);

	    if (! dir) {

		/*
		 * If no directory was explicitely specified, the new handler will 
		 * have the same directory associated with it as the handler 
		 * currently being processed.
		 */

		py_dir_config *conf;

		/* get config */
		conf = (py_dir_config *) ap_get_module_config(
		    self->request_rec->per_dir_config, &python_module);
        
		/* what's the directory for this handler? */
		dir = ap_table_get(conf->dirs, currhand);

		/*
		 * make a note that the handler's been added. 
		 * req_get_all_* rely on this to be faster
		 */
		ap_table_set(self->request_rec->notes, "py_more_directives", "1");

	    }
	    s = ap_pstrcat(self->request_rec->pool, handler, "_dir", NULL);
	    ap_table_set(self->request_rec->notes, s, dir);
	}
    }
    
    Py_INCREF(Py_None);
    return Py_None;
}
Ejemplo n.º 20
0
static const char *log_server_port(request_rec *r, char *a)
{
    return ap_psprintf(r->pool, "%u",
	r->server->port ? r->server->port : ap_default_port(r));
}
Ejemplo n.º 21
0
static const char *log_child_pid(request_rec *r, char *a)
{
    return ap_psprintf(r->pool, "%ld", (long) getpid());
}
Ejemplo n.º 22
0
/*******************************************************************************
 * Configure a static FastCGI server.
 */
const char *fcgi_config_new_static_server(cmd_parms *cmd, void *dummy, const char *arg)
{
    fcgi_server *s;
    pool *p = cmd->pool, *tp = cmd->temp_pool;
    const char *name = cmd->cmd->name;
    char *fs_path = ap_getword_conf(p, &arg);
    const char *option, *err;

    /* Allocate temp storage for the array of initial environment variables */
    char **envp = ap_pcalloc(tp, sizeof(char *) * (MAX_INIT_ENV_VARS + 3));
    unsigned int envc = 0;

#ifdef WIN32
    HANDLE mutex;
#endif

    err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_DIR_LOC_FILE);
    if (err)
    {
        return err;
    }

    if (*fs_path == '\0')
        return "AppClass requires a pathname!?";

    if ((err = fcgi_config_set_fcgi_uid_n_gid(1)) != NULL)
        return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);

#ifdef APACHE2
    if (apr_filepath_merge(&fs_path, "", fs_path, 0, p))
        return ap_psprintf(tp, "%s %s: invalid filepath", name, fs_path);
#else
    fs_path = ap_os_canonical_filename(p, fs_path);
#endif
    fs_path = ap_server_root_relative(p, fs_path);

    ap_getparents(fs_path);
    ap_no2slash(fs_path);

    /* See if we've already got one of these configured */
    s = fcgi_util_fs_get_by_id(fs_path, fcgi_util_get_server_uid(cmd->server),
                               fcgi_util_get_server_gid(cmd->server));
    if (s != NULL) {
        if (fcgi_wrapper) {
            return ap_psprintf(tp,
                "%s: redefinition of a previously defined FastCGI "
                "server \"%s\" with uid=%ld and gid=%ld",
                name, fs_path, (long) fcgi_util_get_server_uid(cmd->server),
                (long) fcgi_util_get_server_gid(cmd->server));
        }
        else {
            return ap_psprintf(tp,
                "%s: redefinition of a previously defined FastCGI server \"%s\"",
                name, fs_path);
        }
    }

    err = fcgi_util_fs_is_path_ok(tp, fs_path, NULL);
    if (err != NULL) {
        return ap_psprintf(tp, "%s: \"%s\" %s", name, fs_path, err);
    }

    s = fcgi_util_fs_new(p);
    s->fs_path = fs_path;
    s->directive = APP_CLASS_STANDARD;
    s->restartOnExit = TRUE;
    s->numProcesses = 1;

#ifdef WIN32

    /* TCP FastCGI applications require SystemRoot be present in the environment
     * Put it in both for consistency to the application */
    fcgi_config_set_env_var(p, envp, &envc, "SystemRoot");

    mutex = CreateMutex(NULL, FALSE, fs_path);
    
    if (mutex == NULL)
    {
        ap_log_error(FCGI_LOG_ALERT, fcgi_apache_main_server,
            "FastCGI: CreateMutex() failed");
        return "failed to create FastCGI application accept mutex";
    }
    
    SetHandleInformation(mutex, HANDLE_FLAG_INHERIT, TRUE);

    s->mutex_env_string = ap_psprintf(p, "_FCGI_MUTEX_=%ld", mutex);

#endif

    /*  Parse directive arguments */
    while (*arg) {
        option = ap_getword_conf(tp, &arg);

        if (strcasecmp(option, "-processes") == 0) {
            if ((err = get_u_int(tp, &arg, &s->numProcesses, 1)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-restart-delay") == 0) {
            if ((err = get_u_int(tp, &arg, &s->restartDelay, 0)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-init-start-delay") == 0) {
            if ((err = get_int(tp, &arg, &s->initStartDelay, 0)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-min-server-life") == 0) {
            if ((err = get_u_int(tp, &arg, &s->minServerLife, 0)))
                return invalid_value(tp, name, NULL, option, err);
        }
        else if (strcasecmp(option, "-priority") == 0) {
            if ((err = get_u_int(tp, &arg, &s->processPriority, 0)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-listen-queue-depth") == 0) {
            if ((err = get_u_int(tp, &arg, &s->listenQueueDepth, 1)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-appConnTimeout") == 0) {
            if ((err = get_u_int(tp, &arg, &s->appConnectTimeout, 0)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-idle-timeout") == 0) {
            if ((err = get_u_int(tp, &arg, &s->idle_timeout, 1)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-port") == 0) {
            if ((err = get_u_short(tp, &arg, &s->port, 1)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-socket") == 0) {
            s->socket_path = ap_getword_conf(tp, &arg);
            if (*s->socket_path == '\0')
                return invalid_value(tp, name, fs_path, option, "\"\"");
        }
        else if (strcasecmp(option, "-initial-env") == 0) {
            if ((err = get_env_var(p, &arg, envp, &envc)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-pass-header") == 0) {
            if ((err = get_pass_header(p, &arg, &s->pass_headers)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-flush") == 0) {
            s->flush = 1;
        }
        else if (strcasecmp(option, "-nph") == 0) {
            s->nph = 1;
        }
        else if (strcasecmp(option, "-user") == 0) {
#ifdef WIN32
            return ap_psprintf(tp, 
                "%s %s: the -user option isn't supported on WIN", name, fs_path);
#else
            s->user = ap_getword_conf(tp, &arg);
            if (*s->user == '\0')
                return invalid_value(tp, name, fs_path, option, "\"\"");
#endif
        }
        else if (strcasecmp(option, "-group") == 0) {
#ifdef WIN32
            return ap_psprintf(tp, 
                "%s %s: the -group option isn't supported on WIN", name, fs_path);
#else
            s->group = ap_getword_conf(tp, &arg);
            if (*s->group == '\0')
                return invalid_value(tp, name, fs_path, option, "\"\"");
#endif
        }
        else {
            return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option);
        }
    } /* while */

#ifndef WIN32
    if (fcgi_wrapper)
    {
        if (s->group == NULL)
        {
            s->group = ap_psprintf(tp, "#%ld", (long)fcgi_util_get_server_gid(cmd->server));
        }

        if (s->user == NULL)
        {
            s->user = ap_psprintf(p, "#%ld", (long)fcgi_util_get_server_uid(cmd->server)); 
        }

        s->uid = ap_uname2id(s->user);
        s->gid = ap_gname2id(s->group);
    }
    else if (s->user || s->group)
    {
        ap_log_error(FCGI_LOG_WARN, cmd->server, "FastCGI: there is no "
                     "fastcgi wrapper set, user/group options are ignored");
    }

    if ((err = fcgi_util_fs_set_uid_n_gid(p, s, s->uid, s->gid)))
    {
        return ap_psprintf(tp, 
            "%s %s: invalid user or group: %s", name, fs_path, err);
    }
#endif /* !WIN32 */

    if (s->socket_path != NULL && s->port != 0) {
        return ap_psprintf(tp,
                "%s %s: -port and -socket are mutually exclusive options",
                name, fs_path);
    }

    /* Move env array to a surviving pool */
    s->envp = (char **)ap_pcalloc(p, sizeof(char *) * (envc + 4));
    memcpy(s->envp, envp, sizeof(char *) * envc);

    /* Initialize process structs */
    s->procs = fcgi_util_fs_create_procs(p, s->numProcesses);

    /* Build the appropriate sockaddr structure */
    if (s->port != 0) {
        err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr,
                                &s->socket_addr_len, NULL, s->port);
        if (err != NULL)
            return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
#ifdef WIN32
        err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->dest_addr,
                                          &s->socket_addr_len, "localhost", s->port);
        if (err != NULL)
            return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
#endif
    } else {
        if (s->socket_path == NULL)
             s->socket_path = fcgi_util_socket_hash_filename(tp, fs_path, s->user, s->group);

        if (fcgi_socket_dir == NULL)
        {
#ifdef WIN32
            fcgi_socket_dir = DEFAULT_SOCK_DIR;
#else
            fcgi_socket_dir = ap_server_root_relative(p, DEFAULT_SOCK_DIR);
#endif
        }

        s->socket_path = fcgi_util_socket_make_path_absolute(p, s->socket_path, 0);
#ifndef WIN32
        err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr,
                                  &s->socket_addr_len, s->socket_path);
        if (err != NULL)
            return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
#endif
    }

    /* Add it to the list of FastCGI servers */
    fcgi_util_fs_add(s);

    return NULL;
}
Ejemplo n.º 23
0
static const char *log_request_duration(request_rec *r, char *a)
{
    return ap_psprintf(r->pool, "%ld", time(NULL) - r->request_time);
}
Ejemplo n.º 24
0
static int handle_request(request_rec *r)
{
	tmcdreq_t tmcdreq, *reqp = &tmcdreq;
	tmcdresp_t *response = NULL;
	char *command;
	struct in_addr local_addr;
	struct in_addr remote_addr;
	struct sockaddr_in redir_client;
	int tmcd_status;
	int status = OK;
	char *status_line = NULL;
	char *args = NULL;
	char *function_args = NULL;
	char *p;
	char **argv = NULL;
	int argc, i;

	reqp->istcp = 1;
	reqp->isssl = 1; /* FIXME */

	if (strcmp(r->handler, "tmcd")) {
		status = DECLINED;
		goto err;
	}

#if 0
	r->allowed |= (AP_METHOD_BIT << M_GET);
	if (r->method_number != M_GET) {
		status = DECLINED;
		goto err;
	}
#endif

	memset(reqp, 0, sizeof(*reqp));

	local_addr = r->connection->local_addr.sin_addr;
	remote_addr = r->connection->remote_addr.sin_addr;

	reqp->version = 1; /* FIXME need sane default */
	tmcd_init(reqp, &local_addr, NULL);

	command = r->path_info;
	while (*command && *command == '/') {
		command++;
	}
	if (command[0] == '\0') {
		status = HTTP_BAD_REQUEST;
		goto err;
	}

	if (r->args) {
		args = malloc(strlen(r->args) + 1);
		if (args == NULL) {
			status = HTTP_INTERNAL_SERVER_ERROR;
			goto err;
		}

		strcpy(args, r->args);
		argv = make_argv(args, &argc, '&');
		if (argv == NULL) {
			status = HTTP_INTERNAL_SERVER_ERROR;
			goto err;
		}

		for (i = 0; i < argc; i++) {
			/* Unescape the arguments */
			p = args;
			while (*p) {
				if (*p == '+')
					*p = ' ';
				p++;
			}

			status = ap_unescape_url(args);
			if (status != OK) {
				goto err;
			}

			if (strncasecmp(argv[i], "version=", 8) == 0) {
				long version;
				char *end;
				version = strtol(argv[i] + 8, &end, 10);
				if (*end != '\0' || *(argv[i] + 8) == '\0') {
					status = HTTP_BAD_REQUEST;
					status_line = "Invalid Version";
					goto err;
				}

				reqp->version = version;
			} else if (strncasecmp(argv[i], "redirect=", 9) == 0) {
				if (inet_pton(AF_INET, argv[i] + 9,
				              &redir_client.sin_addr) <= 0) {
					status = HTTP_BAD_REQUEST;
					status_line = "Invalid IP Address";
					goto err;
				}
				/* FIXME info message */

				if (remote_addr.s_addr != local_addr.s_addr) {
					status = HTTP_FORBIDDEN;
					status_line = "Redirection Not Allowed";
					goto err;
				}

				remote_addr =
				    redir_client.sin_addr;

			} else if (strncasecmp(argv[i], "vnodeid=", 8) == 0) {
				if (strlen(argv[i] + 8) >=
				           sizeof(reqp->vnodeid)) {
					status = HTTP_BAD_REQUEST;
					status_line =
					    "Virtual Node ID Too Long";
					goto err;
				}
				reqp->isvnode = 1;
				strcpy(reqp->vnodeid, argv[i] + 8);
			} else if (strncasecmp(argv[i], "args=", 5) == 0) {
				function_args = argv[i] + 5;
			}
		}

	}

	/* FIXME handle wanodekey */
	if ((tmcd_status = iptonodeid(reqp, remote_addr, NULL))) {
		if (reqp->isvnode) {
			status_line = "Invalid Virtual Node";
		}
		else {
			status_line = "Invalid Node";
		}
		status = HTTP_NOT_FOUND;
		goto err;
	}

	if (reqp->tmcd_redirect[0]) {
		/* FIXME what if https should be used? */
		/* FIXME do I need to specify the args should be passed too? */
		char *uri = ap_psprintf(r->pool, "http://%s%s?%s", reqp->tmcd_redirect,
		                        r->uri, r->args);
		ap_table_setn(r->headers_out, "Location", uri);
		status = HTTP_MOVED_TEMPORARILY;
		goto done;
	}

	tmcd_status = tmcd_handle_request(reqp, &response, command,
	                                  function_args);

	if (tmcd_status == TMCD_STATUS_OK) {
		r->content_type = response->type;
		ap_set_content_length(r, response->length);
		/* FIXME doctype */
		ap_soft_timeout("tmcd response call trace", r);
		ap_send_http_header(r);
		ap_rprintf(r, "%s", response->data);
		ap_kill_timeout(r);
		status = OK;
		goto done;
	} else {
		switch(tmcd_status) {
			case TMCD_STATUS_UNKNOWN_COMMAND:
				status = HTTP_NOT_FOUND;
				status_line = "Unknown Command";
				break;
			case TMCD_STATUS_REQUIRES_ENCRYPTION:
				status = HTTP_FORBIDDEN;
				status_line = "SSL Required";
				break;
			case TMCD_STATUS_NODE_NOT_ALLOCATED:
				status = HTTP_FORBIDDEN;
				status_line = "Node Not Allocated";
				break;
			case TMCD_STATUS_COMMAND_FAILED:
				status = HTTP_INTERNAL_SERVER_ERROR;
				if (response && response->data) {
					status_line = response->data;
				}
				break;
			case TMCD_STATUS_MALLOC_FAILED:
				status = HTTP_INTERNAL_SERVER_ERROR;
				break;
		}

		goto err;
	}
err:
done:
	if (argv)
		free(argv);

	if (args)
		free(args);

	if (response)
		tmcd_free_response(response);

	if (status_line) {
		r->status_line = ap_psprintf(r->pool, "%3.3u %s", status,
		                             status_line);
	}
	return status;
}
Ejemplo n.º 25
0
static char *format_integer(pool *p, int i)
{
    return ap_psprintf(p, "%d", i);
}
Ejemplo n.º 26
0
/*******************************************************************************
 * Configure a static FastCGI server that is started/managed elsewhere.
 */
const char *fcgi_config_new_external_server(cmd_parms *cmd, void *dummy, const char *arg)
{
    fcgi_server *s;
    pool * const p = cmd->pool, *tp = cmd->temp_pool;
    const char * const name = cmd->cmd->name;
    char *fs_path = ap_getword_conf(p, &arg);
    const char *option, *err;

    err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_DIR_LOC_FILE);
    if (err) {
        return err;
    }

    if (!*fs_path) {
        return ap_pstrcat(tp, name, " requires a path and either a -socket or -host option", NULL);
    }

#ifdef APACHE2
    if (apr_filepath_merge(&fs_path, "", fs_path, 0, p))
        return ap_psprintf(tp, "%s %s: invalid filepath", name, fs_path);
#else
    fs_path = ap_os_canonical_filename(p, fs_path);
#endif

    fs_path = ap_server_root_relative(p, fs_path);

    ap_getparents(fs_path);
    ap_no2slash(fs_path);

    /* See if we've already got one of these bettys configured */
    s = fcgi_util_fs_get_by_id(fs_path, fcgi_util_get_server_uid(cmd->server),
                               fcgi_util_get_server_gid(cmd->server));
    if (s != NULL) {
        if (fcgi_wrapper) {
            return ap_psprintf(tp,
                "%s: redefinition of a previously defined class \"%s\" "
                "with uid=%ld and gid=%ld",
                name, fs_path, (long) fcgi_util_get_server_uid(cmd->server),
                (long) fcgi_util_get_server_gid(cmd->server));
        }
        else 
        {
            return ap_psprintf(tp,
                "%s: redefinition of previously defined class \"%s\"", name, fs_path);
        }
    }

    s = fcgi_util_fs_new(p);
    s->fs_path = fs_path;
    s->directive = APP_CLASS_EXTERNAL;

    /*  Parse directive arguments */
    while (*arg != '\0') {
        option = ap_getword_conf(tp, &arg);

        if (strcasecmp(option, "-host") == 0) {
            if ((err = get_host_n_port(p, &arg, &s->host, &s->port)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-socket") == 0) {
            s->socket_path = ap_getword_conf(tp, &arg);
            if (*s->socket_path == '\0')
                return invalid_value(tp, name, fs_path, option, "\"\"");
        }
        else if (strcasecmp(option, "-appConnTimeout") == 0) {
            if ((err = get_u_int(tp, &arg, &s->appConnectTimeout, 0)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-idle-timeout") == 0) {
            if ((err = get_u_int(tp, &arg, &s->idle_timeout, 1)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-nph") == 0) {
            s->nph = 1;
        }
        else if (strcasecmp(option, "-pass-header") == 0) {
            if ((err = get_pass_header(p, &arg, &s->pass_headers)))
                return invalid_value(tp, name, fs_path, option, err);
        }
        else if (strcasecmp(option, "-flush") == 0) {
            s->flush = 1;
        }
        else if (strcasecmp(option, "-user") == 0) {
#ifdef WIN32
            return ap_psprintf(tp, 
                "%s %s: the -user option isn't supported on WIN", name, fs_path);
#else
            s->user = ap_getword_conf(tp, &arg);
            if (*s->user == '\0')
                return invalid_value(tp, name, fs_path, option, "\"\"");
#endif
        }
        else if (strcasecmp(option, "-group") == 0) {
#ifdef WIN32
            return ap_psprintf(tp, 
                "%s %s: the -group option isn't supported on WIN", name, fs_path);
#else
            s->group = ap_getword_conf(tp, &arg);
            if (*s->group == '\0')
                return invalid_value(tp, name, fs_path, option, "\"\"");
#endif
        }
        else if (strcasecmp(option, "-fixPaths") == 0) {
            s->fixPaths = 1;
        }
        else {
            return ap_psprintf(tp, "%s %s: invalid option: %s", name, fs_path, option);
        }
    } /* while */


#ifndef WIN32
    if (fcgi_wrapper)
    {
        if (s->group == NULL)
        {
            s->group = ap_psprintf(tp, "#%ld", (long)fcgi_util_get_server_gid(cmd->server));
        }

        if (s->user == NULL)
        {
            s->user = ap_psprintf(p, "#%ld", (long)fcgi_util_get_server_uid(cmd->server));
        }

        s->uid = ap_uname2id(s->user);
        s->gid = ap_gname2id(s->group);
    }
    else if (s->user || s->group)
    {
        ap_log_error(FCGI_LOG_WARN, cmd->server, "FastCGI: there is no "
                     "fastcgi wrapper set, user/group options are ignored");
    }

    if ((err = fcgi_util_fs_set_uid_n_gid(p, s, s->uid, s->gid)))
    {
        return ap_psprintf(tp,
            "%s %s: invalid user or group: %s", name, fs_path, err);
    }
#endif /* !WIN32 */

    /* Require one of -socket or -host, but not both */
    if (s->socket_path != NULL && s->port != 0) {
        return ap_psprintf(tp,
            "%s %s: -host and -socket are mutually exclusive options",
            name, fs_path);
    }
    if (s->socket_path == NULL && s->port == 0) {
        return ap_psprintf(tp,
            "%s %s: -socket or -host option missing", name, fs_path);
    }

    /* Build the appropriate sockaddr structure */
    if (s->port != 0) {
        err = fcgi_util_socket_make_inet_addr(p, (struct sockaddr_in **)&s->socket_addr,
            &s->socket_addr_len, s->host, s->port);
        if (err != NULL)
            return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
    } else {

        if (fcgi_socket_dir == NULL)
        {
#ifdef WIN32
            fcgi_socket_dir = DEFAULT_SOCK_DIR;
#else
            fcgi_socket_dir = ap_server_root_relative(p, DEFAULT_SOCK_DIR);
#endif
        }

        s->socket_path = fcgi_util_socket_make_path_absolute(p, s->socket_path, 0);
#ifndef WIN32
        err = fcgi_util_socket_make_domain_addr(p, (struct sockaddr_un **)&s->socket_addr,
                                  &s->socket_addr_len, s->socket_path);
        if (err != NULL)
            return ap_psprintf(tp, "%s %s: %s", name, fs_path, err);
#endif
    }

    /* Add it to the list of FastCGI servers */
    fcgi_util_fs_add(s);

    return NULL;
}
Ejemplo n.º 27
0
API_EXPORT(void) ap_add_common_vars(request_rec *r)
{
    table *e;
    server_rec *s = r->server;
    conn_rec *c = r->connection;
    const char *rem_logname;
    char *env_path;
#if defined(WIN32) || defined(OS2)
    char *env_temp;
#endif
    const char *host;
    array_header *hdrs_arr = ap_table_elts(r->headers_in);
    table_entry *hdrs = (table_entry *) hdrs_arr->elts;
    int i;
    char servbuf[NI_MAXSERV];

    /* use a temporary table which we'll overlap onto
     * r->subprocess_env later
     */
    e = ap_make_table(r->pool, 25 + hdrs_arr->nelts);

    /* First, add environment vars from headers... this is as per
     * CGI specs, though other sorts of scripting interfaces see
     * the same vars...
     */

    for (i = 0; i < hdrs_arr->nelts; ++i) {
        if (!hdrs[i].key) {
	    continue;
	}

	/* A few headers are special cased --- Authorization to prevent
	 * rogue scripts from capturing passwords; content-type and -length
	 * for no particular reason.
	 */

	if (!strcasecmp(hdrs[i].key, "Content-type")) {
	    ap_table_addn(e, "CONTENT_TYPE", hdrs[i].val);
	}
	else if (!strcasecmp(hdrs[i].key, "Content-length")) {
	    ap_table_addn(e, "CONTENT_LENGTH", hdrs[i].val);
	}
	/*
	 * You really don't want to disable this check, since it leaves you
	 * wide open to CGIs stealing passwords and people viewing them
	 * in the environment with "ps -e".  But, if you must...
	 */
#ifndef SECURITY_HOLE_PASS_AUTHORIZATION
	else if (!strcasecmp(hdrs[i].key, "Authorization") 
		 || !strcasecmp(hdrs[i].key, "Proxy-Authorization")) {
	    continue;
	}
#endif
	else {
	    ap_table_addn(e, http2env(r->pool, hdrs[i].key), hdrs[i].val);
	}
    }

    if (!(env_path = ap_pstrdup(r->pool, getenv("PATH")))) {
	env_path = DEFAULT_PATH;
    }

#ifdef WIN32
    if (env_temp = getenv("SystemRoot")) {
        ap_table_addn(e, "SystemRoot", env_temp);         
    }
    if (env_temp = getenv("COMSPEC")) {
        ap_table_addn(e, "COMSPEC", env_temp);            
    }
    if (env_temp = getenv("WINDIR")) {
        ap_table_addn(e, "WINDIR", env_temp);
    }
#endif

#ifdef OS2
    if ((env_temp = getenv("COMSPEC")) != NULL) {
        ap_table_addn(e, "COMSPEC", env_temp);            
    }
    if ((env_temp = getenv("ETC")) != NULL) {
        ap_table_addn(e, "ETC", env_temp);            
    }
    if ((env_temp = getenv("DPATH")) != NULL) {
        ap_table_addn(e, "DPATH", env_temp);            
    }
    if ((env_temp = getenv("PERLLIB_PREFIX")) != NULL) {
        ap_table_addn(e, "PERLLIB_PREFIX", env_temp);            
    }
#endif

    ap_table_addn(e, "PATH", env_path);
    ap_table_addn(e, "SERVER_SIGNATURE", ap_psignature("", r));
    ap_table_addn(e, "SERVER_SOFTWARE", ap_get_server_version());
    ap_table_addn(e, "SERVER_NAME", 
		  ap_escape_html(r->pool,ap_get_server_name(r)));
    ap_table_addn(e, "SERVER_ADDR", r->connection->local_ip);	/* Apache */
    ap_table_addn(e, "SERVER_PORT",
		  ap_psprintf(r->pool, "%u", ap_get_server_port(r)));
    host = ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST);
    if (host) {
	ap_table_addn(e, "REMOTE_HOST", host);
    }
    ap_table_addn(e, "REMOTE_ADDR", c->remote_ip);
    ap_table_addn(e, "DOCUMENT_ROOT", ap_document_root(r));	/* Apache */
    ap_table_addn(e, "SERVER_ADMIN", s->server_admin);	/* Apache */
    ap_table_addn(e, "SCRIPT_FILENAME", r->filename);	/* Apache */

    servbuf[0] = '\0';
    if (!getnameinfo((struct sockaddr *)&c->remote_addr,
#ifndef HAVE_SOCKADDR_LEN
		     SA_LEN((struct sockaddr *)&c->remote_addr),
#else
		     c->remote_addr.ss_len,
#endif
		     NULL, 0, servbuf, sizeof(servbuf), NI_NUMERICSERV)){
	ap_table_addn(e, "REMOTE_PORT", ap_pstrdup(r->pool, servbuf));
    }

    if (c->user) {
	ap_table_addn(e, "REMOTE_USER", c->user);
    }
    if (c->ap_auth_type) {
	ap_table_addn(e, "AUTH_TYPE", c->ap_auth_type);
    }
    rem_logname = ap_get_remote_logname(r);
    if (rem_logname) {
	ap_table_addn(e, "REMOTE_IDENT", ap_pstrdup(r->pool, rem_logname));
    }

    /* Apache custom error responses. If we have redirected set two new vars */

    if (r->prev) {
        if (r->prev->args) {
	    ap_table_addn(e, "REDIRECT_QUERY_STRING", r->prev->args);
	}
	if (r->prev->uri) {
	    ap_table_addn(e, "REDIRECT_URL", r->prev->uri);
	}
    }

    ap_overlap_tables(r->subprocess_env, e, AP_OVERLAP_TABLES_SET);
}
Ejemplo n.º 28
0
/*******************************************************************************
 * Determine if a process with uid/gid can access a file with mode permissions.
 */
const char *
fcgi_util_check_access(pool *tp, 
        const char * const path, const struct stat *statBuf, 
        const int mode, const uid_t uid, const gid_t gid)
{
    struct stat myStatBuf;

    if (statBuf == NULL) {    
        if (stat(path, &myStatBuf) < 0)
            return ap_psprintf(tp, "stat(%s) failed: %s", path, strerror(errno));
        statBuf = &myStatBuf;
    }
    
#ifndef WIN32    
    /* If the uid owns the file, check the owner bits */
    if (uid == statBuf->st_uid) {
        if (mode & R_OK && !(statBuf->st_mode & S_IRUSR))
            return "read not allowed by owner";
        if (mode & W_OK && !(statBuf->st_mode & S_IWUSR))
            return "write not allowed by owner";
        if (mode & X_OK && !(statBuf->st_mode & S_IXUSR))
            return "execute not allowed by owner";
        return NULL;
    }
#else
    if (mode & _S_IREAD && !(statBuf->st_mode & _S_IREAD))
        return "read not allowed";
    if (mode & _S_IWRITE && !(statBuf->st_mode & _S_IWRITE))
        return "write not allowed";
    
    /* I don't think this works on FAT, but since I don't know how to check..
     * if (mode & _S_IEXEC && !(statBuf->st_mode & _S_IEXEC))
     *     return "execute not allowed"; */
#endif

#if  !defined(__EMX__) && !defined(WIN32)
    /* If the gid is same as the file's group, check the group bits */
    if (gid == statBuf->st_gid) {
        if (mode & R_OK && !(statBuf->st_mode & S_IRGRP))
            return "read not allowed by group";
        if (mode & W_OK && !(statBuf->st_mode & S_IWGRP))
            return "write not allowed by group";
        if (mode & X_OK && !(statBuf->st_mode & S_IXGRP))
            return "execute not allowed by group";
        return NULL;
    }

    /* Get the user membership for the file's group.  If the
     * uid is a member, check the group bits. */
    {
        const struct group * const gr = getgrgid(statBuf->st_gid);
        const struct passwd * const pw = getpwuid(uid);

        if (gr != NULL && pw != NULL) {
            char **user = gr->gr_mem;
            for ( ; *user != NULL; user++) {
                if (strcmp(*user, pw->pw_name) == 0) {
                    if (mode & R_OK && !(statBuf->st_mode & S_IRGRP))
                        return "read not allowed by group";
                    if (mode & W_OK && !(statBuf->st_mode & S_IWGRP))
                        return "write not allowed by group";
                    if (mode & X_OK && !(statBuf->st_mode & S_IXGRP))
                        return "execute not allowed by group";
                    return NULL;
                }
            }
        }
    }
    
    /* That just leaves the other bits.. */
    if (mode & R_OK && !(statBuf->st_mode & S_IROTH))
        return "read not allowed";
    if (mode & W_OK && !(statBuf->st_mode & S_IWOTH))
        return "write not allowed";
    if (mode & X_OK && !(statBuf->st_mode & S_IXOTH))
        return "execute not allowed";
#endif

    return NULL;
}
Ejemplo n.º 29
0
/*
 * This handles http:// URLs, and other URLs using a remote proxy over http
 * If proxyhost is NULL, then contact the server directly, otherwise
 * go via the proxy.
 * Note that if a proxy is used, then URLs other than http: can be accessed,
 * also, if we have trouble which is clearly specific to the proxy, then
 * we return DECLINED so that we can try another proxy. (Or the direct
 * route.)
 */
int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
                              const char *proxyhost, int proxyport)
{
    const char *strp;
    char *strp2;
    const char *err, *desthost;
    int i, j, sock,/* len,*/ backasswards;
    table *req_hdrs, *resp_hdrs;
    array_header *reqhdrs_arr;
    table_entry *reqhdrs_elts;
    BUFF *f;
    char buffer[HUGE_STRING_LEN];
    char portstr[32];
    pool *p = r->pool;
    int chunked = 0, destport = 0;
    char *destportstr = NULL;
    const char *urlptr = NULL;
    const char *datestr, *urlstr;
    struct addrinfo hints, *res, *res0;
    int error;
    int result, major, minor;
    const char *content_length;
    const char *peer;
    int destportstrtonum;
    const char *errstr;

    void *sconf = r->server->module_config;
    proxy_server_conf *conf =
    (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module);
    struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
    struct nocache_entry *ncent = (struct nocache_entry *) conf->nocaches->elts;
    int nocache = 0;

    if (conf->cache.root == NULL)
        nocache = 1;

    /* We break the URL into host, port, path-search */

    urlptr = strstr(url, "://");
    if (urlptr == NULL)
        return HTTP_BAD_REQUEST;
    destport = DEFAULT_HTTP_PORT;
    urlptr += 3;
    ap_hook_use("ap::mod_proxy::http::handler::set_destport", 
                AP_HOOK_SIG2(int,ptr), 
                AP_HOOK_TOPMOST,
                &destport, r);
    ap_snprintf(portstr, sizeof(portstr), "%d", destport);
    destportstr = portstr;
    strp = strchr(urlptr, '/');
    if (strp == NULL) {
        desthost = ap_pstrdup(p, urlptr);
        urlptr = "/";
    }
    else {
        char *q = ap_palloc(p, strp - urlptr + 1);
        memcpy(q, urlptr, strp - urlptr);
        q[strp - urlptr] = '\0';
        urlptr = strp;
        desthost = q;
    }
    if (*desthost == '['){
      char *u = strrchr(desthost+1, ']');
      if (u){
          desthost++;
          *u = '\0';
          if (*(u+1) == ':'){ /* [host]:xx */
              strp2 = u+1;
          }
          else if (*(u+1) == '\0'){   /* [host] */
              strp2 = NULL;
          }
          else
              return HTTP_BAD_REQUEST;
      }
      else
          return HTTP_BAD_REQUEST;
    }
    else
       strp2 = strrchr(desthost, ':');

    if (strp2 != NULL) {
        *(strp2++) = '\0';
        if (ap_isdigit(*strp2))
            destportstr = strp2;
    }

    /* Make sure peer is always set to prevent a segfault in the SSL handler */
    peer = desthost;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    error = getaddrinfo(desthost, destportstr, &hints, &res0);
    if (error && proxyhost == NULL) {
      return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR,
                  gai_strerror(error));       /* give up */
     }
 
      /* check if ProxyBlock directive on this host */
      for (i = 0; i < conf->noproxies->nelts; i++) {
      int fail;
      struct sockaddr_in *sin;

      fail = 0;
      if (npent[i].name != NULL && strstr(desthost, npent[i].name))
          fail++;
      if (npent[i].name != NULL && strcmp(npent[i].name, "*") == 0)
          fail++;
      for (res = res0; res; res = res->ai_next) {
          switch (res->ai_family) {
          case AF_INET:
              sin = (struct sockaddr_in *)res->ai_addr;
              if (sin->sin_addr.s_addr == npent[i].addr.s_addr)
                  fail++;
              break;
		
          }
      }
      if (fail) {
          if (res0 != NULL)
              freeaddrinfo(res0);
          return ap_proxyerror(r, HTTP_FORBIDDEN,
                               "Connect to remote machine blocked");
      }
    }
    if (proxyhost != NULL) {
      char pbuf[10];

      if (res0 != NULL)
          freeaddrinfo(res0);

      ap_snprintf(pbuf, sizeof(pbuf), "%d", proxyport);
      memset(&hints, 0, sizeof(hints));
      hints.ai_family = PF_UNSPEC;
      hints.ai_socktype = SOCK_STREAM;
      hints.ai_protocol = IPPROTO_TCP;
      error = getaddrinfo(proxyhost, pbuf, &hints, &res0);
      if (error)
          return DECLINED;    /* try another */
    }

    /* check if ProxyBlock directive on this host */
    for (i = 0; i < conf->noproxies->nelts; i++) {
	peer =  ap_psprintf(p, "%s:%s", desthost, destportstr);  
    }


    /*
     * we have worked out who exactly we are going to connect to, now make
     * that connection...
     */
     sock = i = -1;
     for (res = res0; res; res = res->ai_next) {
       sock = ap_psocket(p, res->ai_family, res->ai_socktype,
           res->ai_protocol);
       if (sock < 0)
           continue;

      if (conf->recv_buffer_size) {
          if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
                         (const char *)&conf->recv_buffer_size, sizeof(int))
              == -1) {
              ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
                            "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
          }
      }

      i = ap_proxy_doconnect(sock, res->ai_addr, r);
      if (i == 0)
          break;
      ap_pclosesocket(p, sock);
    }
    freeaddrinfo(res0);

    if (i == -1) {
        if (proxyhost != NULL)
            return DECLINED;    /* try again another way */
        else
            return ap_proxyerror(r, HTTP_BAD_GATEWAY, ap_pstrcat(r->pool,
                                    "Could not connect to remote machine: ",
                                                    strerror(errno), NULL));
    }

    /* record request_time for HTTP/1.1 age calculation */
    c->req_time = time(NULL);

    /*
     * build upstream-request headers by stripping r->headers_in from
     * connection specific headers. We must not remove the Connection: header
     * from r->headers_in, we still have to react to Connection: close
     */
    req_hdrs = ap_copy_table(r->pool, r->headers_in);
    ap_proxy_clear_connection(r->pool, req_hdrs);

    /*
     * At this point, we start sending the HTTP/1.1 request to the remote
     * server (proxy or otherwise).
     */
    f = ap_bcreate(p, B_RDWR | B_SOCKET);
    ap_bpushfd(f, sock, sock);

    {
        char *errmsg = NULL;
        ap_hook_use("ap::mod_proxy::http::handler::new_connection", 
                    AP_HOOK_SIG4(ptr,ptr,ptr,ptr), 
                    AP_HOOK_DECLINE(NULL),
                    &errmsg, r, f, peer);
        if (errmsg != NULL)
            return ap_proxyerror(r, HTTP_BAD_GATEWAY, errmsg);
    }

    ap_hard_timeout("proxy send", r);
    ap_bvputs(f, r->method, " ", proxyhost ? url : urlptr, " HTTP/1.1" CRLF,
              NULL);
    {
	int rc = DECLINED;
	ap_hook_use("ap::mod_proxy::http::handler::write_host_header", 
		    AP_HOOK_SIG6(int,ptr,ptr,ptr,ptr,ptr), 
		    AP_HOOK_DECLINE(DECLINED),
		    &rc, r, f, desthost, destportstr, destportstr);
        if (rc == DECLINED) {
	    destportstrtonum = strtonum(destportstr, 0, 65535, &errstr);
	    if (errstr)
		errx(1, "The destination port is %s: %s", errstr, destportstr);

	    if (destportstr != NULL && destportstrtonum != destport)
		ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL);
	    else
		ap_bvputs(f, "Host: ", desthost, CRLF, NULL);
        }
    }

    if (conf->viaopt == via_block) {
        /* Block all outgoing Via: headers */
        ap_table_unset(req_hdrs, "Via");
    }
    else if (conf->viaopt != via_off) {
        /* Create a "Via:" request header entry and merge it */
        i = ap_get_server_port(r);
        if (ap_is_default_port(i, r)) {
            strlcpy(portstr, "", sizeof(portstr));
        }
        else {
            ap_snprintf(portstr, sizeof portstr, ":%d", i);
        }
        /* Generate outgoing Via: header with/without server comment: */
        ap_table_mergen(req_hdrs, "Via",
                        (conf->viaopt == via_full)
                        ? ap_psprintf(p, "%d.%d %s%s (%s)",
                                      HTTP_VERSION_MAJOR(r->proto_num),
                                      HTTP_VERSION_MINOR(r->proto_num),
                                      ap_get_server_name(r), portstr,
                                      SERVER_BASEVERSION)
                        : ap_psprintf(p, "%d.%d %s%s",
                                      HTTP_VERSION_MAJOR(r->proto_num),
                                      HTTP_VERSION_MINOR(r->proto_num),
                                      ap_get_server_name(r), portstr)
            );
    }

    /* the X-* headers are only added if we are a reverse
     * proxy, otherwise we would be giving away private information.
     */
    if (r->proxyreq == PROXY_PASS) {
        const char *buf;

        /*
         * Add X-Forwarded-For: so that the upstream has a chance to determine,
         * where the original request came from.
         */
        ap_table_mergen(req_hdrs, "X-Forwarded-For", r->connection->remote_ip);

        /* Add X-Forwarded-Host: so that upstream knows what the
         * original request hostname was.
         */
        if ((buf = ap_table_get(r->headers_in, "Host"))) {
            ap_table_mergen(req_hdrs, "X-Forwarded-Host", buf);
        }

        /* Add X-Forwarded-Server: so that upstream knows what the
         * name of this proxy server is (if there are more than one)
         * XXX: This duplicates Via: - do we strictly need it?
         */
        ap_table_mergen(req_hdrs, "X-Forwarded-Server", r->server->server_hostname);
    } 

    /* we don't yet support keepalives - but we will soon, I promise! */
    ap_table_set(req_hdrs, "Connection", "close");

    reqhdrs_arr = ap_table_elts(req_hdrs);
    reqhdrs_elts = (table_entry *)reqhdrs_arr->elts;
    for (i = 0; i < reqhdrs_arr->nelts; i++) {
        if (reqhdrs_elts[i].key == NULL || reqhdrs_elts[i].val == NULL

        /*
         * Clear out hop-by-hop request headers not to send: RFC2616 13.5.1
         * says we should strip these headers:
         */
            || !strcasecmp(reqhdrs_elts[i].key, "Host") /* Already sent */
            || !strcasecmp(reqhdrs_elts[i].key, "Keep-Alive")
            || !strcasecmp(reqhdrs_elts[i].key, "TE")
            || !strcasecmp(reqhdrs_elts[i].key, "Trailer")
            || !strcasecmp(reqhdrs_elts[i].key, "Transfer-Encoding")
            || !strcasecmp(reqhdrs_elts[i].key, "Upgrade")
        /*
         * XXX: @@@ FIXME: "Proxy-Authorization" should *only* be suppressed
         * if THIS server requested the authentication, not when a frontend
         * proxy requested it!
         * 
         * The solution to this problem is probably to strip out the
         * Proxy-Authorisation header in the authorisation code itself, not
         * here. This saves us having to signal somehow whether this request
         * was authenticated or not.
         */
            || !strcasecmp(reqhdrs_elts[i].key, "Proxy-Authorization"))
            continue;
        ap_bvputs(f, reqhdrs_elts[i].key, ": ", reqhdrs_elts[i].val, CRLF, NULL);
    }

    /* the obligatory empty line to mark the end of the headers */
    ap_bputs(CRLF, f);

    /* and flush the above away */
    ap_bflush(f);

    /* and kill the send timeout */
    ap_kill_timeout(r);


    /* read the request data, and pass it to the backend.
     * we might encounter a stray 100-continue reponse from a PUT or POST,
     * if this happens we ignore the 100 continue status line and read the
     * response again.
     */
    {
        /* send the request data, if any. */
        ap_hard_timeout("proxy receive request data", r);
        if (ap_should_client_block(r)) {
            while ((i = ap_get_client_block(r, buffer, sizeof buffer)) > 0) {
                ap_reset_timeout(r);
                ap_bwrite(f, buffer, i);
            }
        }
        ap_bflush(f);
        ap_kill_timeout(r);


        /* then, read a response line */
        ap_hard_timeout("proxy receive response status line", r);
        result = ap_proxy_read_response_line(f, r, buffer, sizeof(buffer)-1, &backasswards, &major, &minor);
        ap_kill_timeout(r);

        /* trap any errors */
        if (result != OK) {
            ap_bclose(f);
            return result;
        }

        /* if this response was 100-continue, a stray response has been caught.
         * read the line again for the real response
         */
        if (r->status == 100) {
            ap_hard_timeout("proxy receive response status line", r);
            result = ap_proxy_read_response_line(f, r, buffer, sizeof(buffer)-1, &backasswards, &major, &minor);
            ap_kill_timeout(r);

            /* trap any errors */
            if (result != OK) {
                ap_bclose(f);
                return result;
            }
        }
    }


    /*
     * We have our response status line from the convoluted code above,
     * now we read the headers to continue.
     */
    ap_hard_timeout("proxy receive response headers", r);

    /*
     * Is it an HTTP/1 response? Do some sanity checks on the response. (This
     * is buggy if we ever see an HTTP/1.10)
     */
    if (backasswards == 0) {

        /* read the response headers. */
        /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */
        /* Also, take care with headers with multiple occurences. */

        resp_hdrs = ap_proxy_read_headers(r, buffer, sizeof(buffer), f);
        if (resp_hdrs == NULL) {
            ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_NOERRNO, r->server,
                         "proxy: Bad HTTP/%d.%d header returned by %s (%s)",
                         major, minor, r->uri, r->method);
            resp_hdrs = ap_make_table(p, 20);
            nocache = 1;        /* do not cache this broken file */
        }

        /* handle Via header in the response */
        if (conf->viaopt != via_off && conf->viaopt != via_block) {
            /* Create a "Via:" response header entry and merge it */
            i = ap_get_server_port(r);
            if (ap_is_default_port(i, r)) {
                strlcpy(portstr, "", sizeof(portstr));
            }
            else {
                ap_snprintf(portstr, sizeof portstr, ":%d", i);
            }
            ap_table_mergen((table *)resp_hdrs, "Via",
                            (conf->viaopt == via_full)
                            ? ap_psprintf(p, "%d.%d %s%s (%s)",
                                          major, minor,
                                          ap_get_server_name(r), portstr,
                                          SERVER_BASEVERSION)
                            : ap_psprintf(p, "%d.%d %s%s",
                                          major, minor,
                                          ap_get_server_name(r), portstr)
                );
        }

        /* is this content chunked? */
        chunked = ap_find_last_token(r->pool,
                                     ap_table_get(resp_hdrs, "Transfer-Encoding"),
                                     "chunked");

        /* strip hop-by-hop headers defined by Connection and RFC2616 */
        ap_proxy_clear_connection(p, resp_hdrs);

        content_length = ap_table_get(resp_hdrs, "Content-Length");
        if (content_length != NULL) {
            c->len = ap_strtol(content_length, NULL, 10);

	    if (c->len < 0) {
		ap_kill_timeout(r);
		return ap_proxyerror(r, HTTP_BAD_GATEWAY, ap_pstrcat(r->pool,
				     "Invalid Content-Length from remote server",
                                      NULL));
	    }
        }

    }
    else {
        /* an http/0.9 response */

        /* no headers */
        resp_hdrs = ap_make_table(p, 20);
    }

    ap_kill_timeout(r);

    /*
     * HTTP/1.1 requires us to accept 3 types of dates, but only generate one
     * type
     */
    /*
     * we SET the dates here, obliterating possible multiple dates, as only
     * one of each date makes sense in each response.
     */
    if ((datestr = ap_table_get(resp_hdrs, "Date")) != NULL)
        ap_table_set(resp_hdrs, "Date", ap_proxy_date_canon(p, datestr));
    if ((datestr = ap_table_get(resp_hdrs, "Last-Modified")) != NULL)
        ap_table_set(resp_hdrs, "Last-Modified", ap_proxy_date_canon(p, datestr));
    if ((datestr = ap_table_get(resp_hdrs, "Expires")) != NULL)
        ap_table_set(resp_hdrs, "Expires", ap_proxy_date_canon(p, datestr));

    /* handle the ProxyPassReverse mappings */
    if ((urlstr = ap_table_get(resp_hdrs, "Location")) != NULL)
        ap_table_set(resp_hdrs, "Location", proxy_location_reverse_map(r, urlstr));
    if ((urlstr = ap_table_get(resp_hdrs, "URI")) != NULL)
        ap_table_set(resp_hdrs, "URI", proxy_location_reverse_map(r, urlstr));
    if ((urlstr = ap_table_get(resp_hdrs, "Content-Location")) != NULL)
        ap_table_set(resp_hdrs, "Content-Location", proxy_location_reverse_map(r, urlstr));

/* check if NoCache directive on this host */
  {
    struct sockaddr_in *sin;
    struct sockaddr_in6 *sin6;

    if (nocache == 0) {
	for (i = 0; i < conf->nocaches->nelts; i++) {
	    if (ncent[i].name != NULL && 
		(ncent[i].name[0] == '*' ||
		 strstr(desthost, ncent[i].name) != NULL)) {
		nocache = 1;
		break;
	    }
	    switch (res->ai_addr->sa_family) {
	    case AF_INET:
		sin = (struct sockaddr_in *)res->ai_addr;
		if (sin->sin_addr.s_addr == ncent[i].addr.s_addr) {
		    nocache = 1;
		    break;
		}
	    }
	}

        /* update the cache file, possibly even fulfilling the request if
         * it turns out a conditional allowed us to serve the object from the
         * cache...
         */
        i = ap_proxy_cache_update(c, resp_hdrs, !backasswards, nocache);
        if (i != DECLINED) {
            ap_bclose(f);
            return i;
        }

        /* write status line and headers to the cache file */
        ap_proxy_write_headers(c, ap_pstrcat(p, "HTTP/1.1 ", r->status_line, NULL), resp_hdrs);
    }
  }

    /* Setup the headers for our client from upstreams response-headers */
    ap_proxy_table_replace(r->headers_out, resp_hdrs);
    /* Add X-Cache header - be careful not to obliterate any upstream headers */
    ap_table_mergen(r->headers_out, "X-Cache",
                    ap_pstrcat(r->pool, "MISS from ",
                               ap_get_server_name(r), NULL));
    /* The Content-Type of this response is the upstream one. */
    r->content_type = ap_table_get(r->headers_out, "Content-Type");
    ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server, "Content-Type: %s", r->content_type);

    /* finally output the headers to the client */
    ap_send_http_header(r);

    /*
     * Is it an HTTP/0.9 respose? If so, send the extra data we read from
     * upstream as the start of the reponse to client
     */
/* FIXME: This code is broken: we try and write a buffer and length that
 * were never intelligently initialised. Rather have a bit of broken protocol
 * handling for now than broken code.
 */
/*
    if (backasswards) {
        ap_hard_timeout("proxy send assbackward", r);

        ap_bwrite(r->connection->client, buffer, len);
        if (c != NULL && c->fp != NULL && ap_bwrite(c->fp, buffer, len) != len) {
            ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
                      "proxy: error writing extra data to %s", c->tempfile);
            c = ap_proxy_cache_error(c);
        }
        ap_kill_timeout(r);
    }
*/

/* send body */
/* if header only, then cache will be NULL */
/* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */
/* XXX CHANGEME: We want to eventually support keepalives, which means
 * we must read content-length bytes... */
    if (!r->header_only) {
/* we need to set this for ap_proxy_send_fb()... */
        c->cache_completion = conf->cache.cache_completion;

/* XXX CHECKME: c->len should be the expected content length, or -1 if the
 * content length is not known. We need to make 100% sure c->len is always
 * set correctly before we get here to correctly do keepalive.
 */
        ap_proxy_send_fb(f, r, c, c->len, 0, chunked, conf->io_buffer_size);
    }

    /* ap_proxy_send_fb() closes the socket f for us */

    ap_proxy_cache_tidy(c);

    ap_proxy_garbage_coll(r);
    return OK;
}
Ejemplo n.º 30
0
/*
** dav_load_lock_record:  Reads lock information about key from lock db;
**    creates linked lists of the direct and indirect locks.
**
**    If add_method = DAV_APPEND_LIST, the result will be appended to the
**    head of the direct and indirect lists supplied.
**
**    Passive lock removal:  If lock has timed out, it will not be returned.
**    ### How much "logging" does RFC 2518 require?
*/
static dav_error * dav_fs_load_lock_record(dav_lockdb *lockdb, dav_datum key,
					   int add_method,
					   dav_lock_discovery **direct,
					   dav_lock_indirect **indirect)
{
    dav_error *err;
    size_t offset = 0;
    int need_save = DAV_FALSE;
    dav_datum val = { 0 };
    dav_lock_discovery *dp;
    dav_lock_indirect *ip;
    dav_buffer buf = { 0 };

    if (add_method != DAV_APPEND_LIST) {
	*direct = NULL;
	*indirect = NULL;
    }

    if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) {
	/* ### add a higher-level error? */
	return err;
    }

    /*
    ** If we opened readonly and the db wasn't there, then there are no
    ** locks for this resource. Just exit.
    */
    if (lockdb->info->db == NULL)
	return NULL;

    if ((err = (*dav_hooks_db_dbm.fetch)(lockdb->info->db, key, &val)) != NULL)
        return err;
	
    if (!val.dsize)
	return NULL;

    while (offset < val.dsize) {
	switch (*(val.dptr + offset++)) {
	case DAV_LOCK_DIRECT:
	    /* Create and fill a dav_lock_discovery structure */

	    dp = ap_pcalloc(lockdb->info->pool, sizeof(*dp));
	    memcpy(dp, val.dptr + offset, sizeof(dp->f));
	    offset += sizeof(dp->f);
            dp->locktoken = ap_palloc(lockdb->info->pool, sizeof(*dp->locktoken));
            memcpy(dp->locktoken, val.dptr + offset, sizeof(*dp->locktoken));
            offset += sizeof(*dp->locktoken);
	    if (*(val.dptr + offset) == '\0') {
		++offset;
	    }
	    else {
		dp->owner = ap_pstrdup(lockdb->info->pool, val.dptr + offset);
		offset += strlen(dp->owner) + 1;
	    }

            if (*(val.dptr + offset) == '\0') {
                ++offset;
            } 
            else {
                dp->auth_user = ap_pstrdup(lockdb->info->pool, val.dptr + offset);
                offset += strlen(dp->auth_user) + 1;
            }

	    if (!dav_fs_lock_expired(dp->f.timeout)) {
		dp->next = *direct;
		*direct = dp;
	    }
	    else {
		need_save = DAV_TRUE;

		/* Remove timed-out locknull fm .locknull list */
		if (*key.dptr == DAV_TYPE_FNAME) {
		    const char *fname = key.dptr + 1;
		    struct stat finfo;

		    /* if we don't see the file, then it's a locknull */
		    if (lstat(fname, &finfo) != 0) {
			if ((err = dav_fs_remove_locknull_member(lockdb->info->pool, fname, &buf)) != NULL) {
                            /* ### push a higher-level description? */
                            return err;
                        }
		    }
		}
	    }
	    break;

	case DAV_LOCK_INDIRECT:
	    /* Create and fill a dav_lock_indirect structure */

	    ip = ap_pcalloc(lockdb->info->pool, sizeof(*ip));
            ip->locktoken = ap_palloc(lockdb->info->pool, sizeof(*ip->locktoken));
	    memcpy(ip->locktoken, val.dptr + offset, sizeof(*ip->locktoken));
	    offset += sizeof(*ip->locktoken);
	    memcpy(&ip->timeout, val.dptr + offset, sizeof(ip->timeout));
	    offset += sizeof(ip->timeout);
	    memcpy(&ip->key.dsize, val.dptr + offset, sizeof(int)); /* length of datum */
	    offset += sizeof(ip->key.dsize);
	    ip->key.dptr = ap_palloc(lockdb->info->pool, ip->key.dsize); 
	    memcpy(ip->key.dptr, val.dptr + offset, ip->key.dsize);
	    offset += ip->key.dsize;

	    if (!dav_fs_lock_expired(ip->timeout)) {
		ip->next = *indirect;
		*indirect = ip;
	    }
	    else {
		need_save = DAV_TRUE;
		/* A locknull resource will never be locked indirectly */
	    }

	    break;

	default:
	    (*dav_hooks_db_dbm.freedatum)(lockdb->info->db, val);

	    /* ### should use a computed_desc and insert corrupt token data */
	    --offset;
	    return dav_new_error(lockdb->info->pool,
				 HTTP_INTERNAL_SERVER_ERROR,
				 DAV_ERR_LOCK_CORRUPT_DB,
				 ap_psprintf(lockdb->info->pool,
					     "The lock database was found to "
					     "be corrupt. offset %i, c=%02x",
					     offset, val.dptr[offset]));
	}
    }

    (*dav_hooks_db_dbm.freedatum)(lockdb->info->db, val);

    /* Clean up this record if we found expired locks */
    /*
    ** ### shouldn't do this if we've been opened READONLY. elide the
    ** ### timed-out locks from the response, but don't save that info back
    */
    if (need_save == DAV_TRUE) {
	return dav_fs_save_lock_record(lockdb, key, *direct, *indirect);
    }

    return NULL;
}