1 #include "php_snuffleupagus.h"
2
3 #if (HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION))
4
5 #ifdef ZTS
6 static ts_rsrc_id session_globals_id = 0;
7 #define SESSION_G(v) ZEND_TSRMG(session_globals_id, php_ps_globals *, v)
8 #ifdef COMPILE_DL_SESSION
9 ZEND_TSRMLS_CACHE_EXTERN();
10 #endif
11 #else
12 static php_ps_globals *session_globals = NULL;
13 #define SESSION_G(v) (ps_globals.v)
14 #endif
15
16 static ps_module *s_module;
17 #if PHP_VERSION_ID < 70300
18 static ps_module *s_original_mod;
19 #else
20 static const ps_module *s_original_mod;
21 #endif
22 static int (*old_s_read)(PS_READ_ARGS);
23 static int (*old_s_write)(PS_WRITE_ARGS);
24 static int (*previous_sessionRINIT)(INIT_FUNC_ARGS) = NULL;
25 static ZEND_INI_MH((*old_OnUpdateSaveHandler)) = NULL;
26
sp_hook_s_read(PS_READ_ARGS)27 static int sp_hook_s_read(PS_READ_ARGS) {
28 int r = old_s_read(mod_data, key, val, maxlifetime);
29 const sp_config_session *config_session =
30 SNUFFLEUPAGUS_G(config).config_session;
31
32 if ((NULL == val) || (NULL == *val) || (0 == ZSTR_LEN(*val))) {
33 return r;
34 }
35
36 if (r == SUCCESS && config_session->encrypt) {
37 zend_string *orig_val = *val;
38 zval val_zval;
39 ZVAL_PSTRINGL(&val_zval, ZSTR_VAL(*val), ZSTR_LEN(*val));
40
41 int ret = decrypt_zval(&val_zval, config_session->simulation, NULL);
42 if (ZEND_HASH_APPLY_KEEP != ret) {
43 zend_bailout();
44 }
45
46 *val = zend_string_dup(val_zval.value.str, 0);
47 zend_string_release(orig_val);
48 }
49
50 return r;
51 }
52
sp_hook_s_write(PS_WRITE_ARGS)53 static int sp_hook_s_write(PS_WRITE_ARGS) {
54 if (ZSTR_LEN(val) > 0 && SNUFFLEUPAGUS_G(config).config_session->encrypt) {
55 zend_string *new_val = encrypt_zval(val);
56 return old_s_write(mod_data, key, new_val, maxlifetime);
57 }
58 return old_s_write(mod_data, key, val, maxlifetime);
59 }
60
sp_hook_session_module()61 static void sp_hook_session_module() {
62 #if PHP_VERSION_ID < 70300
63 ps_module *old_mod = SESSION_G(mod);
64 #else
65 const ps_module *old_mod = SESSION_G(mod);
66 #endif
67 ps_module *mod;
68
69 if (old_mod == NULL || s_module == old_mod) {
70 return; // LCOV_EXCL_LINE
71 }
72
73 if (s_module == NULL) {
74 s_module = mod = malloc(sizeof(ps_module));
75 if (mod == NULL) {
76 return; // LCOV_EXCL_LINE
77 }
78 }
79
80 s_original_mod = old_mod;
81
82 mod = s_module;
83 memcpy(mod, old_mod, sizeof(ps_module));
84
85 old_s_read = mod->s_read;
86 mod->s_read = sp_hook_s_read;
87
88 old_s_write = mod->s_write;
89 mod->s_write = sp_hook_s_write;
90
91 SESSION_G(mod) = mod;
92 }
93
PHP_INI_MH(sp_OnUpdateSaveHandler)94 static PHP_INI_MH(sp_OnUpdateSaveHandler) {
95 #if PHP_VERSION_ID < 70100
96 /* PHP7.0 doesn't handle well recusively set session handlers */
97 if (stage == PHP_INI_STAGE_RUNTIME &&
98 SESSION_G(session_status) == php_session_none && s_original_mod &&
99 zend_string_equals_literal(new_value, "user") == 0 &&
100 strcmp(((ps_module *)s_original_mod)->s_name, "user") == 0) {
101 return SUCCESS;
102 }
103 #endif
104
105 SESSION_G(mod) = s_original_mod;
106
107 int r = old_OnUpdateSaveHandler(entry, new_value, mh_arg1, mh_arg2, mh_arg3,
108 stage);
109
110 sp_hook_session_module();
111
112 return r;
113 }
114
sp_hook_session_RINIT(INIT_FUNC_ARGS)115 static int sp_hook_session_RINIT(INIT_FUNC_ARGS) {
116 if (SESSION_G(mod) == NULL) {
117 zend_ini_entry *ini_entry;
118 if ((ini_entry = zend_hash_str_find_ptr(
119 EG(ini_directives), ZEND_STRL("session.save_handler")))) {
120 if (ini_entry->value) {
121 sp_OnUpdateSaveHandler(NULL, ini_entry->value, NULL, NULL, NULL, 0);
122 }
123 }
124 }
125 return previous_sessionRINIT(INIT_FUNC_ARGS_PASSTHRU);
126 }
127
hook_session()128 void hook_session() {
129 zend_module_entry *module;
130
131 if ((module = zend_hash_str_find_ptr(&module_registry,
132 ZEND_STRL("session"))) == NULL) {
133 return; // LCOV_EXCL_LINE
134 }
135
136 #ifdef ZTS
137 if (session_globals_id == 0) {
138 session_globals_id = *module->globals_id_ptr;
139 }
140 #else
141 if (session_globals == NULL) {
142 session_globals = module->globals_ptr;
143 }
144 #endif
145 if (old_OnUpdateSaveHandler != NULL) {
146 return; // LCOV_EXCL_LINE
147 }
148
149 previous_sessionRINIT = module->request_startup_func;
150 module->request_startup_func = sp_hook_session_RINIT;
151
152 zend_ini_entry *ini_entry;
153 if ((ini_entry = zend_hash_str_find_ptr(
154 EG(ini_directives), ZEND_STRL("session.save_handler"))) != NULL) {
155 old_OnUpdateSaveHandler = ini_entry->on_modify;
156 ini_entry->on_modify = sp_OnUpdateSaveHandler;
157 }
158 s_module = NULL;
159
160 sp_hook_session_module();
161 }
162
163 #else
164
hook_session()165 void hook_session() {}
166
167 #endif // HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
168