|
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 |
#include "apr_dbd.h"
|
|
Packit |
90a5c9 |
#include "mod_dbd.h"
|
|
Packit |
90a5c9 |
#include "mpm_common.h"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
#define MOD_SESSION_DBD "mod_session_dbd"
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
module AP_MODULE_DECLARE_DATA session_dbd_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 peruser;
|
|
Packit |
90a5c9 |
int peruser_set;
|
|
Packit |
90a5c9 |
int remove;
|
|
Packit |
90a5c9 |
int remove_set;
|
|
Packit |
90a5c9 |
const char *selectlabel;
|
|
Packit |
90a5c9 |
const char *insertlabel;
|
|
Packit |
90a5c9 |
const char *updatelabel;
|
|
Packit |
90a5c9 |
const char *deletelabel;
|
|
Packit |
90a5c9 |
} session_dbd_dir_conf;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* optional function - look it up once in post_config */
|
|
Packit |
90a5c9 |
static ap_dbd_t *(*session_dbd_acquire_fn) (request_rec *) = NULL;
|
|
Packit |
90a5c9 |
static void (*session_dbd_prepare_fn) (server_rec *, const char *, const char *) = NULL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Initialise the database.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* If the mod_dbd module is missing, this method will return APR_EGENERAL.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t dbd_init(request_rec *r, const char *query, ap_dbd_t **dbdp,
|
|
Packit |
90a5c9 |
apr_dbd_prepared_t **statementp)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
ap_dbd_t *dbd;
|
|
Packit |
90a5c9 |
apr_dbd_prepared_t *statement;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (!session_dbd_prepare_fn || !session_dbd_acquire_fn) {
|
|
Packit |
90a5c9 |
session_dbd_prepare_fn = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_prepare);
|
|
Packit |
90a5c9 |
session_dbd_acquire_fn = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_acquire);
|
|
Packit |
90a5c9 |
if (!session_dbd_prepare_fn || !session_dbd_acquire_fn) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01850)
|
|
Packit |
90a5c9 |
"You must load mod_dbd to enable AuthDBD functions");
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
dbd = session_dbd_acquire_fn(r);
|
|
Packit |
90a5c9 |
if (!dbd) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01851)
|
|
Packit |
90a5c9 |
"failed to acquire database connection");
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
statement = apr_hash_get(dbd->prepared, query, APR_HASH_KEY_STRING);
|
|
Packit |
90a5c9 |
if (!statement) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01852)
|
|
Packit |
90a5c9 |
"failed to find the prepared statement called '%s'", query);
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
*dbdp = dbd;
|
|
Packit |
90a5c9 |
*statementp = statement;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Load the session by the key specified.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* The session value is allocated using the passed apr_pool_t.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t dbd_load(apr_pool_t *p, request_rec * r,
|
|
Packit |
90a5c9 |
const char *key, const char **val)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
ap_dbd_t *dbd = NULL;
|
|
Packit |
90a5c9 |
apr_dbd_prepared_t *statement = NULL;
|
|
Packit |
90a5c9 |
apr_dbd_results_t *res = NULL;
|
|
Packit |
90a5c9 |
apr_dbd_row_t *row = NULL;
|
|
Packit |
90a5c9 |
apr_int64_t expiry = (apr_int64_t) apr_time_now();
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
session_dbd_dir_conf *conf = ap_get_module_config(r->per_dir_config,
|
|
Packit |
90a5c9 |
&session_dbd_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (conf->selectlabel == NULL) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01853)
|
|
Packit |
90a5c9 |
"no SessionDBDselectlabel has been specified");
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = dbd_init(r, conf->selectlabel, &dbd, &statement);
|
|
Packit |
90a5c9 |
if (rv) {
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
rv = apr_dbd_pvbselect(dbd->driver, r->pool, dbd->handle, &res, statement,
|
|
Packit |
90a5c9 |
0, key, &expiry, NULL);
|
|
Packit |
90a5c9 |
if (rv) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01854)
|
|
Packit |
90a5c9 |
"query execution error saving session '%s' "
|
|
Packit |
90a5c9 |
"in database using query '%s': %s", key, conf->selectlabel,
|
|
Packit |
90a5c9 |
apr_dbd_error(dbd->driver, dbd->handle, rv));
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
for (rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1);
|
|
Packit |
90a5c9 |
rv != -1;
|
|
Packit |
90a5c9 |
rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1)) {
|
|
Packit |
90a5c9 |
if (rv != 0) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01855)
|
|
Packit |
90a5c9 |
"error retrieving results while saving '%s' "
|
|
Packit |
90a5c9 |
"in database using query '%s': %s", key, conf->selectlabel,
|
|
Packit |
90a5c9 |
apr_dbd_error(dbd->driver, dbd->handle, rv));
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (*val == NULL) {
|
|
Packit |
90a5c9 |
*val = apr_pstrdup(p, apr_dbd_get_entry(dbd->driver, row, 0));
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
/* we can't break out here or row won't get cleaned up */
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Load the session by firing off a dbd query.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* If the session is anonymous, the session key will be extracted from
|
|
Packit |
90a5c9 |
* the cookie specified. Failing that, the session key will be extracted
|
|
Packit |
90a5c9 |
* from the GET parameters.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* If the session is keyed by the username, the session will be extracted
|
|
Packit |
90a5c9 |
* by that.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* If no session is found, an empty session will be created.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* On success, this returns OK.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t session_dbd_load(request_rec * r, session_rec ** z)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
session_dbd_dir_conf *conf = ap_get_module_config(r->per_dir_config,
|
|
Packit |
90a5c9 |
&session_dbd_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t ret = APR_SUCCESS;
|
|
Packit |
90a5c9 |
session_rec *zz = NULL;
|
|
Packit |
90a5c9 |
const char *name = NULL;
|
|
Packit |
90a5c9 |
const char *note = NULL;
|
|
Packit |
90a5c9 |
const char *val = NULL;
|
|
Packit |
90a5c9 |
const char *key = NULL;
|
|
Packit |
90a5c9 |
request_rec *m = r->main ? r->main : r;
|
|
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 if (conf->peruser_set && r->user) {
|
|
Packit |
90a5c9 |
name = r->user;
|
|
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_DBD, 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 |
/* load anonymous sessions */
|
|
Packit |
90a5c9 |
if (conf->name_set || conf->name2_set) {
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* load an RFC2109 or RFC2965 compliant cookie */
|
|
Packit |
90a5c9 |
ap_cookie_read(r, name, &key, conf->remove);
|
|
Packit |
90a5c9 |
if (key) {
|
|
Packit |
90a5c9 |
ret = dbd_load(m->pool, r, key, &val;;
|
|
Packit |
90a5c9 |
if (ret != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return ret;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* load named session */
|
|
Packit |
90a5c9 |
else if (conf->peruser) {
|
|
Packit |
90a5c9 |
if (r->user) {
|
|
Packit |
90a5c9 |
ret = dbd_load(m->pool, r, r->user, &val;;
|
|
Packit |
90a5c9 |
if (ret != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return ret;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* otherwise not for us */
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
}
|
|
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(zz->pool, 10);
|
|
Packit |
90a5c9 |
if (key && val) {
|
|
Packit |
90a5c9 |
apr_uuid_t *uuid = apr_pcalloc(zz->pool, sizeof(apr_uuid_t));
|
|
Packit |
90a5c9 |
if (APR_SUCCESS == apr_uuid_parse(uuid, key)) {
|
|
Packit |
90a5c9 |
zz->uuid = uuid;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
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 pages with a session */
|
|
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 |
* Save the session by the key specified.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t dbd_save(request_rec * r, const char *oldkey,
|
|
Packit |
90a5c9 |
const char *newkey, const char *val, apr_int64_t expiry)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
ap_dbd_t *dbd = NULL;
|
|
Packit |
90a5c9 |
apr_dbd_prepared_t *statement;
|
|
Packit |
90a5c9 |
int rows = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
session_dbd_dir_conf *conf = ap_get_module_config(r->per_dir_config,
|
|
Packit |
90a5c9 |
&session_dbd_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (conf->updatelabel == NULL) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01856)
|
|
Packit |
90a5c9 |
"no SessionDBDupdatelabel has been specified");
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = dbd_init(r, conf->updatelabel, &dbd, &statement);
|
|
Packit |
90a5c9 |
if (rv) {
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (oldkey) {
|
|
Packit |
90a5c9 |
rv = apr_dbd_pvbquery(dbd->driver, r->pool, dbd->handle, &rows,
|
|
Packit |
90a5c9 |
statement, val, &expiry, newkey, oldkey, NULL);
|
|
Packit |
90a5c9 |
if (rv) {
|
|
Packit |
90a5c9 |
ap_log_rerror(
|
|
Packit |
90a5c9 |
APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01857) "query execution error updating session '%s' "
|
|
Packit |
90a5c9 |
"using database query '%s': %s/%s", oldkey, newkey, conf->updatelabel, apr_dbd_error(dbd->driver, dbd->handle, rv));
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* if some rows were updated it means a session existed and was updated,
|
|
Packit |
90a5c9 |
* so we are done.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if (rows != 0) {
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (conf->insertlabel == NULL) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01858)
|
|
Packit |
90a5c9 |
"no SessionDBDinsertlabel has been specified");
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = dbd_init(r, conf->insertlabel, &dbd, &statement);
|
|
Packit |
90a5c9 |
if (rv) {
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
rv = apr_dbd_pvbquery(dbd->driver, r->pool, dbd->handle, &rows, statement,
|
|
Packit |
90a5c9 |
val, &expiry, newkey, NULL);
|
|
Packit |
90a5c9 |
if (rv) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01859)
|
|
Packit |
90a5c9 |
"query execution error inserting session '%s' "
|
|
Packit |
90a5c9 |
"in database with '%s': %s", newkey, conf->insertlabel,
|
|
Packit |
90a5c9 |
apr_dbd_error(dbd->driver, dbd->handle, rv));
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/*
|
|
Packit |
90a5c9 |
* if some rows were inserted it means a session was inserted, so we are
|
|
Packit |
90a5c9 |
* done.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
if (rows != 0) {
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01860)
|
|
Packit |
90a5c9 |
"the session insert query did not cause any rows to be added "
|
|
Packit |
90a5c9 |
"to the database for session '%s', session not inserted", newkey);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Remove the session by the key specified.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t dbd_remove(request_rec * r, const char *key)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t rv;
|
|
Packit |
90a5c9 |
ap_dbd_t *dbd;
|
|
Packit |
90a5c9 |
apr_dbd_prepared_t *statement;
|
|
Packit |
90a5c9 |
int rows = 0;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
session_dbd_dir_conf *conf = ap_get_module_config(r->per_dir_config,
|
|
Packit |
90a5c9 |
&session_dbd_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (conf->deletelabel == NULL) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01862)
|
|
Packit |
90a5c9 |
"no SessionDBDdeletelabel has been specified");
|
|
Packit |
90a5c9 |
return APR_EGENERAL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = dbd_init(r, conf->deletelabel, &dbd, &statement);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
/* No need to do additional error logging here, it has already
|
|
Packit |
90a5c9 |
been done in dbd_init if needed */
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
rv = apr_dbd_pvbquery(dbd->driver, r->pool, dbd->handle, &rows, statement,
|
|
Packit |
90a5c9 |
key, NULL);
|
|
Packit |
90a5c9 |
if (rv != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01864)
|
|
Packit |
90a5c9 |
"query execution error removing session '%s' "
|
|
Packit |
90a5c9 |
"from database", key);
|
|
Packit |
90a5c9 |
return rv;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_SUCCESS;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Clean out expired sessions.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* TODO: We need to figure out a way to clean out expired sessions from the database.
|
|
Packit |
90a5c9 |
* The monitor hook doesn't help us that much, as we have no handle into the
|
|
Packit |
90a5c9 |
* server, and so we need to come up with a way to do this safely.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static apr_status_t dbd_clean(apr_pool_t *p, server_rec *s)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return APR_ENOTIMPL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* Save the session by firing off a dbd query.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* If the session is anonymous, save the session and write a cookie
|
|
Packit |
90a5c9 |
* containing the uuid.
|
|
Packit |
90a5c9 |
*
|
|
Packit |
90a5c9 |
* If the session is keyed to the username, save the session using
|
|
Packit |
90a5c9 |
* the username as a key.
|
|
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_dbd_save(request_rec * r, session_rec * z)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
apr_status_t ret = APR_SUCCESS;
|
|
Packit |
90a5c9 |
session_dbd_dir_conf *conf = ap_get_module_config(r->per_dir_config,
|
|
Packit |
90a5c9 |
&session_dbd_module);
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* support anonymous sessions */
|
|
Packit |
90a5c9 |
if (conf->name_set || conf->name2_set) {
|
|
Packit |
90a5c9 |
char *oldkey = NULL, *newkey = NULL;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* if the session is new or changed, make a new session ID */
|
|
Packit |
90a5c9 |
if (z->uuid) {
|
|
Packit |
90a5c9 |
oldkey = apr_pcalloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
|
|
Packit |
90a5c9 |
apr_uuid_format(oldkey, z->uuid);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (z->dirty || !oldkey) {
|
|
Packit |
90a5c9 |
z->uuid = apr_pcalloc(z->pool, sizeof(apr_uuid_t));
|
|
Packit |
90a5c9 |
apr_uuid_get(z->uuid);
|
|
Packit |
90a5c9 |
newkey = apr_pcalloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
|
|
Packit |
90a5c9 |
apr_uuid_format(newkey, z->uuid);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
newkey = oldkey;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* save the session with the uuid as key */
|
|
Packit |
90a5c9 |
if (z->encoded && z->encoded[0]) {
|
|
Packit |
90a5c9 |
ret = dbd_save(r, oldkey, newkey, z->encoded, z->expiry);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ret = dbd_remove(r, oldkey);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
if (ret != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return ret;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* create RFC2109 compliant cookie */
|
|
Packit |
90a5c9 |
if (conf->name_set) {
|
|
Packit |
90a5c9 |
ap_cookie_write(r, conf->name, newkey, conf->name_attrs, z->maxage,
|
|
Packit |
90a5c9 |
r->headers_out, r->err_headers_out, NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* create RFC2965 compliant cookie */
|
|
Packit |
90a5c9 |
if (conf->name2_set) {
|
|
Packit |
90a5c9 |
ap_cookie_write2(r, conf->name2, newkey, conf->name2_attrs, z->maxage,
|
|
Packit |
90a5c9 |
r->headers_out, r->err_headers_out, NULL);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* save named session */
|
|
Packit |
90a5c9 |
else if (conf->peruser) {
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/* don't cache pages with a session */
|
|
Packit |
682164 |
apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private");
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
if (r->user) {
|
|
Packit |
90a5c9 |
ret = dbd_save(r, r->user, r->user, z->encoded, z->expiry);
|
|
Packit |
90a5c9 |
if (ret != APR_SUCCESS) {
|
|
Packit |
90a5c9 |
return ret;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
else {
|
|
Packit |
90a5c9 |
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01865)
|
|
Packit |
90a5c9 |
"peruser sessions can only be saved if a user is logged in, "
|
|
Packit |
90a5c9 |
"session not saved: %s", r->uri);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return DECLINED;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
/**
|
|
Packit |
90a5c9 |
* This function performs housekeeping on the database, deleting expired
|
|
Packit |
90a5c9 |
* sessions.
|
|
Packit |
90a5c9 |
*/
|
|
Packit |
90a5c9 |
static int session_dbd_monitor(apr_pool_t *p, server_rec *s)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
/* TODO handle housekeeping */
|
|
Packit |
90a5c9 |
dbd_clean(p, s);
|
|
Packit |
90a5c9 |
return OK;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *create_session_dbd_dir_config(apr_pool_t * p, char *dummy)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
session_dbd_dir_conf *new =
|
|
Packit |
90a5c9 |
(session_dbd_dir_conf *) apr_pcalloc(p, sizeof(session_dbd_dir_conf));
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
new->remove = 1;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
new->selectlabel = "selectsession";
|
|
Packit |
90a5c9 |
new->insertlabel = "insertsession";
|
|
Packit |
90a5c9 |
new->updatelabel = "updatesession";
|
|
Packit |
90a5c9 |
new->deletelabel = "deletesession";
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return (void *) new;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static void *merge_session_dbd_dir_config(apr_pool_t * p, void *basev, void *addv)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
session_dbd_dir_conf *new = (session_dbd_dir_conf *) apr_pcalloc(p, sizeof(session_dbd_dir_conf));
|
|
Packit |
90a5c9 |
session_dbd_dir_conf *add = (session_dbd_dir_conf *) addv;
|
|
Packit |
90a5c9 |
session_dbd_dir_conf *base = (session_dbd_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->peruser = (add->peruser_set == 0) ? base->peruser : add->peruser;
|
|
Packit |
90a5c9 |
new->peruser_set = add->peruser_set || base->peruser_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 |
new->selectlabel = (!add->selectlabel) ? base->selectlabel : add->selectlabel;
|
|
Packit |
90a5c9 |
new->updatelabel = (!add->updatelabel) ? base->updatelabel : add->updatelabel;
|
|
Packit |
90a5c9 |
new->insertlabel = (!add->insertlabel) ? base->insertlabel : add->insertlabel;
|
|
Packit |
90a5c9 |
new->deletelabel = (!add->deletelabel) ? base->deletelabel : add->deletelabel;
|
|
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 (APR_SUCCESS != ap_cookie_check_string(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 *
|
|
Packit |
90a5c9 |
set_dbd_peruser(cmd_parms * parms, void *dconf, int flag)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
session_dbd_dir_conf *conf = dconf;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
conf->peruser = flag;
|
|
Packit |
90a5c9 |
conf->peruser_set = 1;
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
return NULL;
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
static const char *
|
|
Packit |
90a5c9 |
set_dbd_cookie_remove(cmd_parms * parms, void *dconf, int flag)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
session_dbd_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 char *set_cookie_name(cmd_parms * cmd, void *config, const char *args)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char *last;
|
|
Packit |
90a5c9 |
char *line = apr_pstrdup(cmd->pool, args);
|
|
Packit |
90a5c9 |
session_dbd_dir_conf *conf = (session_dbd_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, const char *args)
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
char *last;
|
|
Packit |
90a5c9 |
char *line = apr_pstrdup(cmd->pool, args);
|
|
Packit |
90a5c9 |
session_dbd_dir_conf *conf = (session_dbd_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 command_rec session_dbd_cmds[] =
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("SessionDBDSelectLabel", ap_set_string_slot,
|
|
Packit |
90a5c9 |
(void *) APR_OFFSETOF(session_dbd_dir_conf, selectlabel), RSRC_CONF|OR_AUTHCFG,
|
|
Packit |
90a5c9 |
"Query label used to select a new session"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("SessionDBDInsertLabel", ap_set_string_slot,
|
|
Packit |
90a5c9 |
(void *) APR_OFFSETOF(session_dbd_dir_conf, insertlabel), RSRC_CONF|OR_AUTHCFG,
|
|
Packit |
90a5c9 |
"Query label used to insert a new session"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("SessionDBDUpdateLabel", ap_set_string_slot,
|
|
Packit |
90a5c9 |
(void *) APR_OFFSETOF(session_dbd_dir_conf, updatelabel), RSRC_CONF|OR_AUTHCFG,
|
|
Packit |
90a5c9 |
"Query label used to update an existing session"),
|
|
Packit |
90a5c9 |
AP_INIT_TAKE1("SessionDBDDeleteLabel", ap_set_string_slot,
|
|
Packit |
90a5c9 |
(void *) APR_OFFSETOF(session_dbd_dir_conf, deletelabel), RSRC_CONF|OR_AUTHCFG,
|
|
Packit |
90a5c9 |
"Query label used to delete an existing session"),
|
|
Packit |
90a5c9 |
AP_INIT_FLAG("SessionDBDPerUser", set_dbd_peruser, NULL, RSRC_CONF|OR_AUTHCFG,
|
|
Packit |
90a5c9 |
"Save the session per user"),
|
|
Packit |
90a5c9 |
AP_INIT_FLAG("SessionDBDCookieRemove", set_dbd_cookie_remove, NULL, RSRC_CONF|OR_AUTHCFG,
|
|
Packit |
90a5c9 |
"Remove the session cookie after session load. On by default."),
|
|
Packit |
90a5c9 |
AP_INIT_RAW_ARGS("SessionDBDCookieName", set_cookie_name, NULL, RSRC_CONF|OR_AUTHCFG,
|
|
Packit |
90a5c9 |
"The name of the RFC2109 cookie carrying the session key"),
|
|
Packit |
90a5c9 |
AP_INIT_RAW_ARGS("SessionDBDCookieName2", set_cookie_name2, NULL, RSRC_CONF|OR_AUTHCFG,
|
|
Packit |
90a5c9 |
"The name of the RFC2965 cookie carrying the session key"),
|
|
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_dbd_load, NULL, NULL, APR_HOOK_MIDDLE);
|
|
Packit |
90a5c9 |
ap_hook_session_save(session_dbd_save, NULL, NULL, APR_HOOK_MIDDLE);
|
|
Packit |
90a5c9 |
ap_hook_monitor(session_dbd_monitor, NULL, NULL, APR_HOOK_MIDDLE);
|
|
Packit |
90a5c9 |
}
|
|
Packit |
90a5c9 |
|
|
Packit |
90a5c9 |
AP_DECLARE_MODULE(session_dbd) =
|
|
Packit |
90a5c9 |
{
|
|
Packit |
90a5c9 |
STANDARD20_MODULE_STUFF,
|
|
Packit |
90a5c9 |
create_session_dbd_dir_config, /* dir config creater */
|
|
Packit |
90a5c9 |
merge_session_dbd_dir_config, /* dir merger --- default is to
|
|
Packit |
90a5c9 |
* override */
|
|
Packit |
90a5c9 |
NULL, /* server config */
|
|
Packit |
90a5c9 |
NULL, /* merge server config */
|
|
Packit |
90a5c9 |
session_dbd_cmds, /* command apr_table_t */
|
|
Packit |
90a5c9 |
register_hooks /* register hooks */
|
|
Packit |
90a5c9 |
};
|