mod_session_dbd.c revision 185aa71728867671e105178b4c66fbc22b65ae26
d5082de325fb6351c6bd34d28df0b43ec5a8ac90erikabele/* Licensed to the Apache Software Foundation (ASF) under one or more
d5082de325fb6351c6bd34d28df0b43ec5a8ac90erikabele * contributor license agreements. See the NOTICE file distributed with
d5082de325fb6351c6bd34d28df0b43ec5a8ac90erikabele * this work for additional information regarding copyright ownership.
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * The ASF licenses this file to You under the Apache License, Version 2.0
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * (the "License"); you may not use this file except in compliance with
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * the License. You may obtain a copy of the License at
5a58787efeb02a1c3f06569d019ad81fd2efa06end * Unless required by applicable law or agreed to in writing, software
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * distributed under the License is distributed on an "AS IS" BASIS,
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * See the License for the specific language governing permissions and
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * limitations under the License.
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * Structure to carry the per-dir session config.
5a58787efeb02a1c3f06569d019ad81fd2efa06endtypedef struct {
5a58787efeb02a1c3f06569d019ad81fd2efa06end const char *name;
5a58787efeb02a1c3f06569d019ad81fd2efa06end const char *name_attrs;
5a58787efeb02a1c3f06569d019ad81fd2efa06end const char *name2;
6f227ca67f7a591c2b1dbfd0f7ac31cc341061a5nd const char *name2_attrs;
5a58787efeb02a1c3f06569d019ad81fd2efa06end const char *selectlabel;
5a58787efeb02a1c3f06569d019ad81fd2efa06end const char *insertlabel;
1bf55339918c7e8ebf57ab686ff459c3f2651fcagryzor/* optional function - look it up once in post_config */
5a58787efeb02a1c3f06569d019ad81fd2efa06endstatic ap_dbd_t *(*session_dbd_acquire_fn) (request_rec *) = NULL;
5a58787efeb02a1c3f06569d019ad81fd2efa06endstatic void (*session_dbd_prepare_fn) (server_rec *, const char *, const char *) = NULL;
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * Initialise the database.
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * If the mod_dbd module is missing, this method will return APR_EGENERAL.
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowenstatic apr_status_t dbd_init(request_rec *r, const char *query, ap_dbd_t **dbdp,
6f227ca67f7a591c2b1dbfd0f7ac31cc341061a5nd if (!session_dbd_prepare_fn || !session_dbd_acquire_fn) {
6f227ca67f7a591c2b1dbfd0f7ac31cc341061a5nd session_dbd_prepare_fn = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_prepare);
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen session_dbd_acquire_fn = APR_RETRIEVE_OPTIONAL_FN(ap_dbd_acquire);
15292da5451dea4ad10c12d35d9addc88be302c5humbedooh if (!session_dbd_prepare_fn || !session_dbd_acquire_fn) {
15292da5451dea4ad10c12d35d9addc88be302c5humbedooh ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01850)
6f227ca67f7a591c2b1dbfd0f7ac31cc341061a5nd "You must load mod_dbd to enable AuthDBD functions");
c10e24e52c0f454df46a44e3ccc8ccb56abd9d2aslive ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01851)
c10e24e52c0f454df46a44e3ccc8ccb56abd9d2aslive "failed to acquire database connection");
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen statement = apr_hash_get(dbd->prepared, query, APR_HASH_KEY_STRING);
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01852)
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen "failed to find the prepared statement called '%s'", query);
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * Load the session by the key specified.
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowenstatic apr_status_t dbd_load(request_rec * r, const char *key, const char **val)
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen session_dbd_dir_conf *conf = ap_get_module_config(r->per_dir_config,
1bf55339918c7e8ebf57ab686ff459c3f2651fcagryzor ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01853)
bde4540877ce9bac98aec1d196a307b39c5c9775rbowen "no SessionDBDselectlabel has been specified");
bde4540877ce9bac98aec1d196a307b39c5c9775rbowen rv = dbd_init(r, conf->selectlabel, &dbd, &statement);
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen rv = apr_dbd_pvbselect(dbd->driver, r->pool, dbd->handle, &res, statement,
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01854)
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen "query execution error saving session '%s' "
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen "in database using query '%s': %s", key, conf->selectlabel,
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen for (rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1);
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1)) {
1bf55339918c7e8ebf57ab686ff459c3f2651fcagryzor if (rv != 0) {
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01855)
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen "error retrieving results while saving '%s' "
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen "in database using query '%s': %s", key, conf->selectlabel,
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen /* we can't break out here or row won't get cleaned up */
8a77625288bc7112717de423742309213a7d453erbowen * Load the session by firing off a dbd query.
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * If the session is anonymous, the session key will be extracted from
6f227ca67f7a591c2b1dbfd0f7ac31cc341061a5nd * the cookie specified. Failing that, the session key will be extracted
d5082de325fb6351c6bd34d28df0b43ec5a8ac90erikabele * from the GET parameters.
d5082de325fb6351c6bd34d28df0b43ec5a8ac90erikabele * If the session is keyed by the username, the session will be extracted
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * If no session is found, an empty session will be created.
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * On success, this returns OK.
6f227ca67f7a591c2b1dbfd0f7ac31cc341061a5ndstatic apr_status_t session_dbd_load(request_rec * r, session_rec ** z)
bde4540877ce9bac98aec1d196a307b39c5c9775rbowen session_dbd_dir_conf *conf = ap_get_module_config(r->per_dir_config,
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen /* is our session in a cookie? */
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen /* first look in the notes */
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen note = apr_pstrcat(r->pool, MOD_SESSION_DBD, name, NULL);
e487d6c09669296f94a5190cc34586a98e624a00nd /* load anonymous sessions */
15292da5451dea4ad10c12d35d9addc88be302c5humbedooh /* load an RFC2109 or RFC2965 compliant cookie */
6f227ca67f7a591c2b1dbfd0f7ac31cc341061a5nd /* load named session */
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen /* otherwise not for us */
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen /* create a new session and return it */
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen zz = (session_rec *) apr_pcalloc(r->pool, sizeof(session_rec));
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen zz->uuid = (apr_uuid_t *) apr_pcalloc(zz->pool, sizeof(apr_uuid_t));
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen /* put the session in the notes so we don't have to parse it again */
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * Save the session by the key specified.
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowenstatic apr_status_t dbd_save(request_rec * r, const char *key, const char *val,
2a80f5f5b2b28a9b603fc41d3e2b37128f5f1e00slive session_dbd_dir_conf *conf = ap_get_module_config(r->per_dir_config,
2a80f5f5b2b28a9b603fc41d3e2b37128f5f1e00slive ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01856)
2a80f5f5b2b28a9b603fc41d3e2b37128f5f1e00slive "no SessionDBDupdatelabel has been specified");
a720273cbea5177f46ba0550044a31f6363d3e4chumbedooh rv = dbd_init(r, conf->updatelabel, &dbd, &statement);
419d55842022e9e257941bfe226549661fb2c6c7humbedooh rv = apr_dbd_pvbquery(dbd->driver, r->pool, dbd->handle, &rows, statement,
419d55842022e9e257941bfe226549661fb2c6c7humbedooh ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01857)
2a80f5f5b2b28a9b603fc41d3e2b37128f5f1e00slive "query execution error updating session '%s' "
bcd392b291251e23c63d0cc4d11c9121e9627c24rbowen "using database query '%s': %s", key, conf->updatelabel,
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * if some rows were updated it means a session existed and was updated,
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * so we are done.
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen if (rows != 0) {
6f227ca67f7a591c2b1dbfd0f7ac31cc341061a5nd ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01858)
6f227ca67f7a591c2b1dbfd0f7ac31cc341061a5nd "no SessionDBDinsertlabel has been specified");
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen rv = dbd_init(r, conf->insertlabel, &dbd, &statement);
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen rv = apr_dbd_pvbquery(dbd->driver, r->pool, dbd->handle, &rows, statement,
15292da5451dea4ad10c12d35d9addc88be302c5humbedooh ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01859)
15292da5451dea4ad10c12d35d9addc88be302c5humbedooh "query execution error inserting session '%s' "
15292da5451dea4ad10c12d35d9addc88be302c5humbedooh "in database with '%s': %s", key, conf->insertlabel,
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * if some rows were inserted it means a session was inserted, so we are
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen if (rows != 0) {
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01860)
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen "the session insert query did not cause any rows to be added "
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen "to the database for session '%s', session not inserted", key);
15292da5451dea4ad10c12d35d9addc88be302c5humbedooh * Remove the session by the key specified.
419d55842022e9e257941bfe226549661fb2c6c7humbedoohstatic apr_status_t dbd_remove(request_rec * r, const char *key)
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen session_dbd_dir_conf *conf = ap_get_module_config(r->per_dir_config,
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01861)
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen "failed to acquire database connection to remove "
15292da5451dea4ad10c12d35d9addc88be302c5humbedooh ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01862)
419d55842022e9e257941bfe226549661fb2c6c7humbedooh "no SessionDBDdeletelabel has been specified");
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen statement = apr_hash_get(dbd->prepared, conf->deletelabel,
419d55842022e9e257941bfe226549661fb2c6c7humbedooh ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01863)
15292da5451dea4ad10c12d35d9addc88be302c5humbedooh "prepared statement could not be found for "
15292da5451dea4ad10c12d35d9addc88be302c5humbedooh "SessionDBDdeletelabel with the label '%s'",
6f227ca67f7a591c2b1dbfd0f7ac31cc341061a5nd rv = apr_dbd_pvbquery(dbd->driver, r->pool, dbd->handle, &rows, statement,
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01864)
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen "query execution error removing session '%s' "
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * Clean out expired sessions.
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * TODO: We need to figure out a way to clean out expired sessions from the database.
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * The monitor hook doesn't help us that much, as we have no handle into the
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowen * server, and so we need to come up with a way to do this safely.
47bbfaa3a2ea0afb775a3aa3e7dbf8a71ea1b966rbowenstatic apr_status_t dbd_clean(apr_pool_t *p, server_rec *s)
1baec6e12c9c698202c8cd880b8013431f7542c9rbowen * Save the session by firing off a dbd query.
1baec6e12c9c698202c8cd880b8013431f7542c9rbowen * If the session is anonymous, save the session and write a cookie
1baec6e12c9c698202c8cd880b8013431f7542c9rbowen * containing the uuid.
1baec6e12c9c698202c8cd880b8013431f7542c9rbowen * If the session is keyed to the username, save the session using
1baec6e12c9c698202c8cd880b8013431f7542c9rbowen * the username as a key.
1baec6e12c9c698202c8cd880b8013431f7542c9rbowen * On success, this method will return APR_SUCCESS.
1bf55339918c7e8ebf57ab686ff459c3f2651fcagryzor * @param r The request pointer.
1baec6e12c9c698202c8cd880b8013431f7542c9rbowen * @param z A pointer to where the session will be written.
1baec6e12c9c698202c8cd880b8013431f7542c9rbowenstatic apr_status_t session_dbd_save(request_rec * r, session_rec * z)
1baec6e12c9c698202c8cd880b8013431f7542c9rbowen session_dbd_dir_conf *conf = ap_get_module_config(r->per_dir_config,
6f227ca67f7a591c2b1dbfd0f7ac31cc341061a5nd /* support anonymous sessions */
980bee71ed017c72bfdd9861445f9495855508ccgryzor /* don't cache pages with a session */
7f5b59ccc63c0c0e3e678a168f09ee6a2f51f9d0nd apr_table_addn(r->headers_out, "Cache-Control", "no-cache");
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung /* must we create a uuid? */
ed62c84ee0911cfebbd8da319ac00757b555707chumbedooh buffer = apr_pcalloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1);
ed62c84ee0911cfebbd8da319ac00757b555707chumbedooh /* save the session with the uuid as key */
0d0ba3a410038e179b695446bb149cce6264e0abnd /* create RFC2109 compliant cookie */
0d0ba3a410038e179b695446bb149cce6264e0abnd ap_cookie_write(r, conf->name, buffer, conf->name_attrs, z->maxage,
d229f940abfb2490dee17979e9a5ff31b7012eb5rbowen /* create RFC2965 compliant cookie */
7fec19672a491661b2fe4b29f685bc7f4efa64d4nd ap_cookie_write2(r, conf->name2, buffer, conf->name2_attrs, z->maxage,
return OK;
if (r->user) {
return ret;
return OK;
return DECLINED;
dbd_clean(p, s);
return OK;
return (void *) new;
return new;
NULL);
return NULL;
return NULL;
return NULL;
char *last;
last++;
char *last;
last++;
{NULL}