/* * validate an access token against the validation endpoint of the Authorization server and gets a response back */ static int oidc_oauth_validate_access_token(request_rec *r, oidc_cfg *c, const char *token, const char **response) { /* get a handle to the directory config */ oidc_dir_cfg *dir_cfg = ap_get_module_config(r->per_dir_config, &auth_openidc_module); /* assemble parameters to call the token endpoint for validation */ apr_table_t *params = apr_table_make(r->pool, 4); /* add any configured extra static parameters to the introspection endpoint */ oidc_util_table_add_query_encoded_params(r->pool, params, c->oauth.introspection_endpoint_params); /* add the access_token itself */ apr_table_addn(params, "token", token); /* see if we want to do basic auth or post-param-based auth */ const char *basic_auth = NULL; if ((c->oauth.introspection_endpoint_auth != NULL) && (apr_strnatcmp(c->oauth.introspection_endpoint_auth, "client_secret_post") == 0)) { apr_table_addn(params, "client_id", c->oauth.client_id); apr_table_addn(params, "client_secret", c->oauth.client_secret); } else { basic_auth = apr_psprintf(r->pool, "%s:%s", c->oauth.client_id, c->oauth.client_secret); } /* call the endpoint with the constructed parameter set and return the resulting response */ return oidc_util_http_post_form(r, c->oauth.introspection_endpoint_url, params, basic_auth, NULL, c->oauth.ssl_validate_server, response, c->http_timeout_long, c->outgoing_proxy, dir_cfg->pass_cookies); }
static void table_overlap(abts_case *tc, void *data) { const char *val; apr_table_t *t1 = apr_table_make(p, 1); apr_table_t *t2 = apr_table_make(p, 1); apr_table_addn(t1, "a", "0"); apr_table_addn(t1, "g", "7"); apr_table_addn(t2, "a", "1"); apr_table_addn(t2, "b", "2"); apr_table_addn(t2, "c", "3"); apr_table_addn(t2, "b", "2.0"); apr_table_addn(t2, "d", "4"); apr_table_addn(t2, "e", "5"); apr_table_addn(t2, "b", "2."); apr_table_addn(t2, "f", "6"); apr_table_overlap(t1, t2, APR_OVERLAP_TABLES_SET); ABTS_INT_EQUAL(tc, 7, apr_table_elts(t1)->nelts); val = apr_table_get(t1, "a"); ABTS_STR_EQUAL(tc, "1", val); val = apr_table_get(t1, "b"); ABTS_STR_EQUAL(tc, "2.", val); val = apr_table_get(t1, "c"); ABTS_STR_EQUAL(tc, "3", val); val = apr_table_get(t1, "d"); ABTS_STR_EQUAL(tc, "4", val); val = apr_table_get(t1, "e"); ABTS_STR_EQUAL(tc, "5", val); val = apr_table_get(t1, "f"); ABTS_STR_EQUAL(tc, "6", val); val = apr_table_get(t1, "g"); ABTS_STR_EQUAL(tc, "7", val); }
/* This function sets the value of our cookie. * * Parameters: * request_rec *r The request we should set the cookie in. * const char *id The value ve should store in the cookie. * * Returns: * Nothing. */ void am_cookie_set(request_rec *r, const char *id) { am_req_cfg_rec *req_cfg; const char *name; const char *cookie_params; char *cookie; if (id == NULL) return; name = am_cookie_name(r); cookie_params = am_cookie_params(r); cookie = apr_psprintf(r->pool, "%s=%s; %s", name, id, cookie_params); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "cookie_set: %s", cookie); /* Setting the headers inn err_headers_out ensures that they will be * sent for all responses. */ apr_table_addn(r->err_headers_out, "Set-Cookie", cookie); /* Add a note on the current request, to allow us to retrieve this * cookie in the current request. */ req_cfg = am_get_req_cfg(r); req_cfg->cookie_value = apr_pstrdup(r->pool, id); }
static void check_push(request_rec *r, const char *tag) { const h2_config *conf = h2_config_rget(r); if (!r->expecting_100 && conf && conf->push_list && conf->push_list->nelts > 0) { int i, old_status; const char *old_line; ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "%s, early announcing %d resources for push", tag, conf->push_list->nelts); for (i = 0; i < conf->push_list->nelts; ++i) { h2_push_res *push = &APR_ARRAY_IDX(conf->push_list, i, h2_push_res); apr_table_addn(r->headers_out, "Link", apr_psprintf(r->pool, "<%s>; rel=preload%s", push->uri_ref, push->critical? "; critical" : "")); } old_status = r->status; old_line = r->status_line; r->status = 103; r->status_line = "103 Early Hints"; ap_send_interim_response(r, 1); r->status = old_status; r->status_line = old_line; } }
/** * Write an RFC2965 compliant cookie. * * @param r The request * @param name2 The name of the cookie. * @param val The value to place in the cookie. * @param attrs2 The string containing additional cookie attributes. If NULL, the * DEFAULT_ATTRS will be used. * @param maxage If non zero, a Max-Age header will be added to the cookie. */ AP_DECLARE(apr_status_t) ap_cookie_write2(request_rec * r, const char *name2, const char *val, const char *attrs2, long maxage, ...) { const char *buffer; const char *rfc2965; apr_table_t *t; va_list vp; /* handle expiry */ buffer = ""; if (maxage) { buffer = apr_pstrcat(r->pool, "Max-Age=", apr_ltoa(r->pool, maxage), ";", NULL); } /* create RFC2965 compliant cookie */ rfc2965 = apr_pstrcat(r->pool, name2, "=", val, ";", buffer, attrs2 && *attrs2 ? attrs2 : DEFAULT_ATTRS, NULL); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00008) LOG_PREFIX "user '%s' set cookie2: '%s'", r->user, rfc2965); /* write the cookie to the header table(s) provided */ va_start(vp, maxage); while ((t = va_arg(vp, apr_table_t *))) { apr_table_addn(t, SET_COOKIE2, rfc2965); } va_end(vp); return APR_SUCCESS; }
void aos_curl_response_headers_parse(aos_pool_t *p, aos_table_t *headers, char *buffer, int len) { char *pos; aos_string_t str; aos_string_t key; aos_string_t value; str.data = buffer; str.len = len; aos_trip_space_and_cntrl(&str); pos = aos_strlchr(str.data, str.data + str.len, ':'); if (pos == NULL) { return; } key.data = str.data; key.len = pos - str.data; pos += 1; value.len = str.data + str.len - pos; value.data = pos; aos_strip_space(&value); apr_table_addn(headers, aos_pstrdup(p, &key), aos_pstrdup(p, &value)); }
/* * refreshes the access_token/id_token /refresh_token received from the OP using the refresh_token */ apr_byte_t oidc_proto_refresh_request(request_rec *r, oidc_cfg *cfg, oidc_provider_t *provider, const char *rtoken, char **id_token, char **access_token, char **token_type, int *expires_in, char **refresh_token) { oidc_debug(r, "enter"); /* assemble the parameters for a call to the token endpoint */ apr_table_t *params = apr_table_make(r->pool, 5); apr_table_addn(params, "grant_type", "refresh_token"); apr_table_addn(params, "refresh_token", rtoken); apr_table_addn(params, "scope", provider->scope); return oidc_proto_token_endpoint_request(r, cfg, provider, params, id_token, access_token, token_type, expires_in, refresh_token); }
/* * resolves the code received from the OP in to an id_token, access_token and refresh_token */ apr_byte_t oidc_proto_resolve_code(request_rec *r, oidc_cfg *cfg, oidc_provider_t *provider, const char *code, char **id_token, char **access_token, char **token_type, int *expires_in, char **refresh_token) { oidc_debug(r, "enter"); /* assemble the parameters for a call to the token endpoint */ apr_table_t *params = apr_table_make(r->pool, 5); apr_table_addn(params, "grant_type", "authorization_code"); apr_table_addn(params, "code", code); apr_table_addn(params, "redirect_uri", cfg->redirect_uri); return oidc_proto_token_endpoint_request(r, cfg, provider, params, id_token, access_token, token_type, expires_in, refresh_token); }
/* Iterate through the cookies, isolate our cookie and then remove it. * * If our cookie appears two or more times, but with different values, * remove it twice and set the duplicated flag to true. Remove any * $path or other attributes following our cookie if present. If we end * up with an empty cookie, remove the whole header. */ static int extract_cookie_line(ap_cookie_do * v, const char *key, const char *val) { char *last1, *last2; char *cookie = apr_pstrdup(v->r->pool, val); const char *name = apr_pstrcat(v->r->pool, v->name ? v->name : "", "=", NULL); apr_size_t len = strlen(name); const char *new_cookie = ""; const char *comma = ","; char *next1; const char *semi = ";"; char *next2; const char *sep = ""; int cookies = 0; /* find the cookie called name */ int eat = 0; next1 = apr_strtok(cookie, comma, &last1); while (next1) { next2 = apr_strtok(next1, semi, &last2); while (next2) { char *trim = next2; while (apr_isspace(*trim)) { trim++; } if (!strncmp(trim, name, len)) { if (v->encoded) { if (strcmp(v->encoded, trim + len)) { v->duplicated = 1; } } v->encoded = apr_pstrdup(v->r->pool, trim + len); eat = 1; } else { if (*trim != '$') { cookies++; eat = 0; } if (!eat) { new_cookie = apr_pstrcat(v->r->pool, new_cookie, sep, next2, NULL); } } next2 = apr_strtok(NULL, semi, &last2); sep = semi; } next1 = apr_strtok(NULL, comma, &last1); sep = comma; } /* any cookies left over? */ if (cookies) { apr_table_addn(v->new_cookies, key, new_cookie); } return 1; }
static void make_cookie(request_rec *r) { cookie_log_state *cls = ap_get_module_config(r->server->module_config, &usertrack_module); char cookiebuf[2 * (sizeof(apr_uint64_t) + sizeof(int)) + 2]; unsigned int random; apr_time_t now = r->request_time ? r->request_time : apr_time_now(); char *new_cookie; cookie_dir_rec *dcfg; ap_random_insecure_bytes(&random, sizeof(random)); apr_snprintf(cookiebuf, sizeof(cookiebuf), "%x.%" APR_UINT64_T_HEX_FMT, random, (apr_uint64_t)now); dcfg = ap_get_module_config(r->per_dir_config, &usertrack_module); if (cls->expires) { /* Cookie with date; as strftime '%a, %d-%h-%y %H:%M:%S GMT' */ new_cookie = apr_psprintf(r->pool, "%s=%s; path=/", dcfg->cookie_name, cookiebuf); if ((dcfg->style == CT_UNSET) || (dcfg->style == CT_NETSCAPE)) { apr_time_exp_t tms; apr_time_exp_gmt(&tms, r->request_time + apr_time_from_sec(cls->expires)); new_cookie = apr_psprintf(r->pool, "%s; expires=%s, " "%.2d-%s-%.2d %.2d:%.2d:%.2d GMT", new_cookie, apr_day_snames[tms.tm_wday], tms.tm_mday, apr_month_snames[tms.tm_mon], tms.tm_year % 100, tms.tm_hour, tms.tm_min, tms.tm_sec); } else { new_cookie = apr_psprintf(r->pool, "%s; max-age=%d", new_cookie, cls->expires); } } else { new_cookie = apr_psprintf(r->pool, "%s=%s; path=/", dcfg->cookie_name, cookiebuf); } if (dcfg->cookie_domain != NULL) { new_cookie = apr_pstrcat(r->pool, new_cookie, "; domain=", dcfg->cookie_domain, (dcfg->style == CT_COOKIE2 ? "; version=1" : ""), NULL); } apr_table_addn(r->err_headers_out, (dcfg->style == CT_COOKIE2 ? "Set-Cookie2" : "Set-Cookie"), new_cookie); apr_table_setn(r->notes, "cookie", apr_pstrdup(r->pool, cookiebuf)); /* log first time */ return; }
void add_argument(modsec_rec *msr, apr_table_t *arguments, msc_arg *arg) { if (msr->txcfg->debuglog_level >= 5) { msr_log(msr, 5, "Adding request argument (%s): name \"%s\", value \"%s\"", arg->origin, log_escape_ex(msr->mp, arg->name, arg->name_len), log_escape_ex(msr->mp, arg->value, arg->value_len)); } apr_table_addn(arguments, log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *)arg); }
/** * Callback function to extract multiple HTTP headers from the outgoing header * and change them a little bit. (borrowed from server/util_script.c) */ static int replace_header_cb(void *v, const char *key, const char *val) { header_replace_cb_t *data; data = (header_replace_cb_t *) v; // do replacement and finally add the new value to the table int len = strlen(val); int rc = 0; int re_vector[RE_VECTOR_SIZE]; // 3 elements per matched pattern request_rec *r; r = data->r; rc = pcre_exec(data->pattern, data->extra, val, len, 0, 0, re_vector, RE_VECTOR_SIZE); if (rc < 0 && rc != PCRE_ERROR_NOMATCH) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, "Matching Error %d", rc); return rc; } if (rc == 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r, "PCRE output vector too small (%d)", RE_VECTOR_SIZE/3-1); } /* If the result count is greater than 0 then there are * matches in the data string. Thus we try to replace those * strings with the user provided string. */ if (rc > 0) { char *replacement; char *prefix, *postfix; replacement = apr_pstrcat(r->pool, data->replacement, NULL); prefix = apr_pcalloc(r->pool, re_vector[0] + 1); if (prefix == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Unable to allocate memory for prefix"); return -1; } memcpy(prefix, val, (size_t)re_vector[0]); postfix = apr_pcalloc(r->pool, len); if (postfix == NULL) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Unable to allocate memory for postfix"); return -1; } memcpy(postfix, (val + re_vector[1]), len - re_vector[1]); val = apr_pstrcat(r->pool, prefix, replacement, postfix, NULL); } apr_table_addn(data->header_table, key, val); return 1; }
static void table_overlap2(abts_case *tc, void *data) { apr_pool_t *subp; apr_table_t *t1, *t2; apr_pool_create(&subp, p); t1 = apr_table_make(subp, 1); t2 = apr_table_make(p, 1); apr_table_addn(t1, "t1", "one"); apr_table_addn(t2, "t2", "two"); apr_table_overlap(t1, t2, APR_OVERLAP_TABLES_SET); ABTS_INT_EQUAL(tc, 2, apr_table_elts(t1)->nelts); ABTS_STR_EQUAL(tc, "one", apr_table_get(t1, "t1")); ABTS_STR_EQUAL(tc, "two", apr_table_get(t1, "t2")); }
static int filter_header_do(void *v, const char *key, const char *val) { if ((*key == 'W' || *key == 'w') && !strcasecmp(key, "Warning") && *val == '1') { /* any stored Warning headers with warn-code 1xx (see section * 14.46) MUST be deleted from the cache entry and the forwarded * response. */ } else { apr_table_addn(v, key, val); } return 1; }
static authn_status pam_authenticate_with_login_password(request_rec * r, const char * pam_service, const char * login, const char * password, int steps) { pam_handle_t * pamh = NULL; struct pam_conv pam_conversation = { &pam_authenticate_conv, (void *) password }; const char * stage = "PAM transaction failed for service"; const char * param = pam_service; int ret; ret = pam_start(pam_service, login, &pam_conversation, &pamh); if (ret == PAM_SUCCESS) { const char * remote_host_or_ip = ap_get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME, NULL); if (remote_host_or_ip) { stage = "PAM pam_set_item PAM_RHOST failed for service"; ret = pam_set_item(pamh, PAM_RHOST, remote_host_or_ip); } } if (ret == PAM_SUCCESS) { if (steps & _PAM_STEP_AUTH) { param = login; stage = "PAM authentication failed for user"; ret = pam_authenticate(pamh, PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK); } if ((ret == PAM_SUCCESS) && (steps & _PAM_STEP_ACCOUNT)) { param = login; stage = "PAM account validation failed for user"; ret = pam_acct_mgmt(pamh, PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK); if (ret == PAM_NEW_AUTHTOK_REQD) { authnz_pam_config_rec * conf = ap_get_module_config(r->per_dir_config, &authnz_pam_module); if (conf && conf->expired_redirect_url) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "mod_authnz_pam: PAM_NEW_AUTHTOK_REQD: redirect to [%s]", conf->expired_redirect_url); apr_table_addn(r->headers_out, "Location", format_location(r, conf->expired_redirect_url, login)); return HTTP_TEMPORARY_REDIRECT; } } } } if (ret != PAM_SUCCESS) { const char * strerr = pam_strerror(pamh, ret); ap_log_error(APLOG_MARK, APLOG_WARNING, 0, r->server, "mod_authnz_pam: %s %s: %s", stage, param, strerr); apr_table_setn(r->subprocess_env, _EXTERNAL_AUTH_ERROR_ENV_NAME, apr_pstrdup(r->pool, strerr)); pam_end(pamh, ret); return AUTH_DENIED; } apr_table_setn(r->subprocess_env, _REMOTE_USER_ENV_NAME, login); r->user = apr_pstrdup(r->pool, login); ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, r->server, "mod_authnz_pam: PAM authentication passed for user %s", login); pam_end(pamh, ret); return AUTH_GRANTED; }
static int copy_headers_out(void *vbaton, const char *key, const char *value) { s_baton_t *ctx = vbaton; int done = 0; /* XXXXX: Special Treatment required for MANY other headers. fixme.*/ switch (key[0]) { case 'c': case 'C': if (strcasecmp("Content-Type", key) == 0) { ap_set_content_type(ctx->r, value); done = 1; break; } else if (strcasecmp("Connection", key) == 0) { done = 1; break; } else if (strcasecmp("Content-Encoding", key) == 0) { done = 1; break; } else if (strcasecmp("Content-Length", key) == 0) { done = 1; break; } break; case 't': case 'T': if (strcasecmp("Transfer-Encoding", key) == 0) { done = 1; break; } break; default: break; } if (!done) { apr_table_addn(ctx->r->headers_out, key, value); } return 0; }
int json_add_argument(modsec_rec *msr, const char *value, unsigned length) { msc_arg *arg = (msc_arg *) NULL; /** * If we do not have a prefix, we cannot create a variable name * to reference this argument; for now we simply ignore these */ if (!msr->json->current_key) { msr_log(msr, 3, "Cannot add scalar value without an associated key"); return 1; } arg = (msc_arg *) apr_pcalloc(msr->mp, sizeof(msc_arg)); /** * Argument name is 'prefix + current_key' */ if (msr->json->prefix) { arg->name = apr_psprintf(msr->mp, "%s.%s", msr->json->prefix, msr->json->current_key); } else { arg->name = apr_psprintf(msr->mp, "%s", msr->json->current_key); } arg->name_len = strlen(arg->name); /** * Argument value is copied from the provided string */ arg->value = apr_pstrmemdup(msr->mp, value, length); arg->value_len = length; arg->origin = "JSON"; if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "Adding JSON argument '%s' with value '%s'", arg->name, arg->value); } apr_table_addn(msr->arguments, log_escape_nq_ex(msr->mp, arg->name, arg->name_len), (void *) arg); return 1; }
/* This function deletes the cookie. * * Parameters: * request_rec *r The request we should clear the cookie in. We will * allocate any neccesary memory from r->pool. * * Returns: * Nothing. */ void am_cookie_delete(request_rec *r) { const char *name; const char *cookie_params; char *cookie; name = am_cookie_name(r); cookie_params = am_cookie_params(r); /* Format a cookie. To delete a cookie we set the expires-timestamp * to the past. */ cookie = apr_psprintf(r->pool, "%s=NULL;" " expires=Thu, 01-Jan-1970 00:00:00 GMT;" " %s", name, cookie_params); apr_table_addn(r->err_headers_out, "Set-Cookie", cookie); }
/** * Set the cookie and embed the session within it. * * This function adds an RFC2109 compliant Set-Cookie header for * the cookie specified in SessionCookieName, and an RFC2965 compliant * Set-Cookie2 header for the cookie specified in SessionCookieName2. * * If specified, the optional cookie attributes will be added to * each cookie. If defaults are not specified, DEFAULT_ATTRS * will be used. * * On success, this method will return APR_SUCCESS. * * @param r The request pointer. * @param z A pointer to where the session will be written. */ static apr_status_t session_cookie_save(request_rec * r, session_rec * z) { session_cookie_dir_conf *conf = ap_get_module_config(r->per_dir_config, &session_cookie_module); /* don't cache auth protected pages */ apr_table_addn(r->headers_out, "Cache-Control", "no-cache"); /* create RFC2109 compliant cookie */ if (conf->name_set) { if (z->encoded && z->encoded[0]) { ap_cookie_write(r, conf->name, z->encoded, conf->name_attrs, z->maxage, r->headers_out, r->err_headers_out, NULL); } else { ap_cookie_remove(r, conf->name, conf->name_attrs, r->headers_out, r->err_headers_out, NULL); } } /* create RFC2965 compliant cookie */ if (conf->name2_set) { if (z->encoded && z->encoded[0]) { ap_cookie_write2(r, conf->name2, z->encoded, conf->name2_attrs, z->maxage, r->headers_out, r->err_headers_out, NULL); } else { ap_cookie_remove2(r, conf->name2, conf->name2_attrs, r->headers_out, r->err_headers_out, NULL); } } if (conf->name_set || conf->name2_set) { return OK; } return DECLINED; }
/** * Remove an RFC2965 compliant cookie. * * @param r The request * @param name2 The name of the cookie. */ AP_DECLARE(apr_status_t) ap_cookie_remove2(request_rec * r, const char *name2, const char *attrs2, ...) { apr_table_t *t; va_list vp; /* create RFC2965 compliant cookie */ const char *rfc2965 = apr_pstrcat(r->pool, name2, "=;Max-Age=0;", attrs2 ? attrs2 : CLEAR_ATTRS, NULL); ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00010) LOG_PREFIX "user '%s' removed cookie2: '%s'", r->user, rfc2965); /* write the cookie to the header table(s) provided */ va_start(vp, attrs2); while ((t = va_arg(vp, apr_table_t *))) { apr_table_addn(t, SET_COOKIE2, rfc2965); } va_end(vp); return APR_SUCCESS; }
/* user apr_table_do to set session information in header http */ static int Auth_memCookie_DoSetHeader(void *rec, const char *szKey, const char *szValue) { // strAuth_memCookie_config_rec *conf = NULL; request_rec *r = (request_rec*)rec; const char *szHeaderName = szKey; /* if key does not start with X-, preprent X-MCAC_ */ if (strncasecmp(szHeaderName, "x-", 2) != 0) szHeaderName = apr_pstrcat(r->pool, "X-", szHeaderName, NULL); ap_log_rerror(APLOG_MARK,APLOG_DEBUG, 0,r,ERRTAG "adding header: %s ", szHeaderName); /* set string header */ if (apr_table_get(r->headers_in, szHeaderName) == NULL) { apr_table_addn(r->headers_in, szHeaderName, szValue); } else { apr_table_set(r->headers_in, szHeaderName, szValue); } return 1; }
static void addCookie(request_rec *r, uint8_t *secret, int secretLen) { authn_google_config_rec *conf = ap_get_module_config(r->per_dir_config, &authn_google_module); if (conf->cookieLife) { unsigned long exp = (apr_time_now() / (1000000) ) + conf->cookieLife; char *h = hash_cookie(r->pool,secret,secretLen,exp); char * cookie = apr_psprintf(r->pool,"google_authn=%s:%lu:%s",r->user,exp,h); if (conf->domain) { cookie = apr_pstrcat(r->pool,cookie,";domain=",conf->domain, NULL); } if (conf->path) { cookie = apr_pstrcat(r->pool,cookie,";path=",conf->path, NULL); } if (conf->debugLevel) ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Created cookie expires %lu hash is %s Cookie: %s",exp,h,cookie); apr_table_addn(r->headers_out,"Set-Cookie",cookie); } }
/* Parse form data from a string. The input string is preserved. */ apr_table_t *mapcache_http_parse_param_string(mapcache_context *r, char *args_str) { apr_table_t *params; char *args = apr_pstrdup(r->pool,args_str); char *key; char *value; const char *delim = "&"; char *last; if (args == NULL) { return apr_table_make(r->pool,0); } params = apr_table_make(r->pool,20); /* Split the input on '&' */ for (key = apr_strtok(args, delim, &last); key != NULL; key = apr_strtok(NULL, delim, &last)) { /* key is a pointer to the key=value string */ /*loop through key=value string to replace '+' by ' ' */ for (value = key; *value; ++value) { if (*value == '+') { *value = ' '; } } /* split into Key / Value and unescape it */ value = strchr(key, '='); if (value) { *value++ = '\0'; /* replace '=' by \0, thus terminating the key string */ _mapcache_unescape_url(key); _mapcache_unescape_url(value); } else { value = ""; _mapcache_unescape_url(key); } /* Store key/value pair in our form hash. */ apr_table_addn(params, key, value); } return params; }
/* * send a code/refresh request to the token endpoint and return the parsed contents */ static apr_byte_t oidc_proto_token_endpoint_request(request_rec *r, oidc_cfg *cfg, oidc_provider_t *provider, apr_table_t *params, char **id_token, char **access_token, char **token_type, int *expires_in, char **refresh_token) { const char *response = NULL; /* see if we need to do basic auth or auth-through-post-params (both applied through the HTTP POST method though) */ const char *basic_auth = NULL; if ((provider->token_endpoint_auth == NULL) || (apr_strnatcmp(provider->token_endpoint_auth, "client_secret_basic") == 0)) { basic_auth = apr_psprintf(r->pool, "%s:%s", provider->client_id, provider->client_secret); } else { apr_table_addn(params, "client_id", provider->client_id); apr_table_addn(params, "client_secret", provider->client_secret); } /* add any configured extra static parameters to the token endpoint */ oidc_util_table_add_query_encoded_params(r->pool, params, provider->token_endpoint_params); /* send the refresh request to the token endpoint */ if (oidc_util_http_post_form(r, provider->token_endpoint_url, params, basic_auth, NULL, provider->ssl_validate_server, &response, cfg->http_timeout_long, cfg->outgoing_proxy) == FALSE) { oidc_warn(r, "error when calling the token endpoint (%s)", provider->token_endpoint_url); return FALSE; } /* check for errors, the response itself will have been logged already */ json_t *result = NULL; if (oidc_util_decode_json_and_check_error(r, response, &result) == FALSE) return FALSE; /* get the id_token from the parsed response */ oidc_json_object_get_string(r->pool, result, "id_token", id_token, NULL); /* get the access_token from the parsed response */ oidc_json_object_get_string(r->pool, result, "access_token", access_token, NULL); /* get the token type from the parsed response */ oidc_json_object_get_string(r->pool, result, "token_type", token_type, NULL); /* check the new token type */ if (token_type != NULL) { if (oidc_proto_validate_token_type(r, provider, *token_type) == FALSE) { oidc_warn(r, "access token type did not validate, dropping it"); *access_token = NULL; } } /* get the expires_in value */ oidc_json_object_get_int(r->pool, result, "expires_in", expires_in, -1); /* get the refresh_token from the parsed response */ oidc_json_object_get_string(r->pool, result, "refresh_token", refresh_token, NULL); json_decref(result); return TRUE; }
static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob, unsigned int blob_size, int log_vars) { apr_table_t *col = NULL; unsigned int blob_offset; col = apr_table_make(msr->mp, 32); if (col == NULL) return NULL; /* ENH verify the first 3 bytes (header) */ blob_offset = 3; while (blob_offset + 1 < blob_size) { msc_string *var = apr_pcalloc(msr->mp, sizeof(msc_string)); var->name_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; if (var->name_len == 0) { /* Is the length a name length, or just the end of the blob? */ if (blob_offset < blob_size - 2) { /* This should never happen as the name length * includes the terminating NUL and should be 1 for "" */ if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); } msr_log(msr, 4, "Possibly corrupted database: var name length = 0 at blob offset %u-%u.", blob_offset, blob_offset + 1); } break; } else if (var->name_len > 65536) { /* This should never happen as the length is restricted on store * to 65536. */ if (msr->txcfg->debuglog_level >= 9) { msr_log(msr, 9, "BLOB[%d]: %s", blob_offset, log_escape_hex(msr->mp, blob + blob_offset, blob_size - blob_offset)); } msr_log(msr, 4, "Possibly corrupted database: var name length > 65536 (0x%04x) at blob offset %u-%u.", var->name_len, blob_offset, blob_offset + 1); break; } blob_offset += 2; if (blob_offset + var->name_len > blob_size) return NULL; var->name = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->name_len - 1); blob_offset += var->name_len; var->name_len--; var->value_len = (blob[blob_offset] << 8) + blob[blob_offset + 1]; blob_offset += 2; if (blob_offset + var->value_len > blob_size) return NULL; var->value = apr_pstrmemdup(msr->mp, (const char *)blob + blob_offset, var->value_len - 1); blob_offset += var->value_len; var->value_len--; if (log_vars && (msr->txcfg->debuglog_level >= 9)) { msr_log(msr, 9, "Read variable: name \"%s\", value \"%s\".", log_escape_ex(msr->mp, var->name, var->name_len), log_escape_ex(msr->mp, var->value, var->value_len)); } apr_table_addn(col, var->name, (void *)var); } return col; }
static int filter_lookup(ap_filter_t *f, ap_filter_rec_t *filter) { ap_filter_provider_t *provider; int match = 0; const char *err = NULL; request_rec *r = f->r; harness_ctx *ctx = f->ctx; provider_ctx *pctx; #ifndef NO_PROTOCOL unsigned int proto_flags; mod_filter_ctx *rctx = ap_get_module_config(r->request_config, &filter_module); #endif /* Check registered providers in order */ for (provider = filter->providers; provider; provider = provider->next) { if (provider->expr) { match = ap_expr_exec(r, provider->expr, &err); if (err) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01379) "Error evaluating filter dispatch condition: %s", err); match = 0; } ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "Expression condition for '%s' %s", provider->frec->name, match ? "matched" : "did not match"); } else if (r->content_type) { const char **type = provider->types; size_t len = strcspn(r->content_type, "; \t"); AP_DEBUG_ASSERT(type != NULL); ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, "Content-Type '%s' ...", r->content_type); while (*type) { /* Handle 'content-type;charset=...' correctly */ if (strncmp(*type, r->content_type, len) == 0 && (*type)[len] == '\0') { ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, "... matched '%s'", *type); match = 1; break; } else { ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, "... did not match '%s'", *type); } type++; } ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "Content-Type condition for '%s' %s", provider->frec->name, match ? "matched" : "did not match"); } else { ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "Content-Type condition for '%s' did not match: " "no Content-Type", provider->frec->name); } if (match) { /* condition matches this provider */ #ifndef NO_PROTOCOL /* check protocol * * FIXME: * This is a quick hack and almost certainly buggy. * The idea is that by putting this in mod_filter, we relieve * filter implementations of the burden of fixing up HTTP headers * for cases that are routinely affected by filters. * * Default is ALWAYS to do nothing, so as not to tread on the * toes of filters which want to do it themselves. * */ proto_flags = provider->frec->proto_flags; /* some specific things can't happen in a proxy */ if (r->proxyreq) { if (proto_flags & AP_FILTER_PROTO_NO_PROXY) { /* can't use this provider; try next */ continue; } if (proto_flags & AP_FILTER_PROTO_TRANSFORM) { const char *str = apr_table_get(r->headers_out, "Cache-Control"); if (str) { if (ap_strcasestr(str, "no-transform")) { /* can't use this provider; try next */ continue; } } apr_table_addn(r->headers_out, "Warning", apr_psprintf(r->pool, "214 %s Transformation applied", r->hostname)); } } /* things that are invalidated if the filter transforms content */ if (proto_flags & AP_FILTER_PROTO_CHANGE) { apr_table_unset(r->headers_out, "Content-MD5"); apr_table_unset(r->headers_out, "ETag"); if (proto_flags & AP_FILTER_PROTO_CHANGE_LENGTH) { apr_table_unset(r->headers_out, "Content-Length"); } } /* no-cache is for a filter that has different effect per-hit */ if (proto_flags & AP_FILTER_PROTO_NO_CACHE) { apr_table_unset(r->headers_out, "Last-Modified"); apr_table_addn(r->headers_out, "Cache-Control", "no-cache"); } if (proto_flags & AP_FILTER_PROTO_NO_BYTERANGE) { apr_table_setn(r->headers_out, "Accept-Ranges", "none"); } else if (rctx && rctx->range) { /* restore range header we saved earlier */ apr_table_setn(r->headers_in, "Range", rctx->range); rctx->range = NULL; } #endif for (pctx = ctx->init_ctx; pctx; pctx = pctx->next) { if (pctx->provider == provider) { ctx->fctx = pctx->ctx ; } } ctx->func = provider->frec->filter_func.out_func; return 1; } } /* No provider matched */ return 0; }
static int set_cookie_doo_doo(void *v, const char *key, const char *val) { apr_table_addn(v, key, val); return 1; }
AP_DECLARE(void) ap_add_common_vars(request_rec *r) { apr_table_t *e; server_rec *s = r->server; conn_rec *c = r->connection; const char *rem_logname; char *env_path; #if defined(WIN32) || defined(OS2) || defined(BEOS) char *env_temp; #endif const char *host; const apr_array_header_t *hdrs_arr = apr_table_elts(r->headers_in); const apr_table_entry_t *hdrs = (const apr_table_entry_t *) hdrs_arr->elts; int i; apr_port_t rport; /* use a temporary apr_table_t which we'll overlap onto * r->subprocess_env later * (exception: if r->subprocess_env is empty at the start, * write directly into it) */ if (apr_is_empty_table(r->subprocess_env)) { e = r->subprocess_env; } else { e = apr_table_make(r->pool, 25 + hdrs_arr->nelts); } /* First, add environment vars from headers... this is as per * CGI specs, though other sorts of scripting interfaces see * the same vars... */ for (i = 0; i < hdrs_arr->nelts; ++i) { if (!hdrs[i].key) { continue; } /* A few headers are special cased --- Authorization to prevent * rogue scripts from capturing passwords; content-type and -length * for no particular reason. */ if (!strcasecmp(hdrs[i].key, "Content-type")) { apr_table_addn(e, "CONTENT_TYPE", hdrs[i].val); } else if (!strcasecmp(hdrs[i].key, "Content-length")) { apr_table_addn(e, "CONTENT_LENGTH", hdrs[i].val); } /* * You really don't want to disable this check, since it leaves you * wide open to CGIs stealing passwords and people viewing them * in the environment with "ps -e". But, if you must... */ #ifndef SECURITY_HOLE_PASS_AUTHORIZATION else if (!strcasecmp(hdrs[i].key, "Authorization") || !strcasecmp(hdrs[i].key, "Proxy-Authorization")) { continue; } #endif else { apr_table_addn(e, http2env(r->pool, hdrs[i].key), hdrs[i].val); } } if (!(env_path = getenv("PATH"))) { env_path = DEFAULT_PATH; } apr_table_addn(e, "PATH", apr_pstrdup(r->pool, env_path)); #ifdef WIN32 if ((env_temp = getenv("SystemRoot")) != NULL) { apr_table_addn(e, "SystemRoot", env_temp); } if ((env_temp = getenv("COMSPEC")) != NULL) { apr_table_addn(e, "COMSPEC", env_temp); } if ((env_temp = getenv("PATHEXT")) != NULL) { apr_table_addn(e, "PATHEXT", env_temp); } if ((env_temp = getenv("WINDIR")) != NULL) { apr_table_addn(e, "WINDIR", env_temp); } #endif #ifdef OS2 if ((env_temp = getenv("COMSPEC")) != NULL) { apr_table_addn(e, "COMSPEC", env_temp); } if ((env_temp = getenv("ETC")) != NULL) { apr_table_addn(e, "ETC", env_temp); } if ((env_temp = getenv("DPATH")) != NULL) { apr_table_addn(e, "DPATH", env_temp); } if ((env_temp = getenv("PERLLIB_PREFIX")) != NULL) { apr_table_addn(e, "PERLLIB_PREFIX", env_temp); } #endif #ifdef BEOS if ((env_temp = getenv("LIBRARY_PATH")) != NULL) { apr_table_addn(e, "LIBRARY_PATH", env_temp); } #endif apr_table_addn(e, "SERVER_SIGNATURE", ap_psignature("", r)); apr_table_addn(e, "SERVER_SOFTWARE", ap_get_server_banner()); apr_table_addn(e, "SERVER_NAME", ap_escape_html(r->pool, ap_get_server_name(r))); apr_table_addn(e, "SERVER_ADDR", r->connection->local_ip); /* Apache */ apr_table_addn(e, "SERVER_PORT", apr_psprintf(r->pool, "%u", ap_get_server_port(r))); host = ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST, NULL); if (host) { apr_table_addn(e, "REMOTE_HOST", host); } apr_table_addn(e, "REMOTE_ADDR", c->remote_ip); apr_table_addn(e, "DOCUMENT_ROOT", ap_document_root(r)); /* Apache */ apr_table_addn(e, "SERVER_ADMIN", s->server_admin); /* Apache */ apr_table_addn(e, "SCRIPT_FILENAME", r->filename); /* Apache */ rport = c->remote_addr->port; apr_table_addn(e, "REMOTE_PORT", apr_itoa(r->pool, rport)); if (r->user) { apr_table_addn(e, "REMOTE_USER", r->user); } else if (r->prev) { request_rec *back = r->prev; while (back) { if (back->user) { apr_table_addn(e, "REDIRECT_REMOTE_USER", back->user); break; } back = back->prev; } } if (r->ap_auth_type) { apr_table_addn(e, "AUTH_TYPE", r->ap_auth_type); } rem_logname = ap_get_remote_logname(r); if (rem_logname) { apr_table_addn(e, "REMOTE_IDENT", apr_pstrdup(r->pool, rem_logname)); } /* Apache custom error responses. If we have redirected set two new vars */ if (r->prev) { if (r->prev->args) { apr_table_addn(e, "REDIRECT_QUERY_STRING", r->prev->args); } if (r->prev->uri) { apr_table_addn(e, "REDIRECT_URL", r->prev->uri); } } if (e != r->subprocess_env) { apr_table_overlap(r->subprocess_env, e, APR_OVERLAP_TABLES_SET); } }
/* * based on an account name, perform OpenID Connect Provider Issuer Discovery to find out the issuer and obtain and store its metadata */ apr_byte_t oidc_proto_account_based_discovery(request_rec *r, oidc_cfg *cfg, const char *acct, char **issuer) { // TODO: maybe show intermediate/progress screen "discovering..." oidc_debug(r, "enter, acct=%s", acct); const char *resource = apr_psprintf(r->pool, "acct:%s", acct); const char *domain = strrchr(acct, '@'); if (domain == NULL) { oidc_error(r, "invalid account name"); return FALSE; } domain++; const char *url = apr_psprintf(r->pool, "https://%s/.well-known/webfinger", domain); apr_table_t *params = apr_table_make(r->pool, 1); apr_table_addn(params, "resource", resource); apr_table_addn(params, "rel", "http://openid.net/specs/connect/1.0/issuer"); const char *response = NULL; if (oidc_util_http_get(r, url, params, NULL, NULL, cfg->provider.ssl_validate_server, &response, cfg->http_timeout_short, cfg->outgoing_proxy) == FALSE) { /* errors will have been logged by now */ return FALSE; } /* decode and see if it is not an error response somehow */ json_t *j_response = NULL; if (oidc_util_decode_json_and_check_error(r, response, &j_response) == FALSE) return FALSE; /* get the links parameter */ json_t *j_links = json_object_get(j_response, "links"); if ((j_links == NULL) || (!json_is_array(j_links))) { oidc_error(r, "response JSON object did not contain a \"links\" array"); json_decref(j_response); return FALSE; } /* get the one-and-only object in the "links" array */ json_t *j_object = json_array_get(j_links, 0); if ((j_object == NULL) || (!json_is_object(j_object))) { oidc_error(r, "response JSON object did not contain a JSON object as the first element in the \"links\" array"); json_decref(j_response); return FALSE; } /* get the href from that object, which is the issuer value */ json_t *j_href = json_object_get(j_object, "href"); if ((j_href == NULL) || (!json_is_string(j_href))) { oidc_error(r, "response JSON object did not contain a \"href\" element in the first \"links\" array object"); json_decref(j_response); return FALSE; } *issuer = apr_pstrdup(r->pool, json_string_value(j_href)); oidc_debug(r, "returning issuer \"%s\" for account \"%s\" after doing successful webfinger-based discovery", *issuer, acct); json_decref(j_response); return TRUE; }
// See here for the structure of request_rec: // http://ci.apache.org/projects/httpd/trunk/doxygen/structrequest__rec.html static int hook(request_rec *r) { settings_rec *cfg = ap_get_module_config( r->per_dir_config, &querystring2cookie_module ); /* Do not run in subrequests, don't run if not enabled */ if( !(cfg->enabled || r->main) ) { return DECLINED; } /* No query string? nothing to do here */ if( !(r->args) || strlen( r->args ) < 1 ) { return DECLINED; } /* skip if dnt headers are present? */ if( !(cfg->enabled_if_dnt) && apr_table_get( r->headers_in, "DNT" ) ) { _DEBUG && fprintf( stderr, "DNT header sent: declined\n" ); return DECLINED; } _DEBUG && fprintf( stderr, "Query string: '%s'\n", r->args ); // *********************************** // Calculate expiry time // *********************************** // The expiry time. We can't use max-age because IE6 - IE8 do not // support it :( char *expires = ""; if( cfg->cookie_expires > 0 ) { apr_time_exp_t tms; apr_time_exp_gmt( &tms, r->request_time + apr_time_from_sec( cfg->cookie_expires ) ); expires = apr_psprintf( r->pool, "expires=%s, %.2d-%s-%.2d %.2d:%.2d:%.2d GMT", apr_day_snames[tms.tm_wday], tms.tm_mday, apr_month_snames[tms.tm_mon], tms.tm_year % 100, tms.tm_hour, tms.tm_min, tms.tm_sec ); } // *********************************** // Find key/value pairs // *********************************** // keep track of how much data we've been writing - there's a limit to how // much a browser will store per domain (usually 4k) so we want to make sure // it's not getting flooded. int total_pair_size = 0; // This holds the final cookie we'll send back - make sure to initialize // or it can point at garbage! char *cookie = ""; // string to use as the cookie name (together with the prefix) - make sure to // initialize or it can point at garbage! char *cookie_name = ""; // Iterate over the key/value pairs char *last_pair; char *pair = apr_strtok( apr_pstrdup( r->pool, r->args ), "&", &last_pair ); _DEBUG && fprintf( stderr, "about to parse query string for pairs\n" ); _DEBUG && fprintf( stderr, "looking for cookie name in %s\n", cfg->cookie_name_from ); while( pair != NULL ) { // length of the substr before the = sign (or index of the = sign) int contains_equals_at = strcspn( pair, "=" ); // Does not contains a =, or starts with a =, meaning it's garbage if( !strstr(pair, "=") || contains_equals_at < 1 ) { _DEBUG && fprintf( stderr, "invalid pair: %s\n", pair ); // And get the next pair -- has to be done at every break pair = apr_strtok( NULL, "&", &last_pair ); continue; } _DEBUG && fprintf( stderr, "pair looks valid: %s - = sign at pos: %i\n", pair, contains_equals_at ); // So this IS a key value pair. Let's get the key and the value. // first, get the key - everything up to the first = char *key = apr_pstrndup( r->pool, pair, contains_equals_at ); // now get the value, everything AFTER the = sign. We do that by // moving the pointer past the = sign. char *value = apr_pstrdup( r->pool, pair ); value += contains_equals_at + 1; _DEBUG && fprintf( stderr, "pair=%s, key=%s, value=%s\n", pair, key, value ); // you want us to use a name from the query string? // This might be that name. if( cfg->cookie_name_from && !(strlen(cookie_name)) && strcasecmp( key, cfg->cookie_name_from ) == 0 ) { // get everything after the = sign -- that's our name. cookie_name = apr_pstrcat( r->pool, cfg->cookie_prefix, value, NULL ); _DEBUG && fprintf( stderr, "using %s as the cookie name\n", cookie_name ); // And get the next pair -- has to be done at every break pair = apr_strtok( NULL, "&", &last_pair ); continue; // may be on the ignore list } else { // may have to continue the outer loop, use this as a marker int do_continue = 0; // you might have blacklisted this key; let's check // Following tutorial code here again: // http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-19.html int i; for( i = 0; i < cfg->qs_ignore->nelts; i++ ) { char *ignore = ((char **)cfg->qs_ignore->elts)[i]; _DEBUG && fprintf( stderr, "processing ignore %s against pair %s\n", ignore, pair ); // it's indeed on the ignore list; move on // do this by comparing the string length first - if the length of // the ignore key and the key are identical AND the first N characters // of the string are the same if( strcasecmp( key, ignore ) == 0 ) { _DEBUG && fprintf( stderr, "pair %s is on the ignore list: %s\n", pair, ignore ); // signal to continue the outer loop; we found an ignore match do_continue = 1; break; } } // ignore match found, move on if( do_continue ) { // And get the next pair -- has to be done at every break pair = apr_strtok( NULL, "&", &last_pair ); continue; } } // looks like a valid key=value declaration _DEBUG && fprintf( stderr, "valid key/value pair: %s\n", pair ); // Now, the key may contain URL unsafe characters, which are also // not allowed in Cookies. See here: // http://tools.ietf.org/html/rfc2068, section 2.2 on 'tspecials' // // So instead, we url encode the key. The size of the key is max // 3 times old key size (any char gets encoded into %xx), so allow // for that space. See the documentation here: // http://httpd.apache.org/apreq/docs/libapreq2/apreq__util_8h.html#785be2ceae273b0a7b2ffda223b2ebae char *escaped_key = apreq_escape( r->pool, key, strlen(key) ); char *escaped_value = apreq_escape( r->pool, value, strlen(value) ); _DEBUG && fprintf( stderr, "Original key: %s - Escaped key: %s\n", key, escaped_key ); _DEBUG && fprintf( stderr, "Original value: %s - Escaped value: %s\n", value, escaped_value ); // Now, let's do some transposing: The '=' sign needs to be replaced // with whatever the separator is. It can't be a '=' sign, as that's // illegal in cookies. The string may be larger than a single char, // so split the string and do the magix. // This makes key[delim]value - redefining pair here is safe, we're // just using it for printing now. char *key_value = apr_pstrcat( r->pool, escaped_key, cfg->cookie_key_value_delimiter, escaped_value, NULL ); int this_pair_size = strlen( key_value ); // Make sure the individual pair, as well as the whole thing doesn't // get too long _DEBUG && fprintf( stderr, "this pair size: %i, total pair size: %i, max size: %i\n", this_pair_size, total_pair_size, cfg->cookie_max_size ); if( (this_pair_size <= cfg->cookie_max_size) && (total_pair_size + this_pair_size <= cfg->cookie_max_size) ) { cookie = apr_pstrcat( r->pool, cookie, // the cookie so far // If we already have pairs in here, we need the // delimiter, otherwise we don't. (strlen(cookie) ? cfg->cookie_pair_delimiter : ""), key_value, // the next pair. NULL ); // update the book keeping - this is the new size including delims total_pair_size = strlen(cookie); _DEBUG && fprintf( stderr, "this pair size: %i, total pair size: %i\n", this_pair_size, total_pair_size ); } else { _DEBUG && fprintf( stderr, "Pair size too long to add: %s (this: %i total: %i max: %i)\n", key_value, this_pair_size, total_pair_size, cfg->cookie_max_size ); } // and move the pointer pair = apr_strtok( NULL, "&", &last_pair ); } // So you told us we should use a cookie name from the query string, // but we never found it in there. That's a problem. if( cfg->cookie_name_from && !strlen(cookie_name) ) { // r->err_headers_out also honors non-2xx responses and // internal redirects. See the patch here: // http://svn.apache.org/viewvc?view=revision&revision=1154620 apr_table_addn( r->err_headers_out, "X-QS2Cookie", apr_pstrcat( r->pool, "ERROR: Did not detect cookie name - missing QS argument: ", cfg->cookie_name_from, NULL ) ); // Let's return the output } else { // we got here without a cookie name? We can use the default. if( !strlen(cookie_name) ) { _DEBUG && fprintf( stderr, "explicitly setting cookie name to: %s\n", cfg->cookie_name ); cookie_name = apr_pstrcat( r->pool, cfg->cookie_prefix, cfg->cookie_name, NULL ); } _DEBUG && fprintf( stderr, "cookie name: %s\n", cookie_name ); // XXX use a sprintf format for more flexibility? if( cfg->encode_in_key ) { _DEBUG && fprintf( stderr, "%s: encoding in the key\n", cookie_name ); cookie = apr_pstrcat( r->pool, // cookie data cookie_name, cfg->cookie_pair_delimiter, cookie, "=", // The format is different on 32 (%ld) vs 64bit (%lld), so // use the constant for it instead. You can find this in apr.h apr_psprintf( r->pool, "%" APR_OFF_T_FMT, apr_time_sec(apr_time_now()) ), NULL ); } else { _DEBUG && fprintf( stderr, "%s: encoding in the value\n", cookie_name ); cookie = apr_pstrcat( r->pool, cookie_name, "=", cookie, NULL ); } // And now add the meta data to the cookie cookie = apr_pstrcat( r->pool, cookie, "; ", "path=/; ", cfg->cookie_domain, expires, NULL ); _DEBUG && fprintf( stderr, "cookie: %s\n", cookie ); // r->err_headers_out also honors non-2xx responses and // internal redirects. See the patch here: // http://svn.apache.org/viewvc?view=revision&revision=1154620 apr_table_addn( r->err_headers_out, "Set-Cookie", cookie ); } return OK; }