xref: /php-src/ext/session/mod_user.c (revision 7936c808)
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