Example #1
0
/**
 * Parse an Alt-Svc specifier as described in "HTTP Alternative Services"
 * (https://tools.ietf.org/html/draft-ietf-httpbis-alt-svc-04)
 * with the following changes:
 * - do not percent encode token values
 * - do not use quotation marks
 */
h2_alt_svc *h2_alt_svc_parse(const char *s, apr_pool_t *pool) {
    const char *sep = ap_strchr_c(s, '=');
    if (sep) {
        const char *alpn = apr_pstrndup(pool, s, sep - s);
        const char *host = NULL;
        int port = 0;
        s = sep + 1;
        sep = ap_strchr_c(s, ':');  /* mandatory : */
        if (sep) {
            if (sep != s) {    /* optional host */
                host = apr_pstrndup(pool, s, sep - s);
            }
            s = sep + 1;
            if (*s) {          /* must be a port number */
                port = (int)apr_atoi64(s);
                if (port > 0 && port < (0x1 << 16)) {
                    h2_alt_svc *as = apr_pcalloc(pool, sizeof(*as));
                    as->alpn = alpn;
                    as->host = host;
                    as->port = port;
                    return as;
                }
            }
        }
    }
    return NULL;
}
Example #2
0
static const char * skip_to_start(saxctxt *ctxt, const char **bufp, apr_size_t *bytes)
{
  char *p = ap_strchr_c(*bufp, '<');
  tattr *starts = (tattr *) ctxt->cfg->skipto->elts;
  int found = 0;
  while (!found && *p) {
    int i;
    for (i = 0; i < ctxt->cfg->skipto->nelts; ++i) {
      if (!strncasecmp(p + 1, starts[i].val, strlen(starts[i].val))) {
        *bytes -= (p - *bufp);
        *bufp = p;
        found = 1;
        ap_log_error(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, ctxt->f->r->server,
                     "skip_to_start: skipped to first <%s> element", starts[i].val);
        break;
      }
    }
    p = ap_strchr_c(p + 1, '<');
  }
  if (p == NULL) {
    ap_log_error(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, ctxt->f->r->server,
                 "skip_to_start: failed to find start of recognised HTML!");
  }
  return *bufp;
}
Example #3
0
/**
 * Sanity check a given string that it exists, is not empty,
 * and does not contain the special characters '=', ';' and '&'.
 *
 * It is used to sanity check the cookie names.
 */
AP_DECLARE(apr_status_t) ap_cookie_check_string(const char *string)
{
    if (!string || !*string || ap_strchr_c(string, '=') || ap_strchr_c(string, '&') ||
        ap_strchr_c(string, ';')) {
        return APR_EGENERAL;
    }
    return APR_SUCCESS;
}
Example #4
0
static authn_status check_anonymous(request_rec *r, const char *user,
                                    const char *sent_pw)
{
    authn_anon_config_rec *conf = ap_get_module_config(r->per_dir_config,
                                                      &authn_anon_module);
    authn_status res = AUTH_USER_NOT_FOUND;

    /* Ignore if we are not configured */
    if (!conf->users && !conf->anyuserid) {
        return AUTH_USER_NOT_FOUND;
    }

    /* Do we allow an empty userID and/or is it the magic one
     */
    if (!*user) {
        if (conf->nouserid) {
            res = AUTH_USER_FOUND;
        }
    }
    else if (conf->anyuserid) {
        res = AUTH_USER_FOUND;
    }
    else {
        anon_auth_user *p = conf->users;

        while (p) {
            if (!strcasecmp(user, p->user)) {
                res = AUTH_USER_FOUND;
                break;
            }
            p = p->next;
        }
    }

    /* Now if the supplied user-ID was ok, grant access if:
     * (a) no passwd was sent and no password and no verification
     *     were configured.
     * (b) password was sent and no verification was configured
     * (c) verification was configured and the password (sent or not)
     *     looks like an email address
     */
    if (   (res == AUTH_USER_FOUND)
        && (!conf->mustemail || *sent_pw)
        && (   !conf->verifyemail
            || (ap_strchr_c(sent_pw, '@') && ap_strchr_c(sent_pw, '.'))))
    {
        if (conf->logemail && ap_is_initial_req(r)) {
            ap_log_rerror(APLOG_MARK, APLOG_INFO, APR_SUCCESS, r, APLOGNO(01672)
                          "Anonymous: Passwd <%s> Accepted",
                          sent_pw ? sent_pw : "\'none\'");
        }

        return AUTH_GRANTED;
    }

    return (res == AUTH_USER_NOT_FOUND ? res : AUTH_DENIED);
}
Example #5
0
static int oidc_session_unescape_url(char *url, const char *forbid,
		const char *reserved) {
	register int badesc, badpath;
	char *x, *y;

	badesc = 0;
	badpath = 0;
	/* Initial scan for first '%'. Don't bother writing values before
	 * seeing a '%' */
	y = strchr(url, '%');
	if (y == NULL) {
		return OK;
	}
	for (x = y; *y; ++x, ++y) {
		if (*y != '%') {
			*x = *y;
		} else {
			if (!apr_isxdigit(*(y + 1)) || !apr_isxdigit(*(y + 2))) {
				badesc = 1;
				*x = '%';
			} else {
				char decoded;
				decoded = x2c(y + 1);
				if ((decoded == '\0')
						|| (forbid && ap_strchr_c(forbid, decoded))) {
					badpath = 1;
					*x = decoded;
					y += 2;
				} else if (reserved && ap_strchr_c(reserved, decoded)) {
					*x++ = *y++;
					*x++ = *y++;
					*x = *y;
				} else {
					*x = decoded;
					y += 2;
				}
			}
		}
	}
	*x = '\0';
	if (badesc) {
		return HTTP_BAD_REQUEST;
	} else if (badpath) {
		return HTTP_NOT_FOUND;
	} else {
		return OK;
	}
}
Example #6
0
apr_status_t h2_request_rwrite(h2_request *req, request_rec *r)
{
    apr_status_t status;
    
    req->config    = h2_config_rget(r);
    req->method    = r->method;
    req->scheme    = (r->parsed_uri.scheme? r->parsed_uri.scheme
                      : ap_http_scheme(r));
    req->authority = r->hostname;
    req->path      = apr_uri_unparse(r->pool, &r->parsed_uri, 
                                     APR_URI_UNP_OMITSITEPART);

    if (!ap_strchr_c(req->authority, ':') && r->server && r->server->port) {
        apr_port_t defport = apr_uri_port_of_scheme(req->scheme);
        if (defport != r->server->port) {
            /* port info missing and port is not default for scheme: append */
            req->authority = apr_psprintf(r->pool, "%s:%d", req->authority,
                                          (int)r->server->port);
        }
    }
    
    AP_DEBUG_ASSERT(req->scheme);
    AP_DEBUG_ASSERT(req->authority);
    AP_DEBUG_ASSERT(req->path);
    AP_DEBUG_ASSERT(req->method);

    status = add_all_h1_header(req, r->pool, r->headers_in);

    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, status, r,
                  "h2_request(%d): rwrite %s host=%s://%s%s",
                  req->id, req->method, req->scheme, req->authority, req->path);
                  
    return status;
}
Example #7
0
static const char *dso_load(cmd_parms *cmd, apr_dso_handle_t **modhandlep,
                            const char *filename, const char **used_filename)
{
    int retry = 0;
    const char *fullname = ap_server_root_relative(cmd->temp_pool, filename);
    char my_error[256];
    if (filename != NULL && ap_strchr_c(filename, '/') == NULL) {
        /* retry on error without path to use dlopen()'s search path */
        retry = 1;
    }

    if (fullname == NULL && !retry) {
        return apr_psprintf(cmd->temp_pool, "Invalid %s path %s",
                            cmd->cmd->name, filename);
    }
    *used_filename = fullname;
    if (apr_dso_load(modhandlep, fullname, cmd->pool) == APR_SUCCESS) {
        return NULL;
    }
    if (retry) {
        *used_filename = filename;
        if (apr_dso_load(modhandlep, filename, cmd->pool) == APR_SUCCESS)
            return NULL;
    }

    return apr_pstrcat(cmd->temp_pool, "Cannot load ", filename,
                        " into server: ",
                        apr_dso_error(*modhandlep, my_error, sizeof(my_error)),
                        NULL);
}
Example #8
0
/* Registration function for extract functions *
 * and update parse cache for transfer_log_format *
 * this is exported from the module */
LOGSQL_DECLARE(void) log_sql_register_item(server_rec *s, apr_pool_t *p,
		char key, logsql_item_func *func, const char *sql_field_name,
		int want_orig_default, int string_contents)
{
	server_rec *ts;
	logsql_item *item;
	if (!logsql_item_list)
		logsql_item_list = apr_array_make(p,10, sizeof(logsql_item));

	item= apr_array_push(logsql_item_list);
	item->key = key;
	item->func = func;
	item->sql_field_name = sql_field_name;
	item->want_orig_default = want_orig_default;
	item->string_contents = string_contents;
	/* some voodoo here to post parse logitems in all servers *
	 * so a "cached" list is used in the main logging loop for speed */
	for (ts = s; ts; ts = ts->next) {
		logsql_state *cfg = ap_get_module_config(ts->module_config,
								&log_sql_module);
		char *pos;

		if (cfg->transfer_log_format) {
			if ( (pos = ap_strchr_c(cfg->transfer_log_format,key))!=NULL) {
				cfg->parsed_log_format[pos - cfg->transfer_log_format] = item;
			}
		}
	}
}
Example #9
0
/* return each comma separated token, one at a time */
CACHE_DECLARE(const char *)ap_cache_tokstr(apr_pool_t *p, const char *list,
                                           const char **str)
{
    apr_size_t i;
    const char *s;

    s = ap_strchr_c(list, ',');
    if (s != NULL) {
        i = s - list;
        do
            s++;
        while (apr_isspace(*s))
            ; /* noop */
    }
    else
        i = strlen(list);

    while (i > 0 && apr_isspace(list[i - 1]))
        i--;

    *str = s;
    if (i)
        return apr_pstrndup(p, list, i);
    else
        return NULL;
}
Example #10
0
/*
 * Canonicalise http-like URLs.
 * scheme is the scheme for the URL
 * url is the URL starting with the first '/'
 * def_port is the default port for this scheme.
 */
static int proxy_ajp_canon(request_rec *r, char *url)
{
    char *host, *path, sport[7];
    char *search = NULL;
    const char *err;
    apr_port_t port = AJP13_DEF_PORT;

    /* ap_port_of_scheme() */
    if (strncasecmp(url, "ajp:", 4) == 0) {
        url += 4;
    }
    else {
        return DECLINED;
    }

    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
             "proxy: AJP: canonicalising URL %s", url);

    /*
     * do syntactic check.
     * We break the URL into host, port, path, search
     */
    err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
    if (err) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                      "error parsing URL %s: %s",
                      url, err);
        return HTTP_BAD_REQUEST;
    }

    /*
     * now parse path/search args, according to rfc1738:
     * process the path. With proxy-noncanon set (by
     * mod_proxy) we use the raw, unparsed uri
     */
    if (apr_table_get(r->notes, "proxy-nocanon")) {
        path = url;   /* this is the raw path */
    }
    else {
        path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
                                 r->proxyreq);
        search = r->args;
    }
    if (path == NULL)
        return HTTP_BAD_REQUEST;

    apr_snprintf(sport, sizeof(sport), ":%d", port);

    if (ap_strchr_c(host, ':')) {
        /* if literal IPv6 address */
        host = apr_pstrcat(r->pool, "[", host, "]", NULL);
    }
    r->filename = apr_pstrcat(r->pool, "proxy:ajp://", host, sport,
                              "/", path, (search) ? "?" : "",
                              (search) ? search : "", NULL);
    return OK;
}
Example #11
0
static int req_mime_types(lua_State *L)
{
  request_rec *r = CHECK_REQUEST_OBJECT(1);
  apr_pool_t *p = r->connection->base_server->process->pool;
  const char* resource_name = luaL_checkstring(L, 2);
  int set = lua_isnoneornil(L, 3) ? 0 : lua_toboolean(L, 3);
  apr_hash_t *mimes = NULL;
  apr_status_t rc = apr_pool_userdata_get((void**)&mimes, "mod_luaex", p);
  const char* fn, *ext, *fntmp;
  const char* type = NULL;

  if (rc == APR_SUCCESS && mimes)
  {
    if ((fn = ap_strrchr_c(resource_name, '/')) == NULL)
    {
      fn = resource_name;
    }
    else
    {
      ++fn;
    }
    /* Always drop the path leading up to the file name. */

    /* The exception list keeps track of those filename components that
     * are not associated with extensions indicating metadata.
     * The base name is always the first exception (i.e., "txt.html" has
     * a basename of "txt" even though it might look like an extension).
     * Leading dots are considered to be part of the base name (a file named
     * ".png" is likely not a png file but just a hidden file called png).
     */
    fntmp = fn;
    while (*fntmp == '.')
      fntmp++;
    fntmp = ap_strchr_c(fntmp, '.');
    if (fntmp)
    {
      fn = fntmp + 1;
      ext = apr_pstrdup(r->pool, fn);
    }
    else
    {
      ext = apr_pstrdup(r->pool, fn);
      fn += strlen(fn);
    }

    if (set && (type = apr_hash_get(mimes, ext, APR_HASH_KEY_STRING)) != NULL)
    {
      ap_set_content_type(r, (char*) type);
    }
  }
  if (type)
    lua_pushstring(L, type);
  else
    lua_pushnil(L);

  return 1;
}
Example #12
0
static const char *cmd_advertise_f(cmd_parms *cmd, void *dummy,
                                   const char *arg)
{
    apr_time_t s, u = 0;
    const char *p;

    mod_advertise_config *mconf = ap_get_module_config(cmd->server->module_config, &advertise_module);
    if (mconf->ma_advertise_freq != MA_DEFAULT_ADV_FREQ)
        return "Duplicate AdvertiseFrequency directives are not allowed";
    if ((p = ap_strchr_c(arg, '.')) || (p = ap_strchr_c(arg, ',')))
        u = atoi(p + 1);

    s = atoi(arg);
    mconf->ma_advertise_freq = s * APR_USEC_PER_SEC + u * APR_TIME_C(1000);
    if (mconf->ma_advertise_freq == 0)
        return "Invalid AdvertiseFrequency value";

    mconf->ma_advertise_server = cmd->server;
    return NULL;
}
/* apr:network_io/unix/sockaddr.c */
static int looks_like_ip(const char *ipstr)
{
    if (ap_strchr_c(ipstr, ':')) {
        /* definitely not a hostname; assume it is intended to be an IPv6 address */
        return 1;
    }

    /* simple IPv4 address string check */
    while ((*ipstr == '.') || apr_isdigit(*ipstr))
        ipstr++;
    return (*ipstr == '\0');
}
static apr_status_t default_build_command(const char **cmd, const char ***argv,
                                          request_rec *r, apr_pool_t *p,
                                          cgi_exec_info_t *e_info)
{
    int numwords, x, idx;
    char *w;
    const char *args = NULL;

    if (e_info->process_cgi) {
        *cmd = r->filename;
        /* Do not process r->args if they contain an '=' assignment
         */
        if (r->args && r->args[0] && !ap_strchr_c(r->args, '=')) {
            args = r->args;
        }
    }

    if (!args) {
        numwords = 1;
    }
    else {
        /* count the number of keywords */
        for (x = 0, numwords = 2; args[x]; x++) {
            if (args[x] == '+') {
                ++numwords;
            }
        }
    }
    /* Everything is - 1 to account for the first parameter
     * which is the program name.
     */
    if (numwords > APACHE_ARG_MAX - 1) {
        numwords = APACHE_ARG_MAX - 1;    /* Truncate args to prevent overrun */
    }
    *argv = apr_palloc(p, (numwords + 2) * sizeof(char *));
    (*argv)[0] = *cmd;
    for (x = 1, idx = 1; x < numwords; x++) {
        w = ap_getword_nulls(p, &args, '+');
        ap_unescape_url(w);
        (*argv)[idx++] = ap_escape_shell_cmd(p, w);
    }
    (*argv)[idx] = NULL;

    return APR_SUCCESS;
}
Example #15
0
static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname,
                                        const char *var)
{
    const char *ptr;
    char *result;
    X509_NAME_ENTRY *xsne;
    int i, j, n, idx = 0, raw = 0;
    apr_size_t varlen;

    ptr = ap_strrchr_c(var, '_');
    if (ptr && ptr > var && strcmp(ptr + 1, "RAW") == 0) {
        var = apr_pstrmemdup(p, var, ptr - var);
        raw = 1;
    }
    
    /* if an _N suffix is used, find the Nth attribute of given name */
    ptr = ap_strchr_c(var, '_');
    if (ptr != NULL && strspn(ptr + 1, "0123456789") == strlen(ptr + 1)) {
        idx = atoi(ptr + 1);
        varlen = ptr - var;
    } else {
        varlen = strlen(var);
    }

    result = NULL;

    for (i = 0; ssl_var_lookup_ssl_cert_dn_rec[i].name != NULL; i++) {
        if (strEQn(var, ssl_var_lookup_ssl_cert_dn_rec[i].name, varlen)
            && strlen(ssl_var_lookup_ssl_cert_dn_rec[i].name) == varlen) {
            for (j = 0; j < X509_NAME_entry_count(xsname); j++) {
                xsne = X509_NAME_get_entry(xsname, j);

                n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne));

                if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid && idx-- == 0) {
                    result = modssl_X509_NAME_ENTRY_to_string(p, xsne, raw);
                    break;
                }
            }
            break;
        }
    }
    return result;
}
Example #16
0
static int rewrite_url(request_rec *r, proxy_worker *worker,
                        char **url)
{
    const char *scheme = strstr(*url, "://");
    const char *path = NULL;

    if (scheme)
        path = ap_strchr_c(scheme + 3, '/');

    /* we break the URL into host, port, uri */
    if (!worker) {
        return ap_proxyerror(r, HTTP_BAD_REQUEST, apr_pstrcat(r->pool,
                             "missing worker. URI cannot be parsed: ", *url,
                             NULL));
    }

    *url = apr_pstrcat(r->pool, worker->name, path, NULL);

    return OK;
}
Example #17
0
static const char *add_env_module_vars_set(cmd_parms *cmd, void *sconf_,
                                           const char *name, const char *value)
{
    env_dir_config_rec *sconf = sconf_;

    if (ap_strchr_c(name, '=')) {
        char *env, *plast;

        env = apr_strtok(apr_pstrdup(cmd->temp_pool, name), "=", &plast);

        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(10032)
                     "Spurious usage of '=' in an environment variable name. "
                     "'%s %s %s' expected instead?", cmd->cmd->name, env, plast);
    }

    /* name is mandatory, value is optional.  no value means
     * set the variable to an empty string
     */
    apr_table_setn(sconf->vars, name, value ? value : "");

    return NULL;
}
Example #18
0
/*
 * Set the value for the 'Domain=' attribute.
 */
static const char *set_cookie_domain(cmd_parms *cmd, void *mconfig,
                                     const char *name)
{
    cookie_dir_rec *dcfg;

    dcfg = (cookie_dir_rec *) mconfig;

    /*
     * Apply the restrictions on cookie domain attributes.
     */
    if (!name[0]) {
        return "CookieDomain values may not be null";
    }
    if (name[0] != '.') {
        return "CookieDomain values must begin with a dot";
    }
    if (ap_strchr_c(&name[1], '.') == NULL) {
        return "CookieDomain values must contain at least one embedded dot";
    }

    dcfg->cookie_domain = name;
    return NULL;
}
Example #19
0
static void dav_set_name(dav_db *db, dav_prop_name *pname)
{
    const char *s = db->iter.dptr;

    if (s == NULL) {
        pname->ns = pname->name = NULL;
    }
    else if (*s == ':') {
        pname->ns = "";
        pname->name = s + 1;
    }
    else {
        int id = atoi(s);

        pname->ns = dav_get_ns_table_uri(db, id);
        if (s[1] == ':') {
            pname->name = s + 2;
        }
        else {
            pname->name = ap_strchr_c(s + 2, ':') + 1;
        }
    }
}
Example #20
0
/**
 * find value for parameter with certain name
 * @param p pool to allocate from
 * @param name name of the attribute
 * @param string string with name=value pairs separated by ";",
 *        value may be a quoted string delimited by double quotes
 * @param end pointer where to stop searching
 * @note string must be NUL-terminated (but the NUL may be after *end)
 * @return copy of the value, NULL if not found
 */
static char *mbox_mime_get_parameter(apr_pool_t *p, const char *name,
                                     const char *string, const char *end)
{
    const char *ptr = string;
    int namelen = strlen(name);
    while (ptr && *ptr && ptr < end) {
        int have_match = 0;
        const char *val_end;
        while (*ptr && (apr_isspace(*ptr) || *ptr == ';'))
            ptr++;
        if (strncasecmp(ptr, name, namelen) == 0) {
            ptr += strlen(name);
            while (*ptr && apr_isspace(*ptr) && ptr < end)
                ptr++;
            if (*ptr == '=') {
                have_match = 1;
                ptr++;
                if (ptr >= end)
                    break;
                while (*ptr && apr_isspace(*ptr) && ptr < end)
                    ptr++;
            }
        }
        if (!have_match)
            ptr += strcspn(ptr, ";= \t");
        if (*ptr == '"')
            val_end = ap_strchr_c(++ptr, '"');
        else
            val_end = ptr + strcspn(ptr, ";\n ");
        if (!val_end || val_end > end)
            val_end = end;
        if (have_match)
            return apr_pstrmemdup(p, ptr, val_end - ptr);
        ptr = val_end + 1;
    }
    return NULL;
}
static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
        const char *uri, apr_uri_t *parsed_uri, const char **key)
{
    cache_server_conf *conf;
    char *port_str, *hn, *lcs;
    const char *hostname, *scheme;
    int i;
    const char *path;
    char *querystring;

    if (*key) {
        /*
         * We have been here before during the processing of this request.
         */
        return APR_SUCCESS;
    }

    /*
     * Get the module configuration. We need this for the CacheIgnoreQueryString
     * option below.
     */
    conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
            &cache_module);

    /*
     * Use the canonical name to improve cache hit rate, but only if this is
     * not a proxy request or if this is a reverse proxy request.
     * We need to handle both cases in the same manner as for the reverse proxy
     * case we have the following situation:
     *
     * If a cached entry is looked up by mod_cache's quick handler r->proxyreq
     * is still unset in the reverse proxy case as it only gets set in the
     * translate name hook (either by ProxyPass or mod_rewrite) which is run
     * after the quick handler hook. This is different to the forward proxy
     * case where it gets set before the quick handler is run (in the
     * post_read_request hook).
     * If a cache entry is created by the CACHE_SAVE filter we always have
     * r->proxyreq set correctly.
     * So we must ensure that in the reverse proxy case we use the same code
     * path and using the canonical name seems to be the right thing to do
     * in the reverse proxy case.
     */
    if (!r->proxyreq || (r->proxyreq == PROXYREQ_REVERSE)) {
        if (conf->base_uri && conf->base_uri->hostname) {
            hostname = conf->base_uri->hostname;
        }
        else {
            /* Use _default_ as the hostname if none present, as in mod_vhost */
            hostname = ap_get_server_name(r);
            if (!hostname) {
                hostname = "_default_";
            }
        }
    }
    else if (parsed_uri->hostname) {
        /* Copy the parsed uri hostname */
        hn = apr_pstrdup(p, parsed_uri->hostname);
        ap_str_tolower(hn);
        /* const work-around */
        hostname = hn;
    }
    else {
        /* We are a proxied request, with no hostname. Unlikely
         * to get very far - but just in case */
        hostname = "_default_";
    }

    /*
     * Copy the scheme, ensuring that it is lower case. If the parsed uri
     * contains no string or if this is not a proxy request get the http
     * scheme for this request. As r->parsed_uri.scheme is not set if this
     * is a reverse proxy request, it is ensured that the cases
     * "no proxy request" and "reverse proxy request" are handled in the same
     * manner (see above why this is needed).
     */
    if (r->proxyreq && parsed_uri->scheme) {
        /* Copy the scheme and lower-case it */
        lcs = apr_pstrdup(p, parsed_uri->scheme);
        ap_str_tolower(lcs);
        /* const work-around */
        scheme = lcs;
    }
    else {
        if (conf->base_uri && conf->base_uri->scheme) {
            scheme = conf->base_uri->scheme;
        }
        else {
            scheme = ap_http_scheme(r);
        }
    }

    /*
     * If this is a proxy request, but not a reverse proxy request (see comment
     * above why these cases must be handled in the same manner), copy the
     * URI's port-string (which may be a service name). If the URI contains
     * no port-string, use apr-util's notion of the default port for that
     * scheme - if available. Otherwise use the port-number of the current
     * server.
     */
    if (r->proxyreq && (r->proxyreq != PROXYREQ_REVERSE)) {
        if (parsed_uri->port_str) {
            port_str = apr_pcalloc(p, strlen(parsed_uri->port_str) + 2);
            port_str[0] = ':';
            for (i = 0; parsed_uri->port_str[i]; i++) {
                port_str[i + 1] = apr_tolower(parsed_uri->port_str[i]);
            }
        }
        else if (apr_uri_port_of_scheme(scheme)) {
            port_str = apr_psprintf(p, ":%u", apr_uri_port_of_scheme(scheme));
        }
        else {
            /* No port string given in the AbsoluteUri, and we have no
             * idea what the default port for the scheme is. Leave it
             * blank and live with the inefficiency of some extra cached
             * entities.
             */
            port_str = "";
        }
    }
    else {
        if (conf->base_uri && conf->base_uri->port_str) {
            port_str = conf->base_uri->port_str;
        }
        else if (conf->base_uri && conf->base_uri->hostname) {
            port_str = "";
        }
        else {
            /* Use the server port */
            port_str = apr_psprintf(p, ":%u", ap_get_server_port(r));
        }
    }

    /*
     * Check if we need to ignore session identifiers in the URL and do so
     * if needed.
     */
    path = uri;
    querystring = parsed_uri->query;
    if (conf->ignore_session_id->nelts) {
        int i;
        char **identifier;

        identifier = (char **) conf->ignore_session_id->elts;
        for (i = 0; i < conf->ignore_session_id->nelts; i++, identifier++) {
            int len;
            const char *param;

            len = strlen(*identifier);
            /*
             * Check that we have a parameter separator in the last segment
             * of the path and that the parameter matches our identifier
             */
            if ((param = ap_strrchr_c(path, ';'))
                    && !strncmp(param + 1, *identifier, len)
                    && (*(param + len + 1) == '=')
                    && !ap_strchr_c(param + len + 2, '/')) {
                path = apr_pstrndup(p, path, param - path);
                continue;
            }
            /*
             * Check if the identifier is in the querystring and cut it out.
             */
            if (querystring) {
                /*
                 * First check if the identifier is at the beginning of the
                 * querystring and followed by a '='
                 */
                if (!strncmp(querystring, *identifier, len)
                        && (*(querystring + len) == '=')) {
                    param = querystring;
                }
                else {
                    char *complete;

                    /*
                     * In order to avoid subkey matching (PR 48401) prepend
                     * identifier with a '&' and append a '='
                     */
                    complete = apr_pstrcat(p, "&", *identifier, "=", NULL);
                    param = strstr(querystring, complete);
                    /* If we found something we are sitting on the '&' */
                    if (param) {
                        param++;
                    }
                }
                if (param) {
                    const char *amp;

                    if (querystring != param) {
                        querystring = apr_pstrndup(p, querystring,
                                param - querystring);
                    }
                    else {
                        querystring = "";
                    }

                    if ((amp = ap_strchr_c(param + len + 1, '&'))) {
                        querystring = apr_pstrcat(p, querystring, amp + 1,
                                NULL);
                    }
                    else {
                        /*
                         * If querystring is not "", then we have the case
                         * that the identifier parameter we removed was the
                         * last one in the original querystring. Hence we have
                         * a trailing '&' which needs to be removed.
                         */
                        if (*querystring) {
                            querystring[strlen(querystring) - 1] = '\0';
                        }
                    }
                }
            }
        }
    }

    /* Key format is a URI, optionally without the query-string */
    if (conf->ignorequerystring) {
        *key = apr_pstrcat(p, scheme, "://", hostname, port_str, path, "?",
                NULL);
    }
    else {
        *key = apr_pstrcat(p, scheme, "://", hostname, port_str, path, "?",
                querystring, NULL);
    }

    /*
     * Store the key in the request_config for the cache as r->parsed_uri
     * might have changed in the time from our first visit here triggered by the
     * quick handler and our possible second visit triggered by the CACHE_SAVE
     * filter (e.g. r->parsed_uri got unescaped). In this case we would save the
     * resource in the cache under a key where it is never found by the quick
     * handler during following requests.
     */
    ap_log_rerror(
            APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00698) "cache: Key for entity %s?%s is %s", uri, parsed_uri->query, *key);

    return APR_SUCCESS;
}
Example #22
0
/*
   =============================================================================
    db:prepare(statement): Prepares a statement for later query/select.
    Returns a table with a :query and :select function, same as the db funcs.
   =============================================================================
 */
int lua_db_prepare(lua_State* L) 
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    lua_db_handle   *db = 0;
    apr_status_t     rc = 0;
    const char      *statement, *at;
    request_rec     *r;
    lua_db_prepared_statement* st;
    int need = 0;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    
    r = ap_lua_check_request_rec(L, 2);
    if (r) {
        apr_dbd_prepared_t *pstatement = NULL;
        luaL_checktype(L, 3, LUA_TSTRING);
        statement = lua_tostring(L, 3);
        
        /* Count number of variables in statement */
        at = ap_strchr_c(statement,'%');
        while (at != NULL) {
            if (at[1] == '%') {
                at++;
            }
            else {
                need++;
            }
            at = ap_strchr_c(at+1,'%');
        }
        
        
        db = lua_get_db_handle(L);
        rc = apr_dbd_prepare(db->driver, r->pool, db->handle, statement, 
                    NULL, &pstatement);
        if (rc != APR_SUCCESS) {
            /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
            const char  *err = apr_dbd_error(db->driver, db->handle, rc);
            /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

            lua_pushnil(L);
            if (err) {
                lua_pushstring(L, err);
                return 2;
            }
            return 1;
        }
        
        /* Push the prepared statement table */
        lua_newtable(L);
        st = lua_newuserdata(L, sizeof(lua_db_prepared_statement));
        st->statement = pstatement;
        st->variables = need;
        st->db = db;
        
        lua_pushliteral(L, "select");
        lua_pushcfunction(L, lua_db_prepared_select);
        lua_rawset(L, -4);
        lua_pushliteral(L, "query");
        lua_pushcfunction(L, lua_db_prepared_query);
        lua_rawset(L, -4);
        lua_rawseti(L, -2, 0);
        return 1;
    }
    return 0;
}
Example #23
0
const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd,
                                    void *dcfg,
                                    const char *arg)
{
    SSLModConfigRec *mc = myModConfig(cmd->server);
    const char *err, *colon;
    char *cp, *cp2;
    int arglen = strlen(arg);

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

    if (ssl_config_global_isfixed(mc)) {
        return NULL;
    }

    if (strcEQ(arg, "none")) {
        mc->nSessionCacheMode      = SSL_SCMODE_NONE;
        mc->szSessionCacheDataFile = NULL;
    }
    else if (strcEQ(arg, "nonenotnull")) {
        mc->nSessionCacheMode      = SSL_SCMODE_NONE_NOT_NULL;
        mc->szSessionCacheDataFile = NULL;
    }
    else if ((arglen > 4) && strcEQn(arg, "dbm:", 4)) {
        mc->nSessionCacheMode      = SSL_SCMODE_DBM;
        mc->szSessionCacheDataFile = ap_server_root_relative(mc->pPool, arg+4);
        if (!mc->szSessionCacheDataFile) {
            return apr_psprintf(cmd->pool,
                                "SSLSessionCache: Invalid cache file path %s",
                                arg+4);
        }
    }
    else if (((arglen > 4) && strcEQn(arg, "shm:", 4)) ||
             ((arglen > 6) && strcEQn(arg, "shmht:", 6)) ||
             ((arglen > 6) && strcEQn(arg, "shmcb:", 6))) {
#if !APR_HAS_SHARED_MEMORY
        return MODSSL_NO_SHARED_MEMORY_ERROR;
#endif
        mc->nSessionCacheMode      = SSL_SCMODE_SHMCB;
        colon = ap_strchr_c(arg, ':');
        mc->szSessionCacheDataFile =
            ap_server_root_relative(mc->pPool, colon+1);
        if (!mc->szSessionCacheDataFile) {
            return apr_psprintf(cmd->pool,
                                "SSLSessionCache: Invalid cache file path %s",
                                colon+1);
        }
        mc->tSessionCacheDataTable = NULL;
        mc->nSessionCacheDataSize  = 1024*512; /* 512KB */

        if ((cp = strchr(mc->szSessionCacheDataFile, '('))) {
            *cp++ = NUL;

            if (!(cp2 = strchr(cp, ')'))) {
                return "SSLSessionCache: Invalid argument: "
                       "no closing parenthesis";
            }

            *cp2 = NUL;

            mc->nSessionCacheDataSize = atoi(cp);

            if (mc->nSessionCacheDataSize < 8192) {
                return "SSLSessionCache: Invalid argument: "
                       "size has to be >= 8192 bytes";

            }

            if (mc->nSessionCacheDataSize >= APR_SHM_MAXSIZE) {
                return apr_psprintf(cmd->pool,
                                    "SSLSessionCache: Invalid argument: "
                                    "size has to be < %d bytes on this "
                                    "platform", APR_SHM_MAXSIZE);

            }
        }
    }
    else if ((arglen > 3) && strcEQn(arg, "dc:", 3)) {
#ifdef HAVE_DISTCACHE
        mc->nSessionCacheMode      = SSL_SCMODE_DC;
        mc->szSessionCacheDataFile = apr_pstrdup(mc->pPool, arg+3);
        if (!mc->szSessionCacheDataFile) {
            return apr_pstrcat(cmd->pool,
                               "SSLSessionCache: Invalid cache file path: ",
                               arg+3, NULL);
        }
#else
        return "SSLSessionCache: distcache support disabled";
#endif
    }
    else {
        return "SSLSessionCache: Invalid argument";
    }

    return NULL;
}
Example #24
0
static int translate_userdir(request_rec *r)
{
    ap_conf_vector_t *server_conf;
    const userdir_config *s_cfg;
    const char *userdirs;
    const char *user, *dname;
    char *redirect;
    apr_finfo_t statbuf;

    /*
     * If the URI doesn't match our basic pattern, we've nothing to do with
     * it.
     */
    if (r->uri[0] != '/' || r->uri[1] != '~') {
        return DECLINED;
    }
    server_conf = r->server->module_config;
    s_cfg = ap_get_module_config(server_conf, &userdir_module);
    userdirs = s_cfg->userdir;
    if (userdirs == NULL) {
        return DECLINED;
    }

    dname = r->uri + 2;
    user = ap_getword(r->pool, &dname, '/');

    /*
     * The 'dname' funny business involves backing it up to capture the '/'
     * delimiting the "/~user" part from the rest of the URL, in case there
     * was one (the case where there wasn't being just "GET /~user HTTP/1.0",
     * for which we don't want to tack on a '/' onto the filename).
     */

    if (dname[-1] == '/') {
        --dname;
    }

    /*
     * If there's no username, it's not for us.  Ignore . and .. as well.
     */
    if (user[0] == '\0' ||
        (user[1] == '.' && (user[2] == '\0' ||
                            (user[2] == '.' && user[3] == '\0')))) {
        return DECLINED;
    }
    /*
     * Nor if there's an username but it's in the disabled list.
     */
    if (apr_table_get(s_cfg->disabled_users, user) != NULL) {
        return DECLINED;
    }
    /*
     * If there's a global interdiction on UserDirs, check to see if this
     * name is one of the Blessed.
     */
    if (s_cfg->globally_disabled == O_DISABLE
        && apr_table_get(s_cfg->enabled_users, user) == NULL) {
        return DECLINED;
    }

    /*
     * Special cases all checked, onward to normal substitution processing.
     */

    while (*userdirs) {
        const char *userdir = ap_getword_conf(r->pool, &userdirs);
        char *filename = NULL, *prefix = NULL;
        apr_status_t rv;
        int is_absolute = ap_os_is_path_absolute(r->pool, userdir);

        if (ap_strchr_c(userdir, '*'))
            prefix = ap_getword(r->pool, &userdir, '*');

        if (userdir[0] == '\0' || is_absolute) {
            if (prefix) {
#ifdef HAVE_DRIVE_LETTERS
                /*
                 * Crummy hack. Need to figure out whether we have been
                 * redirected to a URL or to a file on some drive. Since I
                 * know of no protocols that are a single letter, ignore
                 * a : as the first or second character, and assume a file
                 * was specified
                 */
                if (strchr(prefix + 2, ':'))
#else
                if (strchr(prefix, ':') && !is_absolute)
#endif /* HAVE_DRIVE_LETTERS */
                {
                    redirect = apr_pstrcat(r->pool, prefix, user, userdir,
                                           dname, NULL);
                    apr_table_setn(r->headers_out, "Location", redirect);
                    return HTTP_MOVED_TEMPORARILY;
                }
                else
                    filename = apr_pstrcat(r->pool, prefix, user, userdir,
                                           NULL);
            }
            else
                filename = apr_pstrcat(r->pool, userdir, "/", user, NULL);
        }
        else if (prefix && ap_strchr_c(prefix, ':')) {
            redirect = apr_pstrcat(r->pool, prefix, user, dname, NULL);
            apr_table_setn(r->headers_out, "Location", redirect);
            return HTTP_MOVED_TEMPORARILY;
        }
        else {
#if APR_HAS_USER
            char *homedir;

            if (apr_uid_homepath_get(&homedir, user, r->pool) == APR_SUCCESS) {
                filename = apr_pstrcat(r->pool, homedir, "/", userdir, NULL);
            }
#else
            return DECLINED;
#endif
        }

        /*
         * Now see if it exists, or we're at the last entry. If we are at the
         * last entry, then use the filename generated (if there is one)
         * anyway, in the hope that some handler might handle it. This can be
         * used, for example, to run a CGI script for the user.
         */
        if (filename && (!*userdirs
                      || ((rv = apr_stat(&statbuf, filename, APR_FINFO_MIN,
                                         r->pool)) == APR_SUCCESS
                                             || rv == APR_INCOMPLETE))) {
            r->filename = apr_pstrcat(r->pool, filename, dname, NULL);
            ap_set_context_info(r, apr_pstrmemdup(r->pool, r->uri,
                                                  dname - r->uri),
                                filename);
            /* XXX: Does this walk us around FollowSymLink rules?
             * When statbuf contains info on r->filename we can save a syscall
             * by copying it to r->finfo
             */
            if (*userdirs && dname[0] == 0)
                r->finfo = statbuf;

            /* For use in the get_suexec_identity phase */
            apr_table_setn(r->notes, "mod_userdir_user", user);

            return OK;
        }
    }

    return DECLINED;
}
Example #25
0
static int range_handler(request_rec *r) {
#ifdef APACHE2
	const char *range_header = apr_table_get(r->headers_in, "Range");
#else
	const char *range_header = ap_table_get(r->headers_in, "Range");
#endif
    ranges_server_conf *cfg = ap_get_module_config(r->server->module_config, &rangelimit_module);
	int range_num = 0;			// counter of the number of checked ranges
	int range_overlaps = 0;		// counter of the number of overlapping ranges
	char *ranges = NULL;		// pointer to keep the ranges location
	int start = -1, end = -1;	// start and end of a single range
	int n = 0;					// number of characters collected by sscanf()
	int start_count = 0;		// counter for the new unique starts
	int end_count = 0;			// counter for the new unique ends
	int begins[60];
	int ends[60];

    if (!range_header || strncasecmp(range_header, "bytes=", 6) || r->status != HTTP_OK ) {
		if (r->server->loglevel == APLOG_DEBUG)
#ifdef APACHE2
			ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, "mod_rangelimit: no range found" );
#else
			ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, r, "mod_rangelimit: no range found" );
#endif
        return OK;
	}
//	if (r->server->loglevel == APLOG_DEBUG)
//#ifdef APACHE2
//		ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, "mod_rangelimit: Range header: %s", range_header);
//#else
//		ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, r, "mod_rangelimit: Range header: %s", range_header);
//#endif
#ifdef APACHE2
    if (!ap_strchr_c(range_header, ',')) {
#else
    if (!strchr(range_header, ',')) {
#endif
		if (r->server->loglevel == APLOG_DEBUG)
#ifdef APACHE2
			ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, "mod_rangelimit: single range, nothing to do here");
#else
			ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, r, "mod_rangelimit: single range, nothing to do here");
#endif
		return OK;
	}
    // multiple ranges
#ifdef APACHE2
	ranges = ap_strchr_c(range_header, '=');
#else
	ranges = strchr(range_header, '=');
#endif
	ranges++;			// move the pointer to the begining of the first range
	// start walking over the ranges
	while ( sscanf(ranges, "%11d-%11d%n", &start, &end, &n) >= 1 ) {
		if (start < 0) {
#ifdef APACHE2
			ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
				"mod_rangelimit: requested range(%d-%d) not satisfiable", start, end);
#else
			ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
				"mod_rangelimit: requested range(%d-%d) not satisfiable", start, end);
#endif
			return HTTP_RANGE_NOT_SATISFIABLE;
		}

		if (end >= 0 && end < start) {
#ifdef APACHE2
			ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
				"mod_rangelimit: requested range(%d-%d) not satisfiable", start, end);
#else
			ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
				"mod_rangelimit: requested range(%d-%d) not satisfiable", start, end);
#endif
			return HTTP_RANGE_NOT_SATISFIABLE;
		}
		// code for handling overlaps
		if (check_range(begins, &start) > 0) {
			range_overlaps++;
		} else {
			begins[start_count] = start;
			start_count++;
		}
		if (check_range(ends, &end) > 0) {
			range_overlaps++;
		} else {
			ends[end_count] = end;
			end_count++;
		}
		// end of the overlaps code

		range_num++;	// increase the number of found ranges

		if (r->server->loglevel == APLOG_DEBUG)
#ifdef APACHE2
			ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r,
				"mod_rangelimit: range_num: %d overpalpping: %d start: %d end: %d n: %d",
				range_num, range_overlaps, start, end, n);
#else
			ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, r,
				"mod_rangelimit: range_num: %d overpalpping: %d start: %d end: %d n: %d",
				range_num, range_overlaps, start, end, n);
#endif

		if (range_num > cfg->max_ranges) {
#ifdef APACHE2
			ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
				"mod_rangelimit: too many ranges - %d", range_num);
#else
			ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
				"mod_rangelimit: too many ranges - %d", range_num);
#endif
			return HTTP_RANGE_NOT_SATISFIABLE;
		}
		if (range_overlaps > cfg->max_overlaps) {
#ifdef APACHE2
			ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
				"mod_rangelimit: too many overlapping ranges - %d", range_overlaps);
#else
			ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
				"mod_rangelimit: too many overlapping ranges - %d", range_overlaps);
#endif
			return HTTP_RANGE_NOT_SATISFIABLE;
		}
		if (end == -1) {
			// since n is not set when end is not read
			// find the end of this range using strchr
#ifdef APACHE2
			ranges = ap_strchr_c(ranges, '-') + 1;
#else
			ranges = strchr(ranges, '-') + 1;
#endif
		} else {
			ranges += n;	// advance the pointer by the number of characters read
		}
		if ( *ranges != ',' ) {
			break;			// didn't find an expected delimiter, done?
		}
		++ranges;			// skip the delimiter
		start = end = -1;	// clear the start and end points
		n = 0;				// clear the number of found chars
	}
	return OK;
}

static const char *set_max_ranges(cmd_parms *cmd, void *mconfig, const char *arg) {
    ranges_server_conf *cfg = ap_get_module_config(cmd->server->module_config, &rangelimit_module);
    cfg->max_ranges = atoi(arg);
    return NULL;
}
/* Set the value of a config variabe, strings only */
static const char *set_config_value(cmd_parms *cmd, void *mconfig,
                                    const char *value)
{
    settings_rec *cfg;

    cfg = (settings_rec *) mconfig;

    char name[50];
    sprintf( name, "%s", cmd->cmd->name );

    /*
     * Apply restrictions on attributes.
     */
    if( strlen(value) == 0 ) {
        return apr_psprintf(cmd->pool, "%s not allowed to be NULL", name);
    }

    /* Domain to set the cookie in */
    if( strcasecmp(name, "QS2CookieDomain") == 0 ) {

        if( value[0] != '.' ) {
            return "QS2CookieDomain values must begin with a dot";
        }

        if( ap_strchr_c( &value[1], '.' ) == NULL ) {
            return "QS2CookieDomain values must contain at least one embedded dot";
        }

        // immediately format it for the cookie value, as that's the only
        // place we'll be using it.
        cfg->cookie_domain =
            apr_pstrcat( cmd->pool, "domain=", value, "; ", NULL );

    /* Prefix for all keys set in the cookie */
    } else if( strcasecmp(name, "QS2CookiePrefix") == 0 ) {
        cfg->cookie_prefix     = apr_pstrdup(cmd->pool, value);

    /* Use this query string argument for the cookie name */
    } else if( strcasecmp(name, "QS2CookieName") == 0 ) {
        cfg->cookie_name       = apr_pstrdup(cmd->pool, value);

    /* Use this query string argument for the cookie name */
    } else if( strcasecmp(name, "QS2CookieNameFrom") == 0 ) {
        cfg->cookie_name_from  = apr_pstrdup(cmd->pool, value);

    /* Use this delimiter for pairs of key/values */
    } else if( strcasecmp(name, "QS2CookiePairDelimiter") == 0 ) {

        if( strcspn( value, "=" ) == 0 ) {
            return apr_psprintf(cmd->pool,
                "Variable %s may not be '=' -- illegal in cookie values", name);
        }

        cfg->cookie_pair_delimiter  = apr_pstrdup(cmd->pool, value);

    /* Use this delimiter between a key and a value */
    } else if( strcasecmp(name, "QS2CookieKeyValueDelimiter") == 0 ) {

        if( strcspn( value, "=" ) == 0 ) {
            return apr_psprintf(cmd->pool,
                "Variable %s may not be '=' -- illegal in cookie values", name);
        }

        cfg->cookie_key_value_delimiter  = apr_pstrdup(cmd->pool, value);

    /* Maximum size of all the key/value pairs */
    } else if( strcasecmp(name, "QS2CookieMaxSize") == 0 ) {

        // this has to be a number
        if( apr_isdigit(*value) && apr_isdigit(value[strlen(value) - 1]) ) {
            cfg->cookie_max_size   = atol(apr_pstrdup(cmd->pool, value));
        } else {
            return apr_psprintf(cmd->pool,
                "Variable %s must be a number, not %s", name, value);
        }

    /* Expiry time, in seconds after the request */
    } else if( strcasecmp(name, "QS2CookieExpires") == 0 ) {

        // this has to be a number
        if( apr_isdigit(*value) && apr_isdigit(value[strlen(value) - 1]) ) {
            cfg->cookie_expires = atol(apr_pstrdup(cmd->pool, value));
        } else {
            return apr_psprintf(cmd->pool,
                "Variable %s must be a number, not %s", name, value);
        }

    /* all the keys that will not be put into the cookie */
    } else if( strcasecmp(name, "QS2CookieIgnore") == 0 ) {

        // following tutorial here:
        // http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-19.html
        const char *str                                = apr_pstrdup(cmd->pool, value);
        *(const char**)apr_array_push(cfg->qs_ignore) = str;

        _DEBUG && fprintf( stderr, "qs ignore = %s\n", str );

        char *ary = apr_array_pstrcat( cmd->pool, cfg->qs_ignore, '-' );
        _DEBUG && fprintf( stderr, "qs ignore as str = %s\n", ary );

    } else {
        return apr_psprintf(cmd->pool, "No such variable %s", name);
    }

    return NULL;
}
Example #27
0
/* 
 * Check if a certificate matches for a particular name, by iterating over its
 * DNS-IDs and CN-IDs (RFC 6125), optionally with basic wildcard matching.
 * If server_rec is non-NULL, some (debug/trace) logging is enabled.
 */
BOOL SSL_X509_match_name(apr_pool_t *p, X509 *x509, const char *name,
                         BOOL allow_wildcard, server_rec *s)
{
    BOOL matched = FALSE;
    apr_array_header_t *ids;

    /*
     * At some day in the future, this might be replaced with X509_check_host()
     * (available in OpenSSL 1.0.2 and later), but two points should be noted:
     * 1) wildcard matching in X509_check_host() might yield different
     *    results (by default, it supports a broader set of patterns, e.g.
     *    wildcards in non-initial positions);
     * 2) we lose the option of logging each DNS- and CN-ID (until a match
     *    is found).
     */

    if (SSL_X509_getIDs(p, x509, &ids)) {
        const char *cp;
        int i;
        char **id = (char **)ids->elts;
        BOOL is_wildcard;

        for (i = 0; i < ids->nelts; i++) {
            if (!id[i])
                continue;

            /*
             * Determine if it is a wildcard ID - we're restrictive
             * in the sense that we require the wildcard character to be
             * THE left-most label (i.e., the ID must start with "*.")
             */
            is_wildcard = (*id[i] == '*' && *(id[i]+1) == '.') ? TRUE : FALSE;

            /*
             * If the ID includes a wildcard character (and the caller is
             * allowing wildcards), check if it matches for the left-most
             * DNS label - i.e., the wildcard character is not allowed
             * to match a dot. Otherwise, try a simple string compare.
             */
            if ((allow_wildcard == TRUE && is_wildcard == TRUE &&
                 (cp = ap_strchr_c(name, '.')) && !strcasecmp(id[i]+1, cp)) ||
                !strcasecmp(id[i], name)) {
                matched = TRUE;
            }

            if (s) {
                ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s,
                             "[%s] SSL_X509_match_name: expecting name '%s', "
                             "%smatched by ID '%s'",
                             (mySrvConfig(s))->vhost_id, name,
                             matched == TRUE ? "" : "NOT ", id[i]);
            }

            if (matched == TRUE) {
                break;
            }
        }

    }

    if (s) {
        ssl_log_xerror(SSLLOG_MARK, APLOG_DEBUG, 0, p, s, x509,
                       APLOGNO(02412) "[%s] Cert %s for name '%s'",
                       (mySrvConfig(s))->vhost_id,
                       matched == TRUE ? "matches" : "does not match",
                       name);
    }

    return matched;
}
/* Set the value of a config variabe, strings only */
static const char *set_config_value(cmd_parms *cmd, void *mconfig,
                                    const char *value)
{
    cookietrack_settings_rec *dcfg;

    dcfg = (cookietrack_settings_rec *) mconfig;

    char name[50];
    sprintf( name, "%s", cmd->cmd->name );

    /* Unfortunately, C does not have the equivalent of Perls
       $struct->$name = $value. So we're using a switch instead.
       Suggestions welcome.
    */
    /* Oh hey, switch statements aren't for strings, so we're
       going to be using if (strcasecmp(name, "y") == 0) {
       instead. sexy times!
    */

    /*
     * Apply restrictions on attributes.
     */
    if( strlen(value) == 0 ) {
        return apr_psprintf(cmd->pool, "%s not allowed to be NULL", name);
    }

    /* Name of the cookie header to send */
    if( strcasecmp(name, "CookieHeaderName") == 0 ) {
        dcfg->header_name   = apr_pstrdup(cmd->pool, value);

    /* Name of the note to use in the logs */
    } else if( strcasecmp(name, "CookieNoteName") == 0 ) {
        dcfg->note_name     = apr_pstrdup(cmd->pool, value);

    /* Value to use if setting a DNT cookie */
    } else if( strcasecmp(name, "CookieDNTValue") == 0 ) {
        dcfg->dnt_value     = apr_pstrdup(cmd->pool, value);

    /* Cookie style to sue */
    } else if( strcasecmp(name, "CookieStyle") == 0 ) {

        if( strcasecmp(value, "Netscape") == 0 ) {
            dcfg->style = CT_NETSCAPE;

        } else if( (strcasecmp(value, "Cookie") == 0)
                 || (strcasecmp(value, "RFC2109") == 0) ) {
            dcfg->style = CT_COOKIE;

        } else if( (strcasecmp(value, "Cookie2") == 0)
                 || (strcasecmp(value, "RFC2965") == 0) ) {
            dcfg->style = CT_COOKIE2;

        } else {
            return apr_psprintf(cmd->pool, "Invalid %s: %s", name, value);
        }

    /* Name of the note to use in the logs */
    } else if( strcasecmp(name, "CookieIPHeader") == 0 ) {
        dcfg->cookie_ip_header  = apr_pstrdup(cmd->pool, value);

    /* Domain to set the cookie in */
    } else if( strcasecmp(name, "CookieDomain") == 0 ) {

        if( value[0] != '.' ) {
            return "CookieDomain values must begin with a dot";
        }

        if( ap_strchr_c( &value[1], '.' ) == NULL ) {
            return "CookieDomain values must contain at least one embedded dot";
        }

        dcfg->cookie_domain = apr_pstrdup(cmd->pool, value);

    /* Name of the cookie */
    } else if( strcasecmp(name, "CookieName") == 0 ) {
        dcfg->cookie_name = apr_pstrdup(cmd->pool, value);

        /* build regex to compare against */
        set_and_comp_regexp(dcfg, cmd->pool, value);

        if (dcfg->regexp == NULL) {
            return "Regular expression could not be compiled.";
        }

        if (dcfg->regexp->re_nsub + 1 != NUM_SUBS) {
            return apr_psprintf(cmd->pool, "Invalid cookie name: %s", value);
        }

    } else if( strcasecmp(name, "CookieDNTExempt") == 0 ) {

        // following tutorial here:
        // http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-19.html
        const char *str                                 = apr_pstrdup(cmd->pool, value);
        *(const char**)apr_array_push(dcfg->dnt_exempt) = str;

        _DEBUG && fprintf( stderr, "dnt exempt = %s\n", str );

        char *ary = apr_array_pstrcat( cmd->pool, dcfg->dnt_exempt, '-' );
        _DEBUG && fprintf( stderr, "dnt exempt as str = %s\n", ary );

    } else {
        return apr_psprintf(cmd->pool, "No such variable %s", name);
    }

    return NULL;
}
Example #29
0
static const char *filter_provider(cmd_parms *cmd, void *CFG, const char *args)
{
    mod_filter_cfg *cfg = CFG;
    int flags;
    ap_filter_provider_t *provider;
    const char *rxend;
    const char *c;
    char *str;
    const char *eq;
    ap_filter_rec_t* frec;
    ap_filter_rec_t* provider_frec;

    /* insist on exactly four arguments */
    const char *fname = ap_getword_conf(cmd->pool, &args) ;
    const char *pname = ap_getword_conf(cmd->pool, &args) ;
    const char *condition = ap_getword_conf(cmd->pool, &args) ;
    const char *match = ap_getword_conf(cmd->pool, &args) ;
    eq = ap_getword_conf(cmd->pool, &args) ;
    if ( !*fname || !*pname || !*match || !*condition || *eq ) {
        return "usage: FilterProvider filter provider condition match" ;
    }

    /* fname has been declared with DeclareFilter, so we can look it up */
    frec = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING);

    /* or if provider is mod_filter itself, we can also look it up */
    if (!frec) {
        c = filter_declare(cmd, CFG, fname, NULL);
        if ( c ) {
            return c;
        }
        frec = apr_hash_get(cfg->live_filters, fname, APR_HASH_KEY_STRING);
    }

    if (!frec) {
        return apr_psprintf(cmd->pool, "Undeclared smart filter %s", fname);
    }

    /* if provider has been registered, we can look it up */
    provider_frec = ap_get_output_filter_handle(pname);
    if (!provider_frec) {
        provider_frec = apr_hash_get(cfg->live_filters, pname,
                                     APR_HASH_KEY_STRING);
    }
    if (!provider_frec) {
        return apr_psprintf(cmd->pool, "Unknown filter provider %s", pname);
    }

    provider = apr_palloc(cmd->pool, sizeof(ap_filter_provider_t));
    if (*match == '!') {
        provider->not = 1;
        ++match;
    }
    else {
        provider->not = 0;
    }

    switch (*match++) {
    case '<':
        if (*match == '=') {
            provider->match_type = INT_LE;
            ++match;
        }
        else {
            provider->match_type = INT_LT;
        }
        provider->match.number = atoi(match);
        break;
    case '>':
        if (*match == '=') {
            provider->match_type = INT_GE;
            ++match;
        }
        else {
            provider->match_type = INT_GT;
        }
        provider->match.number = atoi(match);
        break;
    case '=':
        provider->match_type = INT_EQ;
        provider->match.number = atoi(match);
        break;
    case '/':
        provider->match_type = REGEX_MATCH;
        rxend = ap_strchr_c(match, '/');
        if (!rxend) {
              return "Bad regexp syntax";
        }
        flags = AP_REG_NOSUB;        /* we're not mod_rewrite:-) */
        for (c = rxend+1; *c; ++c) {
            switch (*c) {
            case 'i': flags |= AP_REG_ICASE; break;
            }
        }
        provider->match.regex = ap_pregcomp(cmd->pool,
                                            apr_pstrndup(cmd->pool,
                                                         match,
                                                         rxend-match),
                                            flags);
        break;
    case '*':
        provider->match_type = DEFINED;
        provider->match.number = -1;
        break;
    case '$':
        provider->match_type = STRING_CONTAINS;
        str = apr_pstrdup(cmd->pool, match);
        ap_str_tolower(str);
        provider->match.string = str;
        break;
    default:
        provider->match_type = STRING_MATCH;
        provider->match.string = apr_pstrdup(cmd->pool, match-1);
        break;
    }
    provider->frec = provider_frec;
    provider->next = frec->providers;
    frec->providers = provider;

    /* determine what a filter will dispatch this provider on */
    eq = ap_strchr_c(condition, '=');
    if (eq) {
        str = apr_pstrdup(cmd->pool, eq+1);
        if (!strncasecmp(condition, "env=", 4)) {
            provider->dispatch = SUBPROCESS_ENV;
        }
        else if (!strncasecmp(condition, "req=", 4)) {
            provider->dispatch = REQUEST_HEADERS;
        }
        else if (!strncasecmp(condition, "resp=", 5)) {
            provider->dispatch = RESPONSE_HEADERS;
        }
        else {
            return "FilterProvider: unrecognized dispatch table";
        }
    }
    else {
        if (!strcasecmp(condition, "handler")) {
            provider->dispatch = HANDLER;
        }
        else {
            provider->dispatch = RESPONSE_HEADERS;
        }
        str = apr_pstrdup(cmd->pool, condition);
        ap_str_tolower(str);
    }

    if (   (provider->dispatch == RESPONSE_HEADERS)
        && !strcasecmp(str, "content-type")) {
        provider->dispatch = CONTENT_TYPE;
    }
    provider->value = str;

    return NULL;
}
Example #30
0
/*
 * Canonicalise http-like URLs.
 * scheme is the scheme for the URL
 * url is the URL starting with the first '/'
 * def_port is the default port for this scheme.
 */
static int proxy_fcgi_canon(request_rec *r, char *url)
{
    char *host, sport[7];
    const char *err;
    char *path;
    apr_port_t port, def_port;
    fcgi_req_config_t *rconf = NULL;
    const char *pathinfo_type = NULL;

    if (strncasecmp(url, "fcgi:", 5) == 0) {
        url += 5;
    }
    else {
        return DECLINED;
    }

    port = def_port = ap_proxy_port_of_scheme("fcgi");

    ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
                 "canonicalising URL %s", url);
    err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
    if (err) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01059)
                      "error parsing URL %s: %s", url, err);
        return HTTP_BAD_REQUEST;
    }

    if (port != def_port)
        apr_snprintf(sport, sizeof(sport), ":%d", port);
    else
        sport[0] = '\0';

    if (ap_strchr_c(host, ':')) {
        /* if literal IPv6 address */
        host = apr_pstrcat(r->pool, "[", host, "]", NULL);
    }

    if (apr_table_get(r->notes, "proxy-nocanon")) {
        path = url;   /* this is the raw path */
    }
    else {
        path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
                             r->proxyreq);
    }
    if (path == NULL)
        return HTTP_BAD_REQUEST;

    r->filename = apr_pstrcat(r->pool, "proxy:fcgi://", host, sport, "/",
                              path, NULL);

    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01060)
                  "set r->filename to %s", r->filename);

    rconf = ap_get_module_config(r->request_config, &proxy_fcgi_module);
    if (rconf == NULL) { 
        rconf = apr_pcalloc(r->pool, sizeof(fcgi_req_config_t));
        ap_set_module_config(r->request_config, &proxy_fcgi_module, rconf);
    }

    if (NULL != (pathinfo_type = apr_table_get(r->subprocess_env, "proxy-fcgi-pathinfo"))) {
        /* It has to be on disk for this to work */
        if (!strcasecmp(pathinfo_type, "full")) { 
            rconf->need_dirwalk = 1;
            ap_unescape_url_keep2f(path, 0);
        }
        else if (!strcasecmp(pathinfo_type, "first-dot")) { 
            char *split = ap_strchr(path, '.');
            if (split) { 
                char *slash = ap_strchr(split, '/');
                if (slash) { 
                    r->path_info = apr_pstrdup(r->pool, slash);
                    ap_unescape_url_keep2f(r->path_info, 0);
                    *slash = '\0'; /* truncate path */
                }
            }
        }
        else if (!strcasecmp(pathinfo_type, "last-dot")) { 
            char *split = ap_strrchr(path, '.');
            if (split) { 
                char *slash = ap_strchr(split, '/');
                if (slash) { 
                    r->path_info = apr_pstrdup(r->pool, slash);
                    ap_unescape_url_keep2f(r->path_info, 0);
                    *slash = '\0'; /* truncate path */
                }
            }
        }
        else { 
            /* before proxy-fcgi-pathinfo had multi-values. This requires the
             * the FCGI server to fixup PATH_INFO because it's the entire path
             */
            r->path_info = apr_pstrcat(r->pool, "/", path, NULL);
            if (!strcasecmp(pathinfo_type, "unescape")) { 
                ap_unescape_url_keep2f(r->path_info, 0);
            }
            ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01061)
                    "set r->path_info to %s", r->path_info);
        }
    }

    return OK;
}