summaryrefslogtreecommitdiff
path: root/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'session.c')
-rw-r--r--session.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/session.c b/session.c
new file mode 100644
index 0000000..ad114d4
--- /dev/null
+++ b/session.c
@@ -0,0 +1,309 @@
1/*
2 +----------------------------------------------------------------------+
3 | Suhosin Version 1 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2006-2007 The Hardened-PHP Project |
6 | Copyright (c) 2007-2016 SektionEins GmbH |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
16 | Authors: Stefan Esser <sesser@sektioneins.de> |
17 | Ben Fuhrmannek <ben.fuhrmannek@sektioneins.de> |
18 +----------------------------------------------------------------------+
19*/
20/*
21 $Id: session.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $
22*/
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "php.h"
29#include "SAPI.h"
30#include "php_ini.h"
31#include "zend_smart_str.h"
32#include "ext/standard/php_var.h"
33#include <fcntl.h>
34
35#include "php_suhosin7.h"
36
37#include "ext/hash/php_hash.h"
38
39#ifdef HAVE_PHP_SESSION
40#include "ext/session/php_session.h"
41
42#ifdef ZTS
43static ts_rsrc_id session_globals_id = 0;
44#define SESSION_G(v) ZEND_TSRMG(session_globals_id, php_ps_globals *, v)
45# ifdef COMPILE_DL_SESSION
46ZEND_TSRMLS_CACHE_EXTERN();
47# endif
48#else
49static php_ps_globals *session_globals = NULL;
50#define SESSION_G(v) (ps_globals.v)
51#endif
52
53#define COND_DUMB_SH key == NULL || ZSTR_LEN(key) == 0 || ZSTR_VAL(key)[0] == 0 \
54 || ZSTR_LEN(key) > SUHOSIN7_G(session_max_id_length) \
55 || ((mod_data == NULL || *mod_data == NULL) && !SESSION_G(mod_user_implemented))
56
57static void suhosin_send_cookie()
58{
59 int * session_send_cookie = &SESSION_G(send_cookie);
60 char * base;
61 zend_ini_entry *ini_entry;
62
63 /* The following is requires to be 100% compatible to PHP
64 versions where the hash extension is not available by default */
65 if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), ZEND_STRL("session.hash_bits_per_character"))) != NULL) {
66#ifndef ZTS
67 base = (char *) ini_entry->mh_arg2;
68#else
69 base = (char *) ts_resource(*((int *) ini_entry->mh_arg2));
70#endif
71 session_send_cookie = (int *) (base+(size_t) ini_entry->mh_arg1+sizeof(long));
72 }
73 *session_send_cookie = 1;
74}
75
76
77
78static ZEND_INI_MH((*old_OnUpdateSaveHandler)) = NULL;
79static int (*old_SessionRINIT)(INIT_FUNC_ARGS) = NULL;
80
81static int suhosin_hook_s_read(PS_READ_ARGS)
82{
83 zend_string *new_key = key;
84
85 /* protect session vars */
86/* if (SESSION_G(http_session_vars) && SESSION_G(http_session_vars)->type == IS_ARRAY) {
87 SESSION_G(http_session_vars)->refcount++;
88 }*/
89
90 /* protect dumb session handlers */
91 if (COND_DUMB_SH) {
92regenerate:
93 SDEBUG("regenerating key. old key was %s", key ? ZSTR_VAL(key) : "<NULL>");
94 zend_string_release(SESSION_G(id));
95 new_key = SESSION_G(id) = SESSION_G(mod)->s_create_sid(&SESSION_G(mod_data));
96 suhosin_send_cookie();
97 } else if (ZSTR_LEN(key) > SUHOSIN7_G(session_max_id_length)) {
98 suhosin_log(S_SESSION, "session id ('%s') exceeds maximum length - regenerating", ZSTR_VAL(key));
99 if (!SUHOSIN7_G(simulation)) {
100 goto regenerate;
101 }
102 }
103
104 int r = SUHOSIN7_G(old_s_read)(mod_data, new_key, val, maxlifetime);
105
106 if (r == SUCCESS && SUHOSIN7_G(session_encrypt) && val != NULL && *val != NULL && ZSTR_LEN(*val)) {
107 char cryptkey[33];
108
109 // SUHOSIN7_G(do_not_scan) = 1;
110 S7_GENERATE_KEY(session, cryptkey);
111
112 zend_string *orig_val = *val;
113 *val = suhosin_decrypt_string(ZSTR_VAL(*val), ZSTR_LEN(*val), "", 0, (char *)cryptkey, SUHOSIN7_G(session_checkraddr));
114 // SUHOSIN7_G(do_not_scan) = 0;
115 if (*val == NULL) {
116 *val = ZSTR_EMPTY_ALLOC();
117 }
118 zend_string_release(orig_val);
119 }
120
121 return r;
122}
123
124static int suhosin_hook_s_write(PS_WRITE_ARGS)
125{
126 /* protect dumb session handlers */
127 if (COND_DUMB_SH) {
128 return FAILURE;
129 }
130
131 if (ZSTR_LEN(val) > 0 && SUHOSIN7_G(session_encrypt)) {
132 char cryptkey[33];
133 // SUHOSIN7_G(do_not_scan) = 1;
134 S7_GENERATE_KEY(session, cryptkey);
135
136 zend_string *v = suhosin_encrypt_string(ZSTR_VAL(val), ZSTR_LEN(val), "", 0, cryptkey);
137
138 // SUHOSIN7_G(do_not_scan) = 0;
139 return SUHOSIN7_G(old_s_write)(mod_data, key, v, maxlifetime);
140 }
141
142 return SUHOSIN7_G(old_s_write)(mod_data, key, val, maxlifetime);
143
144// return_write:
145 /* protect session vars */
146/* if (SESSION_G(http_session_vars) && SESSION_G(http_session_vars)->type == IS_ARRAY) {
147 if (SESSION_G(http_session_vars)->refcount==1) {
148 nullify = 1;
149 }
150 zval_ptr_dtor(&SESSION_G(http_session_vars));
151 if (nullify) {
152 suhosin_log(S_SESSION, "possible session variables double free attack stopped");
153 SESSION_G(http_session_vars) = NULL;
154 }
155 }*/
156
157 // return r;
158}
159
160static int suhosin_hook_s_destroy(PS_DESTROY_ARGS)
161{
162 /* protect dumb session handlers */
163 if (COND_DUMB_SH) {
164 return FAILURE;
165 }
166
167 return SUHOSIN7_G(old_s_destroy)(mod_data, key);
168}
169
170static void suhosin_hook_session_module()
171{
172 ps_module *old_mod = SESSION_G(mod);
173 ps_module *mod;
174
175 if (old_mod == NULL || SUHOSIN7_G(s_module) == old_mod) {
176 return;
177 }
178
179 if (SUHOSIN7_G(s_module) == NULL) {
180 SUHOSIN7_G(s_module) = mod = malloc(sizeof(ps_module));
181 if (mod == NULL) {
182 return;
183 }
184 }
185
186 SUHOSIN7_G(s_original_mod) = old_mod;
187
188 mod = SUHOSIN7_G(s_module);
189 memcpy(mod, old_mod, sizeof(ps_module));
190
191 SUHOSIN7_G(old_s_read) = mod->s_read;
192 mod->s_read = suhosin_hook_s_read;
193 SUHOSIN7_G(old_s_write) = mod->s_write;
194 mod->s_write = suhosin_hook_s_write;
195 SUHOSIN7_G(old_s_destroy) = mod->s_destroy;
196 mod->s_destroy = suhosin_hook_s_destroy;
197
198 SESSION_G(mod) = mod;
199}
200
201static PHP_INI_MH(suhosin_OnUpdateSaveHandler)
202{
203 if (stage == PHP_INI_STAGE_RUNTIME
204 && SESSION_G(session_status) == php_session_none
205 && SUHOSIN7_G(s_original_mod)
206 && zend_string_equals_literal(new_value, "user") == 0
207 && strcmp(((ps_module*)SUHOSIN7_G(s_original_mod))->s_name, "user") == 0) {
208 return SUCCESS;
209 }
210
211 SESSION_G(mod) = SUHOSIN7_G(s_original_mod);
212
213 int r = old_OnUpdateSaveHandler(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
214
215 suhosin_hook_session_module();
216
217 return r;
218}
219
220
221static int suhosin_hook_session_RINIT(INIT_FUNC_ARGS)
222{
223 if (SESSION_G(mod) == NULL) {
224 zend_ini_entry *ini_entry;
225 if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), ZEND_STRL("session.save_handler")))) {
226 if (ini_entry->value) {
227 suhosin_OnUpdateSaveHandler(NULL, ini_entry->value, NULL, NULL, NULL, 0);
228 }
229 }
230 }
231 return old_SessionRINIT(INIT_FUNC_ARGS_PASSTHRU);
232}
233
234void suhosin_hook_session()
235{
236 zend_module_entry *module;
237
238 if ((module = zend_hash_str_find_ptr(&module_registry, ZEND_STRL("session"))) == NULL) {
239 return;
240 }
241 /* retrieve globals from module entry struct if possible */
242#ifdef ZTS
243 if (session_globals_id == 0) {
244 session_globals_id = *module->globals_id_ptr;
245 }
246#else
247 if (session_globals == NULL) {
248 session_globals = module->globals_ptr;
249 }
250#endif
251
252 if (old_OnUpdateSaveHandler != NULL) {
253 return;
254 }
255
256 /* hook request startup function of session module */
257 old_SessionRINIT = module->request_startup_func;
258 module->request_startup_func = suhosin_hook_session_RINIT;
259
260 /* retrieve pointer to session.save_handler ini entry */
261 zend_ini_entry *ini_entry;
262 if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), ZEND_STRL("session.save_handler"))) != NULL) {
263 /* replace OnUpdateMemoryLimit handler */
264 old_OnUpdateSaveHandler = ini_entry->on_modify;
265 ini_entry->on_modify = suhosin_OnUpdateSaveHandler;
266 }
267 SUHOSIN7_G(s_module) = NULL;
268
269 suhosin_hook_session_module();
270
271#if HAVE_DEV_URANDOM
272 /* increase session identifier entropy */
273 if (SESSION_G(entropy_length) == 0 || SESSION_G(entropy_file) == NULL) {
274 SESSION_G(entropy_length) = 16;
275 SESSION_G(entropy_file) = pestrdup("/dev/urandom", 1);
276 }
277#endif
278}
279
280// void suhosin_unhook_session()
281// {
282// if (old_OnUpdateSaveHandler == NULL) {
283// return;
284// }
285//
286// /* retrieve pointer to session.save_handler ini entry */
287// zend_ini_entry *ini_entry;
288// if ((ini_entry = zend_hash_find(EG(ini_directives), ZEND_STRL("session.save_handler"))) == NULL) {
289// return;
290// }
291// ini_entry->on_modify = old_OnUpdateSaveHandler;
292// old_OnUpdateSaveHandler = NULL;
293// }
294
295#else /* HAVE_PHP_SESSION */
296
297#warning BUILDING SUHOSIN WITHOUT SESSION SUPPORT
298
299#endif /* HAVE_PHP_SESSION */
300
301
302/*
303 * Local variables:
304 * tab-width: 4
305 * c-basic-offset: 4
306 * End:
307 * vim600: sw=4 ts=4 fdm=marker
308 * vim<600: sw=4 ts=4
309 */