/** * 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; }
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; }
/** * 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; }
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); }
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; } }
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; }
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); }
/* 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; } } } }
/* 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; }
/* * 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; }
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; }
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; }
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; }
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; }
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; }
/* * 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; }
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; } } }
/** * 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; }
/* ============================================================================= 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; }
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; }
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; }
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; }
/* * 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; }
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; }
/* * 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; }