|
Packit |
90a5c9 |
/* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
Packit |
90a5c9 |
* contributor license agreements. See the NOTICE file distributed with
|
|
Packit |
90a5c9 |
* this work for additional information regarding copyright ownership.
|
|
Packit |
90a5c9 |
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
Packit |
90a5c9 |
* (the "License"); you may not use this file except in compliance with
|
|
Packit |
90a5c9 |
* the License. You may obtain a copy of the License at
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* http://www.apache.org/licenses/LICENSE-2.0
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* Unless required by applicable law or agreed to in writing, software
|
|
Packit |
90a5c9 |
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
Packit |
90a5c9 |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
Packit |
90a5c9 |
* See the License for the specific language governing permissions and
|
|
Packit |
90a5c9 |
* limitations under the License.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#include "mod_session.h"
|
|
Packit |
90a5c9 |
#include "apr_lib.h"
|
|
Packit |
90a5c9 |
#include "apr_strings.h"
|
|
Packit |
90a5c9 |
#include "http_log.h"
|
|
Packit |
90a5c9 |
#include "util_cookies.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define MOD_SESSION_COOKIE "mod_session_cookie"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
module AP_MODULE_DECLARE_DATA session_cookie_module;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Structure to carry the per-dir session config.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
typedef struct {
|
|
Packit |
90a5c9 |
const char *name;
|
|
Packit |
90a5c9 |
int name_set;
|
|
Packit |
90a5c9 |
const char *name_attrs;
|
|
Packit |
90a5c9 |
const char *name2;
|
|
Packit |
90a5c9 |
int name2_set;
|
|
Packit |
90a5c9 |
const char *name2_attrs;
|
|
Packit |
90a5c9 |
int remove;
|
|
Packit |
90a5c9 |
int remove_set;
|
|
Packit |
90a5c9 |
} session_cookie_dir_conf;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Set the cookie and embed the session within it.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* This function adds an RFC2109 compliant Set-Cookie header for
|
|
Packit |
90a5c9 |
* the cookie specified in SessionCookieName, and an RFC2965 compliant
|
|
Packit |
90a5c9 |
* Set-Cookie2 header for the cookie specified in SessionCookieName2.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* If specified, the optional cookie attributes will be added to
|
|
Packit |
90a5c9 |
* each cookie. If defaults are not specified, DEFAULT_ATTRS
|
|
Packit |
90a5c9 |
* will be used.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* On success, this method will return APR_SUCCESS.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* @param r The request pointer.
|
|
Packit |
90a5c9 |
* @param z A pointer to where the session will be written.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t session_cookie_save(request_rec * r, session_rec * z)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
session_cookie_dir_conf *conf = ap_get_module_config(r->per_dir_config,
|
|
Packit |
90a5c9 |
&session_cookie_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* create RFC2109 compliant cookie */
|
|
Packit |
90a5c9 |
if (conf->name_set) {
|
|
Packit |
90a5c9 |
if (z->encoded && z->encoded[0]) {
|
|
Packit |
90a5c9 |
ap_cookie_write(r, conf->name, z->encoded, conf->name_attrs,
|
|
Packit |
90a5c9 |
z->maxage, r->headers_out, r->err_headers_out,
|
|
Packit |
90a5c9 |
NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_cookie_remove(r, conf->name, conf->name_attrs, r->headers_out,
|
|
Packit |
90a5c9 |
r->err_headers_out, NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* create RFC2965 compliant cookie */
|
|
Packit |
90a5c9 |
if (conf->name2_set) {
|
|
Packit |
90a5c9 |
if (z->encoded && z->encoded[0]) {
|
|
Packit |
90a5c9 |
ap_cookie_write2(r, conf->name2, z->encoded, conf->name2_attrs,
|
|
Packit |
90a5c9 |
z->maxage, r->headers_out, r->err_headers_out,
|
|
Packit |
90a5c9 |
NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_cookie_remove2(r, conf->name2, conf->name2_attrs,
|
|
Packit |
90a5c9 |
r->headers_out, r->err_headers_out, NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (conf->name_set || conf->name2_set) {
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Isolate the cookie with the name "name", and if present, extract
|
|
Packit |
90a5c9 |
* the payload from the cookie.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* If the cookie is found, the cookie and any other cookies with the
|
|
Packit |
90a5c9 |
* same name are removed from the cookies passed in the request, so
|
|
Packit |
90a5c9 |
* that credentials are not leaked to a backend server or process.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* A missing or malformed cookie will cause this function to return
|
|
Packit |
90a5c9 |
* APR_EGENERAL.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* On success, this returns APR_SUCCESS.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t session_cookie_load(request_rec * r, session_rec ** z)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
session_cookie_dir_conf *conf = ap_get_module_config(r->per_dir_config,
|
|
Packit |
90a5c9 |
&session_cookie_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
session_rec *zz = NULL;
|
|
Packit |
90a5c9 |
const char *val = NULL;
|
|
Packit |
90a5c9 |
const char *note = NULL;
|
|
Packit |
90a5c9 |
const char *name = NULL;
|
|
Packit |
90a5c9 |
request_rec *m = r;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* find the first redirect */
|
|
Packit |
90a5c9 |
while (m->prev) {
|
|
Packit |
90a5c9 |
m = m->prev;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
/* find the main request */
|
|
Packit |
90a5c9 |
while (m->main) {
|
|
Packit |
90a5c9 |
m = m->main;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* is our session in a cookie? */
|
|
Packit |
90a5c9 |
if (conf->name2_set) {
|
|
Packit |
90a5c9 |
name = conf->name2;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else if (conf->name_set) {
|
|
Packit |
90a5c9 |
name = conf->name;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* first look in the notes */
|
|
Packit |
90a5c9 |
note = apr_pstrcat(m->pool, MOD_SESSION_COOKIE, name, NULL);
|
|
Packit |
90a5c9 |
zz = (session_rec *)apr_table_get(m->notes, note);
|
|
Packit |
90a5c9 |
if (zz) {
|
|
Packit |
90a5c9 |
*z = zz;
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* otherwise, try parse the cookie */
|
|
Packit |
90a5c9 |
ap_cookie_read(r, name, &val, conf->remove);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* create a new session and return it */
|
|
Packit |
90a5c9 |
zz = (session_rec *) apr_pcalloc(m->pool, sizeof(session_rec));
|
|
Packit |
90a5c9 |
zz->pool = m->pool;
|
|
Packit |
90a5c9 |
zz->entries = apr_table_make(m->pool, 10);
|
|
Packit |
90a5c9 |
zz->encoded = val;
|
|
Packit |
90a5c9 |
*z = zz;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* put the session in the notes so we don't have to parse it again */
|
|
Packit |
90a5c9 |
apr_table_setn(m->notes, note, (char *)zz);
|
|
Packit |
90a5c9 |
|
|
Packit |
682164 |
/* don't cache auth protected pages */
|
|
Packit |
682164 |
apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private");
|
|
Packit |
682164 |
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *create_session_cookie_dir_config(apr_pool_t * p, char *dummy)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
session_cookie_dir_conf *new =
|
|
Packit |
90a5c9 |
(session_cookie_dir_conf *) apr_pcalloc(p, sizeof(session_cookie_dir_conf));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return (void *) new;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *merge_session_cookie_dir_config(apr_pool_t * p, void *basev,
|
|
Packit |
90a5c9 |
void *addv)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
session_cookie_dir_conf *new = (session_cookie_dir_conf *)
|
|
Packit |
90a5c9 |
apr_pcalloc(p, sizeof(session_cookie_dir_conf));
|
|
Packit |
90a5c9 |
session_cookie_dir_conf *add = (session_cookie_dir_conf *) addv;
|
|
Packit |
90a5c9 |
session_cookie_dir_conf *base = (session_cookie_dir_conf *) basev;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
new->name = (add->name_set == 0) ? base->name : add->name;
|
|
Packit |
90a5c9 |
new->name_attrs = (add->name_set == 0) ? base->name_attrs : add->name_attrs;
|
|
Packit |
90a5c9 |
new->name_set = add->name_set || base->name_set;
|
|
Packit |
90a5c9 |
new->name2 = (add->name2_set == 0) ? base->name2 : add->name2;
|
|
Packit |
90a5c9 |
new->name2_attrs = (add->name2_set == 0) ? base->name2_attrs : add->name2_attrs;
|
|
Packit |
90a5c9 |
new->name2_set = add->name2_set || base->name2_set;
|
|
Packit |
90a5c9 |
new->remove = (add->remove_set == 0) ? base->remove : add->remove;
|
|
Packit |
90a5c9 |
new->remove_set = add->remove_set || base->remove_set;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return new;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Sanity check a given string that it exists, is not empty,
|
|
Packit |
90a5c9 |
* and does not contain special characters.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static const char *check_string(cmd_parms * cmd, const char *string)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
if (!string || !*string || ap_strchr_c(string, '=') || ap_strchr_c(string, '&')) {
|
|
Packit |
90a5c9 |
return apr_pstrcat(cmd->pool, cmd->directive->directive,
|
|
Packit |
90a5c9 |
" cannot be empty, or contain '=' or '&'.",
|
|
Packit |
90a5c9 |
NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_cookie_name(cmd_parms * cmd, void *config,
|
|
Packit |
90a5c9 |
const char *args)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char *last;
|
|
Packit |
90a5c9 |
char *line = apr_pstrdup(cmd->pool, args);
|
|
Packit |
90a5c9 |
session_cookie_dir_conf *conf = (session_cookie_dir_conf *) config;
|
|
Packit |
90a5c9 |
char *cookie = apr_strtok(line, " \t", &last);
|
|
Packit |
90a5c9 |
conf->name = cookie;
|
|
Packit |
90a5c9 |
conf->name_set = 1;
|
|
Packit |
90a5c9 |
while (apr_isspace(*last)) {
|
|
Packit |
90a5c9 |
last++;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
conf->name_attrs = last;
|
|
Packit |
90a5c9 |
return check_string(cmd, cookie);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *set_cookie_name2(cmd_parms * cmd, void *config,
|
|
Packit |
90a5c9 |
const char *args)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char *last;
|
|
Packit |
90a5c9 |
char *line = apr_pstrdup(cmd->pool, args);
|
|
Packit |
90a5c9 |
session_cookie_dir_conf *conf = (session_cookie_dir_conf *) config;
|
|
Packit |
90a5c9 |
char *cookie = apr_strtok(line, " \t", &last);
|
|
Packit |
90a5c9 |
conf->name2 = cookie;
|
|
Packit |
90a5c9 |
conf->name2_set = 1;
|
|
Packit |
90a5c9 |
while (apr_isspace(*last)) {
|
|
Packit |
90a5c9 |
last++;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
conf->name2_attrs = last;
|
|
Packit |
90a5c9 |
return check_string(cmd, cookie);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *
|
|
Packit |
90a5c9 |
set_remove(cmd_parms * parms, void *dconf, int flag)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
session_cookie_dir_conf *conf = dconf;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
conf->remove = flag;
|
|
Packit |
90a5c9 |
conf->remove_set = 1;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const command_rec session_cookie_cmds[] =
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
AP_INIT_RAW_ARGS("SessionCookieName", set_cookie_name, NULL, RSRC_CONF|OR_AUTHCFG,
|
|
Packit |
90a5c9 |
"The name of the RFC2109 cookie carrying the session"),
|
|
Packit |
90a5c9 |
AP_INIT_RAW_ARGS("SessionCookieName2", set_cookie_name2, NULL, RSRC_CONF|OR_AUTHCFG,
|
|
Packit |
90a5c9 |
"The name of the RFC2965 cookie carrying the session"),
|
|
Packit |
90a5c9 |
AP_INIT_FLAG("SessionCookieRemove", set_remove, NULL, RSRC_CONF|OR_AUTHCFG,
|
|
Packit |
90a5c9 |
"Set to 'On' to remove the session cookie from the headers "
|
|
Packit |
90a5c9 |
"and hide the cookie from a backend server or process"),
|
|
Packit |
90a5c9 |
{NULL}
|
|
Packit |
90a5c9 |
};
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void register_hooks(apr_pool_t * p)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
ap_hook_session_load(session_cookie_load, NULL, NULL, APR_HOOK_MIDDLE);
|
|
Packit |
90a5c9 |
ap_hook_session_save(session_cookie_save, NULL, NULL, APR_HOOK_MIDDLE);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
AP_DECLARE_MODULE(session_cookie) =
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
STANDARD20_MODULE_STUFF,
|
|
Packit |
90a5c9 |
create_session_cookie_dir_config, /* dir config creater */
|
|
Packit |
90a5c9 |
merge_session_cookie_dir_config, /* dir merger --- default is to
|
|
Packit |
90a5c9 |
* override */
|
|
Packit |
90a5c9 |
NULL, /* server config */
|
|
Packit |
90a5c9 |
NULL, /* merge server config */
|
|
Packit |
90a5c9 |
session_cookie_cmds, /* command apr_table_t */
|
|
Packit |
90a5c9 |
register_hooks /* register hooks */
|
|
Packit |
90a5c9 |
};
|