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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "mod_session.h"
19 #include "apr_strings.h"
21 #include "util_cookies.h"
23 #define LOG_PREFIX "mod_session_cookie: "
24 #define MOD_SESSION_COOKIE "mod_session_cookie"
26 module AP_MODULE_DECLARE_DATA session_cookie_module
;
29 * Structure to carry the per-dir session config.
34 const char *name_attrs
;
37 const char *name2_attrs
;
40 } session_cookie_dir_conf
;
43 * Set the cookie and embed the session within it.
45 * This function adds an RFC2109 compliant Set-Cookie header for
46 * the cookie specified in SessionCookieName, and an RFC2965 compliant
47 * Set-Cookie2 header for the cookie specified in SessionCookieName2.
49 * If specified, the optional cookie attributes will be added to
50 * each cookie. If defaults are not specified, DEFAULT_ATTRS
53 * On success, this method will return APR_SUCCESS.
55 * @param r The request pointer.
56 * @param z A pointer to where the session will be written.
58 static int session_cookie_save(request_rec
* r
, session_rec
* z
)
61 session_cookie_dir_conf
*conf
= ap_get_module_config(r
->per_dir_config
,
62 &session_cookie_module
);
64 /* don't cache auth protected pages */
65 apr_table_addn(r
->headers_out
, "Cache-Control", "no-cache");
67 /* create RFC2109 compliant cookie */
69 if (z
->encoded
&& z
->encoded
[0]) {
70 ap_cookie_write(r
, conf
->name
, z
->encoded
, conf
->name_attrs
, z
->maxage
, r
->headers_out
, r
->err_headers_out
, NULL
);
73 ap_cookie_remove(r
, conf
->name
, conf
->name_attrs
, r
->headers_out
, r
->err_headers_out
, NULL
);
77 /* create RFC2965 compliant cookie */
78 if (conf
->name2_set
) {
79 if (z
->encoded
&& z
->encoded
[0]) {
80 ap_cookie_write2(r
, conf
->name2
, z
->encoded
, conf
->name2_attrs
, z
->maxage
, r
->headers_out
, r
->err_headers_out
, NULL
);
83 ap_cookie_remove2(r
, conf
->name2
, conf
->name2_attrs
, r
->headers_out
, r
->err_headers_out
, NULL
);
87 if (conf
->name_set
|| conf
->name2_set
) {
95 * Isolate the cookie with the name "name", and if present, extract
96 * the payload from the cookie.
98 * If the cookie is found, the cookie and any other cookies with the
99 * same name are removed from the cookies passed in the request, so
100 * that credentials are not leaked to a backend server or process.
102 * A missing or malformed cookie will cause this function to return
105 * On success, this returns APR_SUCCESS.
107 static int session_cookie_load(request_rec
* r
, session_rec
** z
)
110 session_cookie_dir_conf
*conf
= ap_get_module_config(r
->per_dir_config
,
111 &session_cookie_module
);
113 session_rec
*zz
= NULL
;
114 const char *val
= NULL
;
115 const char *note
= NULL
;
116 const char *name
= NULL
;
119 /* find the first redirect */
123 /* find the main request */
128 /* is our session in a cookie? */
129 if (conf
->name2_set
) {
132 else if (conf
->name_set
) {
139 /* first look in the notes */
140 note
= apr_pstrcat(r
->pool
, MOD_SESSION_COOKIE
, name
, NULL
);
141 zz
= (session_rec
*)apr_table_get(m
->notes
, note
);
147 /* otherwise, try parse the cookie */
148 ap_cookie_read(r
, name
, &val
, conf
->remove
);
150 /* create a new session and return it */
151 zz
= (session_rec
*) apr_pcalloc(r
->pool
, sizeof(session_rec
));
153 zz
->entries
= apr_table_make(r
->pool
, 10);
155 zz
->uuid
= (apr_uuid_t
*) apr_pcalloc(r
->pool
, sizeof(apr_uuid_t
));
158 /* put the session in the notes so we don't have to parse it again */
159 apr_table_setn(m
->notes
, note
, (char *)zz
);
167 static void *create_session_cookie_dir_config(apr_pool_t
* p
, char *dummy
)
169 session_cookie_dir_conf
*new =
170 (session_cookie_dir_conf
*) apr_pcalloc(p
, sizeof(session_cookie_dir_conf
));
175 static void *merge_session_cookie_dir_config(apr_pool_t
* p
, void *basev
, void *addv
)
177 session_cookie_dir_conf
*new = (session_cookie_dir_conf
*) apr_pcalloc(p
, sizeof(session_cookie_dir_conf
));
178 session_cookie_dir_conf
*add
= (session_cookie_dir_conf
*) addv
;
179 session_cookie_dir_conf
*base
= (session_cookie_dir_conf
*) basev
;
181 new->name
= (add
->name_set
== 0) ? base
->name
: add
->name
;
182 new->name_attrs
= (add
->name_set
== 0) ? base
->name_attrs
: add
->name_attrs
;
183 new->name_set
= add
->name_set
|| base
->name_set
;
184 new->name2
= (add
->name2_set
== 0) ? base
->name2
: add
->name2
;
185 new->name2_attrs
= (add
->name2_set
== 0) ? base
->name2_attrs
: add
->name2_attrs
;
186 new->name2_set
= add
->name2_set
|| base
->name2_set
;
187 new->remove
= (add
->remove_set
== 0) ? base
->remove
: add
->remove
;
188 new->remove_set
= add
->remove_set
|| base
->remove_set
;
194 * Sanity check a given string that it exists, is not empty,
195 * and does not contain special characters.
197 static const char *check_string(cmd_parms
* cmd
, const char *string
)
199 if (!string
|| !*string
|| ap_strchr_c(string
, '=') || ap_strchr_c(string
, '&')) {
200 return apr_pstrcat(cmd
->pool
, cmd
->directive
->directive
,
201 " cannot be empty, or contain '=' or '&'.",
207 static const char *set_cookie_name(cmd_parms
* cmd
, void *config
, const char *args
)
210 char *line
= apr_pstrdup(cmd
->pool
, args
);
211 session_cookie_dir_conf
*conf
= (session_cookie_dir_conf
*) config
;
212 char *cookie
= apr_strtok(line
, " \t", &last
);
215 while (apr_isspace(*last
)) {
218 conf
->name_attrs
= last
;
219 return check_string(cmd
, cookie
);
222 static const char *set_cookie_name2(cmd_parms
* cmd
, void *config
, const char *args
)
225 char *line
= apr_pstrdup(cmd
->pool
, args
);
226 session_cookie_dir_conf
*conf
= (session_cookie_dir_conf
*) config
;
227 char *cookie
= apr_strtok(line
, " \t", &last
);
228 conf
->name2
= cookie
;
230 while (apr_isspace(*last
)) {
233 conf
->name2_attrs
= last
;
234 return check_string(cmd
, cookie
);
238 set_remove(cmd_parms
* parms
, void *dconf
, int flag
)
240 session_cookie_dir_conf
*conf
= dconf
;
243 conf
->remove_set
= 1;
248 static const command_rec session_cookie_cmds
[] =
250 AP_INIT_RAW_ARGS("SessionCookieName", set_cookie_name
, NULL
, RSRC_CONF
|OR_AUTHCFG
,
251 "The name of the RFC2109 cookie carrying the session"),
252 AP_INIT_RAW_ARGS("SessionCookieName2", set_cookie_name2
, NULL
, RSRC_CONF
|OR_AUTHCFG
,
253 "The name of the RFC2965 cookie carrying the session"),
254 AP_INIT_FLAG("SessionCookieRemove", set_remove
, NULL
, RSRC_CONF
|OR_AUTHCFG
,
255 "Set to 'On' to remove the session cookie from the headers "
256 "and hide the cookie from a backend server or process"),
260 static void register_hooks(apr_pool_t
* p
)
262 ap_hook_session_load(session_cookie_load
, NULL
, NULL
, APR_HOOK_MIDDLE
);
263 ap_hook_session_save(session_cookie_save
, NULL
, NULL
, APR_HOOK_MIDDLE
);
266 module AP_MODULE_DECLARE_DATA session_cookie_module
=
268 STANDARD20_MODULE_STUFF
,
269 create_session_cookie_dir_config
, /* dir config creater */
270 merge_session_cookie_dir_config
, /* dir merger --- default is to
272 NULL
, /* server config */
273 NULL
, /* merge server config */
274 session_cookie_cmds
, /* command apr_table_t */
275 register_hooks
/* register hooks */