diff options
Diffstat (limited to 'session.c')
| -rw-r--r-- | session.c | 309 |
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 | ||
| 43 | static 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 | ||
| 46 | ZEND_TSRMLS_CACHE_EXTERN(); | ||
| 47 | # endif | ||
| 48 | #else | ||
| 49 | static 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 | |||
| 57 | static 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 | |||
| 78 | static ZEND_INI_MH((*old_OnUpdateSaveHandler)) = NULL; | ||
| 79 | static int (*old_SessionRINIT)(INIT_FUNC_ARGS) = NULL; | ||
| 80 | |||
| 81 | static 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) { | ||
| 92 | regenerate: | ||
| 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 | |||
| 124 | static 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 | |||
| 160 | static 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 | |||
| 170 | static 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 | |||
| 201 | static 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 | |||
| 221 | static 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 | |||
| 234 | void 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 | */ | ||
