Apache HTTPD
mod_session_dbd.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "mod_session.h"
18#include "apr_lib.h"
19#include "apr_strings.h"
20#include "http_log.h"
21#include "util_cookies.h"
22#include "apr_dbd.h"
23#include "mod_dbd.h"
24#include "mpm_common.h"
25
26#define MOD_SESSION_DBD "mod_session_dbd"
27
28module AP_MODULE_DECLARE_DATA session_dbd_module;
29
33typedef struct {
34 const char *name;
36 const char *name_attrs;
37 const char *name2;
39 const char *name2_attrs;
42 int remove;
44 const char *selectlabel;
45 const char *insertlabel;
46 const char *updatelabel;
47 const char *deletelabel;
49
50/* optional function - look it up once in post_config */
51static ap_dbd_t *(*session_dbd_acquire_fn) (request_rec *) = NULL;
52static void (*session_dbd_prepare_fn) (server_rec *, const char *, const char *) = NULL;
53
61{
64
70 "You must load mod_dbd to enable AuthDBD functions");
71 return APR_EGENERAL;
72 }
73 }
74
76 if (!dbd) {
78 "failed to acquire database connection");
79 return APR_EGENERAL;
80 }
81
83 if (!statement) {
85 "failed to find the prepared statement called '%s'", query);
86 return APR_EGENERAL;
87 }
88
89 *dbdp = dbd;
91
92 return APR_SUCCESS;
93}
94
101 const char *key, const char **val)
102{
103
104 apr_status_t rv;
105 ap_dbd_t *dbd = NULL;
110
112 &session_dbd_module);
113
114 if (conf->selectlabel == NULL) {
116 "no SessionDBDselectlabel has been specified");
117 return APR_EGENERAL;
118 }
119
120 rv = dbd_init(r, conf->selectlabel, &dbd, &statement);
121 if (rv) {
122 return rv;
123 }
124 rv = apr_dbd_pvbselect(dbd->driver, r->pool, dbd->handle, &res, statement,
125 0, key, &expiry, NULL);
126 if (rv) {
128 "query execution error saving session '%s' "
129 "in database using query '%s': %s", key, conf->selectlabel,
130 apr_dbd_error(dbd->driver, dbd->handle, rv));
131 return APR_EGENERAL;
132 }
133 for (rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1);
134 rv != -1;
135 rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1)) {
136 if (rv != 0) {
138 "error retrieving results while saving '%s' "
139 "in database using query '%s': %s", key, conf->selectlabel,
140 apr_dbd_error(dbd->driver, dbd->handle, rv));
141 return APR_EGENERAL;
142 }
143 if (*val == NULL) {
144 *val = apr_pstrdup(p, apr_dbd_get_entry(dbd->driver, row, 0));
145 }
146 /* we can't break out here or row won't get cleaned up */
147 }
148
149 return APR_SUCCESS;
150
151}
152
168{
169
171 &session_dbd_module);
172
175 const char *name = NULL;
176 const char *note = NULL;
177 const char *val = NULL;
178 const char *key = NULL;
179 request_rec *m = r->main ? r->main : r;
180
181 /* is our session in a cookie? */
182 if (conf->name2_set) {
183 name = conf->name2;
184 }
185 else if (conf->name_set) {
186 name = conf->name;
187 }
188 else if (conf->peruser_set && r->user) {
189 name = r->user;
190 }
191 else {
192 return DECLINED;
193 }
194
195 /* first look in the notes */
197 zz = (session_rec *)apr_table_get(m->notes, note);
198 if (zz) {
199 *z = zz;
200 return OK;
201 }
202
203 /* load anonymous sessions */
204 if (conf->name_set || conf->name2_set) {
205
206 /* load an RFC2109 or RFC2965 compliant cookie */
207 ap_cookie_read(r, name, &key, conf->remove);
208 if (key) {
209 ret = dbd_load(m->pool, r, key, &val);
210 if (ret != APR_SUCCESS) {
211 return ret;
212 }
213 }
214
215 }
216
217 /* load named session */
218 else if (conf->peruser) {
219 if (r->user) {
220 ret = dbd_load(m->pool, r, r->user, &val);
221 if (ret != APR_SUCCESS) {
222 return ret;
223 }
224 }
225 }
226
227 /* otherwise not for us */
228 else {
229 return DECLINED;
230 }
231
232 /* create a new session and return it */
233 zz = (session_rec *) apr_pcalloc(m->pool, sizeof(session_rec));
234 zz->pool = m->pool;
235 zz->entries = apr_table_make(zz->pool, 10);
236 if (key && val) {
237 apr_uuid_t *uuid = apr_pcalloc(zz->pool, sizeof(apr_uuid_t));
239 zz->uuid = uuid;
240 }
241 }
242 zz->encoded = val;
243 *z = zz;
244
245 /* put the session in the notes so we don't have to parse it again */
246 apr_table_setn(m->notes, note, (char *)zz);
247
248 /* don't cache pages with a session */
249 apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private");
250
251 return OK;
252
253}
254
259 const char *newkey, const char *val, apr_int64_t expiry)
260{
261
262 apr_status_t rv;
263 ap_dbd_t *dbd = NULL;
265 int rows = 0;
266
268 &session_dbd_module);
269
270 if (conf->updatelabel == NULL) {
272 "no SessionDBDupdatelabel has been specified");
273 return APR_EGENERAL;
274 }
275
276 rv = dbd_init(r, conf->updatelabel, &dbd, &statement);
277 if (rv) {
278 return rv;
279 }
280
281 if (oldkey) {
282 rv = apr_dbd_pvbquery(dbd->driver, r->pool, dbd->handle, &rows,
283 statement, val, &expiry, newkey, oldkey, NULL);
284 if (rv) {
286 APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01857) "query execution error updating session '%s' "
287 "using database query '%s': %s/%s", oldkey, newkey, conf->updatelabel, apr_dbd_error(dbd->driver, dbd->handle, rv));
288 return APR_EGENERAL;
289 }
290
291 /*
292 * if some rows were updated it means a session existed and was updated,
293 * so we are done.
294 */
295 if (rows != 0) {
296 return APR_SUCCESS;
297 }
298 }
299
300 if (conf->insertlabel == NULL) {
302 "no SessionDBDinsertlabel has been specified");
303 return APR_EGENERAL;
304 }
305
306 rv = dbd_init(r, conf->insertlabel, &dbd, &statement);
307 if (rv) {
308 return rv;
309 }
310 rv = apr_dbd_pvbquery(dbd->driver, r->pool, dbd->handle, &rows, statement,
311 val, &expiry, newkey, NULL);
312 if (rv) {
314 "query execution error inserting session '%s' "
315 "in database with '%s': %s", newkey, conf->insertlabel,
316 apr_dbd_error(dbd->driver, dbd->handle, rv));
317 return APR_EGENERAL;
318 }
319
320 /*
321 * if some rows were inserted it means a session was inserted, so we are
322 * done.
323 */
324 if (rows != 0) {
325 return APR_SUCCESS;
326 }
327
329 "the session insert query did not cause any rows to be added "
330 "to the database for session '%s', session not inserted", newkey);
331
332 return APR_EGENERAL;
333
334}
335
340{
341
342 apr_status_t rv;
343 ap_dbd_t *dbd;
345 int rows = 0;
346
348 &session_dbd_module);
349
350 if (conf->deletelabel == NULL) {
352 "no SessionDBDdeletelabel has been specified");
353 return APR_EGENERAL;
354 }
355
356 rv = dbd_init(r, conf->deletelabel, &dbd, &statement);
357 if (rv != APR_SUCCESS) {
358 /* No need to do additional error logging here, it has already
359 been done in dbd_init if needed */
360 return rv;
361 }
362
363 rv = apr_dbd_pvbquery(dbd->driver, r->pool, dbd->handle, &rows, statement,
364 key, NULL);
365 if (rv != APR_SUCCESS) {
367 "query execution error removing session '%s' "
368 "from database", key);
369 return rv;
370 }
371
372 return APR_SUCCESS;
373
374}
375
384{
385
386 return APR_ENOTIMPL;
387
388}
389
405{
406
409 &session_dbd_module);
410
411 /* support anonymous sessions */
412 if (conf->name_set || conf->name2_set) {
413 char *oldkey = NULL, *newkey = NULL;
414
415 /* if the session is new or changed, make a new session ID */
416 if (z->uuid) {
418 apr_uuid_format(oldkey, z->uuid);
419 }
420 if (z->dirty || !oldkey) {
421 z->uuid = apr_pcalloc(z->pool, sizeof(apr_uuid_t));
422 apr_uuid_get(z->uuid);
424 apr_uuid_format(newkey, z->uuid);
425 }
426 else {
427 newkey = oldkey;
428 }
429
430 /* save the session with the uuid as key */
431 if (z->encoded && z->encoded[0]) {
432 ret = dbd_save(r, oldkey, newkey, z->encoded, z->expiry);
433 }
434 else {
436 }
437 if (ret != APR_SUCCESS) {
438 return ret;
439 }
440
441 /* create RFC2109 compliant cookie */
442 if (conf->name_set) {
443 ap_cookie_write(r, conf->name, newkey, conf->name_attrs, z->maxage,
445 }
446
447 /* create RFC2965 compliant cookie */
448 if (conf->name2_set) {
449 ap_cookie_write2(r, conf->name2, newkey, conf->name2_attrs, z->maxage,
451 }
452
453 return OK;
454
455 }
456
457 /* save named session */
458 else if (conf->peruser) {
459
460 /* don't cache pages with a session */
461 apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private");
462
463 if (r->user) {
464 ret = dbd_save(r, r->user, r->user, z->encoded, z->expiry);
465 if (ret != APR_SUCCESS) {
466 return ret;
467 }
468 return OK;
469 }
470 else {
472 "peruser sessions can only be saved if a user is logged in, "
473 "session not saved: %s", r->uri);
474 }
475 }
476
477 return DECLINED;
478
479}
480
486{
487 /* TODO handle housekeeping */
488 dbd_clean(p, s);
489 return OK;
490}
491
492
494{
497
498 new->remove = 1;
499
500 new->selectlabel = "selectsession";
501 new->insertlabel = "insertsession";
502 new->updatelabel = "updatesession";
503 new->deletelabel = "deletesession";
504
505 return (void *) new;
506}
507
509{
513
514 new->name = (add->name_set == 0) ? base->name : add->name;
515 new->name_attrs = (add->name_set == 0) ? base->name_attrs : add->name_attrs;
516 new->name_set = add->name_set || base->name_set;
517 new->name2 = (add->name2_set == 0) ? base->name2 : add->name2;
518 new->name2_attrs = (add->name2_set == 0) ? base->name2_attrs : add->name2_attrs;
519 new->name2_set = add->name2_set || base->name2_set;
520 new->peruser = (add->peruser_set == 0) ? base->peruser : add->peruser;
521 new->peruser_set = add->peruser_set || base->peruser_set;
522 new->remove = (add->remove_set == 0) ? base->remove : add->remove;
523 new->remove_set = add->remove_set || base->remove_set;
524 new->selectlabel = (!add->selectlabel) ? base->selectlabel : add->selectlabel;
525 new->updatelabel = (!add->updatelabel) ? base->updatelabel : add->updatelabel;
526 new->insertlabel = (!add->insertlabel) ? base->insertlabel : add->insertlabel;
527 new->deletelabel = (!add->deletelabel) ? base->deletelabel : add->deletelabel;
528
529 return new;
530}
531
536static const char *check_string(cmd_parms * cmd, const char *string)
537{
538 if (APR_SUCCESS != ap_cookie_check_string(string)) {
539 return apr_pstrcat(cmd->pool, cmd->directive->directive,
540 " cannot be empty, or contain '=', ';' or '&'.",
541 NULL);
542 }
543 return NULL;
544}
545
546static const char *
547 set_dbd_peruser(cmd_parms * parms, void *dconf, int flag)
548{
549 session_dbd_dir_conf *conf = dconf;
550
551 conf->peruser = flag;
552 conf->peruser_set = 1;
553
554 return NULL;
555}
556
557static const char *
559{
560 session_dbd_dir_conf *conf = dconf;
561
562 conf->remove = flag;
563 conf->remove_set = 1;
564
565 return NULL;
566}
567
568static const char *set_cookie_name(cmd_parms * cmd, void *config, const char *args)
569{
570 char *last;
571 char *line = apr_pstrdup(cmd->pool, args);
573 char *cookie = apr_strtok(line, " \t", &last);
574 conf->name = cookie;
575 conf->name_set = 1;
576 while (apr_isspace(*last)) {
577 last++;
578 }
579 conf->name_attrs = last;
580 return check_string(cmd, cookie);
581}
582
583static const char *set_cookie_name2(cmd_parms * cmd, void *config, const char *args)
584{
585 char *last;
586 char *line = apr_pstrdup(cmd->pool, args);
588 char *cookie = apr_strtok(line, " \t", &last);
589 conf->name2 = cookie;
590 conf->name2_set = 1;
591 while (apr_isspace(*last)) {
592 last++;
593 }
594 conf->name2_attrs = last;
595 return check_string(cmd, cookie);
596}
597
599{
600 AP_INIT_TAKE1("SessionDBDSelectLabel", ap_set_string_slot,
602 "Query label used to select a new session"),
603 AP_INIT_TAKE1("SessionDBDInsertLabel", ap_set_string_slot,
605 "Query label used to insert a new session"),
606 AP_INIT_TAKE1("SessionDBDUpdateLabel", ap_set_string_slot,
608 "Query label used to update an existing session"),
609 AP_INIT_TAKE1("SessionDBDDeleteLabel", ap_set_string_slot,
611 "Query label used to delete an existing session"),
613 "Save the session per user"),
614 AP_INIT_FLAG("SessionDBDCookieRemove", set_dbd_cookie_remove, NULL, RSRC_CONF|OR_AUTHCFG,
615 "Remove the session cookie after session load. On by default."),
616 AP_INIT_RAW_ARGS("SessionDBDCookieName", set_cookie_name, NULL, RSRC_CONF|OR_AUTHCFG,
617 "The name of the RFC2109 cookie carrying the session key"),
618 AP_INIT_RAW_ARGS("SessionDBDCookieName2", set_cookie_name2, NULL, RSRC_CONF|OR_AUTHCFG,
619 "The name of the RFC2965 cookie carrying the session key"),
620 {NULL}
621};
622
629
631{
633 create_session_dbd_dir_config, /* dir config creater */
634 merge_session_dbd_dir_config, /* dir merger --- default is to
635 * override */
636 NULL, /* server config */
637 NULL, /* merge server config */
638 session_dbd_cmds, /* command apr_table_t */
639 register_hooks /* register hooks */
640};
APR-UTIL DBD library.
APR general purpose library routines.
APR Strings library.
#define AP_INIT_TAKE1(directive, func, mconfig, where, help)
#define ap_get_module_config(v, m)
#define AP_DECLARE_MODULE(foo)
#define AP_INIT_FLAG(directive, func, mconfig, where, help)
ap_conf_vector_t * base
#define AP_INIT_RAW_ARGS(directive, func, mconfig, where, help)
const char * ap_set_string_slot(cmd_parms *cmd, void *struct_ptr, const char *arg)
Definition config.c:1469
request_rec * r
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define APLOG_MARK
Definition http_log.h:283
void * dummy
Definition http_vhost.h:62
void ap_hook_monitor(ap_HOOK_monitor_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mpm_common.c:91
#define APR_EGENERAL
Definition apr_errno.h:313
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_UUID_FORMATTED_LENGTH
Definition apr_uuid.h:46
const apr_uuid_t * uuid
Definition apr_uuid.h:62
apr_pool_t apr_dbd_t const char * query
Definition apr_dbd.h:396
struct apr_dbd_prepared_t apr_dbd_prepared_t
Definition apr_dbd.h:87
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
apr_dbd_t int const char * statement
Definition apr_dbd.h:272
struct apr_dbd_results_t apr_dbd_results_t
Definition apr_dbd.h:85
apr_pool_t apr_dbd_results_t apr_dbd_row_t ** row
Definition apr_dbd.h:320
struct apr_dbd_row_t apr_dbd_row_t
Definition apr_dbd.h:86
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define APR_RETRIEVE_OPTIONAL_FN(name)
#define RSRC_CONF
#define OR_AUTHCFG
ap_dbd_t * ap_dbd_acquire(request_rec *r)
Definition mod_dbd.c:929
void ap_dbd_prepare(server_rec *s, const char *query, const char *label)
Definition mod_dbd.c:313
void ap_hook_session_save(ap_HOOK_session_save_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mod_session.c:37
void ap_hook_session_load(ap_HOOK_session_load_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition mod_session.c:35
#define STANDARD20_MODULE_STUFF
apr_size_t size
apr_uint32_t val
Definition apr_atomic.h:66
#define apr_isspace(c)
Definition apr_lib.h:225
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char * key
const char apr_int32_t flag
#define APR_HASH_KEY_STRING
Definition apr_hash.h:47
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char char ** last
const char * s
Definition apr_strings.h:95
const void * m
apr_cmdtype_e cmd
const char const char *const * args
Apache Logging library.
apr_pool_t * p
Definition md_event.c:32
Database Access Extension Module for Apache.
Session Module for Apache.
static const char * set_dbd_peruser(cmd_parms *parms, void *dconf, int flag)
static apr_status_t dbd_load(apr_pool_t *p, request_rec *r, const char *key, const char **val)
static apr_status_t session_dbd_save(request_rec *r, session_rec *z)
static const char * set_cookie_name2(cmd_parms *cmd, void *config, const char *args)
static apr_status_t session_dbd_load(request_rec *r, session_rec **z)
static void(* session_dbd_prepare_fn)(server_rec *, const char *, const char *)
static apr_status_t dbd_init(request_rec *r, const char *query, ap_dbd_t **dbdp, apr_dbd_prepared_t **statementp)
static ap_dbd_t *(* session_dbd_acquire_fn)(request_rec *)
static apr_status_t dbd_clean(apr_pool_t *p, server_rec *s)
static void register_hooks(apr_pool_t *p)
static int session_dbd_monitor(apr_pool_t *p, server_rec *s)
static void * create_session_dbd_dir_config(apr_pool_t *p, char *dummy)
#define MOD_SESSION_DBD
static const char * set_dbd_cookie_remove(cmd_parms *parms, void *dconf, int flag)
static const char * set_cookie_name(cmd_parms *cmd, void *config, const char *args)
static apr_status_t dbd_save(request_rec *r, const char *oldkey, const char *newkey, const char *val, apr_int64_t expiry)
static const char * check_string(cmd_parms *cmd, const char *string)
static const command_rec session_dbd_cmds[]
static apr_status_t dbd_remove(request_rec *r, const char *key)
static void * merge_session_dbd_dir_config(apr_pool_t *p, void *basev, void *addv)
return NULL
Definition mod_so.c:359
Multi-Processing Modules functions.
char * name
A structure that represents the current request.
Definition httpd.h:845
char * user
Definition httpd.h:1005
char * uri
Definition httpd.h:1016
apr_pool_t * pool
Definition httpd.h:847
apr_table_t * err_headers_out
Definition httpd.h:981
request_rec * main
Definition httpd.h:860
struct ap_conf_vector_t * per_dir_config
Definition httpd.h:1047
apr_table_t * headers_out
Definition httpd.h:978
A structure to store information for each virtual server.
Definition httpd.h:1322
Apache cookie library.