1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Author: Sascha Schumann <sascha@schumann.cx> |
14 +----------------------------------------------------------------------+
15 */
16
17 #include "php.h"
18 #include "php_session.h"
19 #include "mod_user.h"
20
21 const ps_module ps_mod_user = {
22 PS_MOD_UPDATE_TIMESTAMP(user)
23 };
24
25
ps_call_handler(zval * func,int argc,zval * argv,zval * retval)26 static void ps_call_handler(zval *func, int argc, zval *argv, zval *retval)
27 {
28 int i;
29 if (PS(in_save_handler)) {
30 PS(in_save_handler) = 0;
31 ZVAL_UNDEF(retval);
32 php_error_docref(NULL, E_WARNING, "Cannot call session save handler in a recursive manner");
33 return;
34 }
35 PS(in_save_handler) = 1;
36 if (call_user_function(NULL, NULL, func, retval, argc, argv) == FAILURE) {
37 zval_ptr_dtor(retval);
38 ZVAL_UNDEF(retval);
39 } else if (Z_ISUNDEF_P(retval)) {
40 ZVAL_NULL(retval);
41 }
42 PS(in_save_handler) = 0;
43 for (i = 0; i < argc; i++) {
44 zval_ptr_dtor(&argv[i]);
45 }
46 }
47
48 #define PSF(a) PS(mod_user_names).ps_##a
49
verify_bool_return_type_userland_calls(const zval * value)50 static zend_result verify_bool_return_type_userland_calls(const zval* value)
51 {
52 /* Exit or exception in userland call */
53 if (Z_TYPE_P(value) == IS_UNDEF) {
54 return FAILURE;
55 }
56 if (Z_TYPE_P(value) == IS_TRUE) {
57 return SUCCESS;
58 }
59 if (Z_TYPE_P(value) == IS_FALSE) {
60 return FAILURE;
61 }
62 if ((Z_TYPE_P(value) == IS_LONG) && (Z_LVAL_P(value) == -1)) {
63 /* TODO Why are exception cheked? */
64 if (!EG(exception)) {
65 php_error_docref(NULL, E_DEPRECATED, "Session callback must have a return value of type bool, %s returned", zend_zval_value_name(value));
66 }
67 return FAILURE;
68 }
69 if ((Z_TYPE_P(value) == IS_LONG) && (Z_LVAL_P(value) == 0)) {
70 /* TODO Why are exception cheked? */
71 if (!EG(exception)) {
72 php_error_docref(NULL, E_DEPRECATED, "Session callback must have a return value of type bool, %s returned", zend_zval_value_name(value));
73 }
74 return SUCCESS;
75 }
76 if (!EG(exception)) {
77 zend_type_error("Session callback must have a return value of type bool, %s returned", zend_zval_value_name(value)); \
78 }
79 return FAILURE;
80 }
81
PS_OPEN_FUNC(user)82 PS_OPEN_FUNC(user)
83 {
84 zval args[2];
85 zval retval;
86 zend_result ret = FAILURE;
87
88 ZEND_ASSERT(!Z_ISUNDEF(PSF(open)));
89
90 ZVAL_STRING(&args[0], (char*)save_path);
91 ZVAL_STRING(&args[1], (char*)session_name);
92
93 zend_try {
94 ps_call_handler(&PSF(open), 2, args, &retval);
95 } zend_catch {
96 PS(session_status) = php_session_none;
97 if (!Z_ISUNDEF(retval)) {
98 zval_ptr_dtor(&retval);
99 }
100 zend_bailout();
101 } zend_end_try();
102
103 PS(mod_user_implemented) = 1;
104
105 ret = verify_bool_return_type_userland_calls(&retval);
106 zval_ptr_dtor(&retval);
107 return ret;
108 }
109
PS_CLOSE_FUNC(user)110 PS_CLOSE_FUNC(user)
111 {
112 bool bailout = 0;
113 zval retval;
114 zend_result ret = FAILURE;
115
116 ZEND_ASSERT(!Z_ISUNDEF(PSF(close)));
117
118 if (!PS(mod_user_implemented)) {
119 /* already closed */
120 return SUCCESS;
121 }
122
123 zend_try {
124 ps_call_handler(&PSF(close), 0, NULL, &retval);
125 } zend_catch {
126 bailout = 1;
127 } zend_end_try();
128
129 PS(mod_user_implemented) = 0;
130
131 if (bailout) {
132 if (!Z_ISUNDEF(retval)) {
133 zval_ptr_dtor(&retval);
134 }
135 zend_bailout();
136 }
137
138 ret = verify_bool_return_type_userland_calls(&retval);
139 zval_ptr_dtor(&retval);
140 return ret;
141 }
142
PS_READ_FUNC(user)143 PS_READ_FUNC(user)
144 {
145 zval args[1];
146 zval retval;
147 zend_result ret = FAILURE;
148
149 ZEND_ASSERT(!Z_ISUNDEF(PSF(read)));
150
151 ZVAL_STR_COPY(&args[0], key);
152
153 ps_call_handler(&PSF(read), 1, args, &retval);
154
155 if (!Z_ISUNDEF(retval)) {
156 if (Z_TYPE(retval) == IS_STRING) {
157 *val = zend_string_copy(Z_STR(retval));
158 ret = SUCCESS;
159 }
160 zval_ptr_dtor(&retval);
161 }
162
163 return ret;
164 }
165
PS_WRITE_FUNC(user)166 PS_WRITE_FUNC(user)
167 {
168 zval args[2];
169 zval retval;
170 zend_result ret = FAILURE;
171
172 ZEND_ASSERT(!Z_ISUNDEF(PSF(write)));
173
174 ZVAL_STR_COPY(&args[0], key);
175 ZVAL_STR_COPY(&args[1], val);
176
177 ps_call_handler(&PSF(write), 2, args, &retval);
178
179 ret = verify_bool_return_type_userland_calls(&retval);
180 zval_ptr_dtor(&retval);
181 return ret;
182 }
183
PS_DESTROY_FUNC(user)184 PS_DESTROY_FUNC(user)
185 {
186 zval args[1];
187 zval retval;
188 zend_result ret = FAILURE;
189
190 ZEND_ASSERT(!Z_ISUNDEF(PSF(destroy)));
191
192 ZVAL_STR_COPY(&args[0], key);
193
194 ps_call_handler(&PSF(destroy), 1, args, &retval);
195
196 ret = verify_bool_return_type_userland_calls(&retval);
197 zval_ptr_dtor(&retval);
198 return ret;
199 }
200
PS_GC_FUNC(user)201 PS_GC_FUNC(user)
202 {
203 zval args[1];
204 zval retval;
205
206 ZEND_ASSERT(!Z_ISUNDEF(PSF(gc)));
207
208 ZVAL_LONG(&args[0], maxlifetime);
209
210 ps_call_handler(&PSF(gc), 1, args, &retval);
211
212 if (Z_TYPE(retval) == IS_LONG) {
213 *nrdels = Z_LVAL(retval);
214 } else if (Z_TYPE(retval) == IS_TRUE) {
215 /* This is for older API compatibility */
216 *nrdels = 1;
217 } else {
218 /* Anything else is some kind of error */
219 *nrdels = -1; // Error
220 }
221 return *nrdels;
222 }
223
PS_CREATE_SID_FUNC(user)224 PS_CREATE_SID_FUNC(user)
225 {
226 /* maintain backwards compatibility */
227 if (!Z_ISUNDEF(PSF(create_sid))) {
228 zend_string *id = NULL;
229 zval retval;
230
231 ps_call_handler(&PSF(create_sid), 0, NULL, &retval);
232
233 if (!Z_ISUNDEF(retval)) {
234 if (Z_TYPE(retval) == IS_STRING) {
235 id = zend_string_copy(Z_STR(retval));
236 }
237 zval_ptr_dtor(&retval);
238 } else {
239 zend_throw_error(NULL, "No session id returned by function");
240 return NULL;
241 }
242
243 if (!id) {
244 zend_throw_error(NULL, "Session id must be a string");
245 return NULL;
246 }
247
248 return id;
249 }
250
251 /* function as defined by PS_MOD */
252 return php_session_create_id(mod_data);
253 }
254
PS_VALIDATE_SID_FUNC(user)255 PS_VALIDATE_SID_FUNC(user)
256 {
257 /* maintain backwards compatibility */
258 if (!Z_ISUNDEF(PSF(validate_sid))) {
259 zval args[1];
260 zval retval;
261 zend_result ret = FAILURE;
262
263 ZVAL_STR_COPY(&args[0], key);
264
265 ps_call_handler(&PSF(validate_sid), 1, args, &retval);
266
267 ret = verify_bool_return_type_userland_calls(&retval);
268 zval_ptr_dtor(&retval);
269 return ret;
270 }
271
272 /* dummy function defined by PS_MOD */
273 return php_session_validate_sid(mod_data, key);
274 }
275
PS_UPDATE_TIMESTAMP_FUNC(user)276 PS_UPDATE_TIMESTAMP_FUNC(user)
277 {
278 zval args[2];
279 zval retval;
280 zend_result ret = FAILURE;
281
282 ZVAL_STR_COPY(&args[0], key);
283 ZVAL_STR_COPY(&args[1], val);
284
285 /* maintain backwards compatibility */
286 if (!Z_ISUNDEF(PSF(update_timestamp))) {
287 ps_call_handler(&PSF(update_timestamp), 2, args, &retval);
288 } else {
289 ps_call_handler(&PSF(write), 2, args, &retval);
290 }
291
292 ret = verify_bool_return_type_userland_calls(&retval);
293 zval_ptr_dtor(&retval);
294 return ret;
295 }
296