xref: /PHP-7.4/ext/session/session.c (revision 688e56d0)
11627a57dSSascha Schumann /*
2a1b42e3fSSascha Schumann    +----------------------------------------------------------------------+
3d0cb7153SJohannes Schlüter    | PHP Version 7                                                        |
4a1b42e3fSSascha Schumann    +----------------------------------------------------------------------+
50cf7de1cSZeev Suraski    | Copyright (c) The PHP Group                                          |
6a1b42e3fSSascha Schumann    +----------------------------------------------------------------------+
75bd93221Sfoobar    | This source file is subject to version 3.01 of the PHP license,      |
8c5724cbdSZeev Suraski    | that is bundled with this package in the file LICENSE, and is        |
9f68c7ff2SJames Cox    | available through the world-wide-web at the following url:           |
105bd93221Sfoobar    | http://www.php.net/license/3_01.txt                                  |
11c5724cbdSZeev Suraski    | If you did not receive a copy of the PHP license and are unable to   |
12c5724cbdSZeev Suraski    | obtain it through the world-wide-web, please send a note to          |
13c5724cbdSZeev Suraski    | license@php.net so we can mail you a copy immediately.               |
14a1b42e3fSSascha Schumann    +----------------------------------------------------------------------+
15e8101d4fSSascha Schumann    | Authors: Sascha Schumann <sascha@schumann.cx>                        |
161668570eSAndrei Zmievski    |          Andrei Zmievski <andrei@php.net>                            |
17a1b42e3fSSascha Schumann    +----------------------------------------------------------------------+
18a1b42e3fSSascha Schumann  */
19a1b42e3fSSascha Schumann 
201beda9eeSStig Bakken #ifdef HAVE_CONFIG_H
211beda9eeSStig Bakken #include "config.h"
221beda9eeSStig Bakken #endif
231beda9eeSStig Bakken 
2412d3e3d7SSascha Schumann #include "php.h"
2512d3e3d7SSascha Schumann 
2680bdd19eSZeev Suraski #ifdef PHP_WIN32
27bfe51d38SPierre Joye # include "win32/winutil.h"
28bfe51d38SPierre Joye # include "win32/time.h"
2912d3e3d7SSascha Schumann #else
30bfe51d38SPierre Joye # include <sys/time.h>
31c5fd7244SAndi Gutmans #endif
32a1b42e3fSSascha Schumann 
33996216b4SSascha Schumann #include <sys/stat.h>
34533ef398SSascha Schumann #include <fcntl.h>
35533ef398SSascha Schumann 
36a1b42e3fSSascha Schumann #include "php_ini.h"
37a1b42e3fSSascha Schumann #include "SAPI.h"
38da9448f3SArnaud Le Blanc #include "rfc1867.h"
39da9448f3SArnaud Le Blanc #include "php_variables.h"
40a1b42e3fSSascha Schumann #include "php_session.h"
413467526aSYasuo Ohgaki #include "ext/standard/php_random.h"
425b983c94SSascha Schumann #include "ext/standard/php_var.h"
432ea67808SScott MacVicar #include "ext/date/php_date.h"
447894c0ccSAndrey Hristov #include "ext/standard/php_lcg.h"
4507e71ce1SSascha Schumann #include "ext/standard/url_scanner_ex.h"
46a7c8bfb9SColin Viebrock #include "ext/standard/info.h"
47e33f3d3bSNikita Popov #include "zend_smart_str.h"
48e2d606e1SIlia Alshanetsky #include "ext/standard/url.h"
4947cfae87SArpad Ray #include "ext/standard/basic_functions.h"
50c5f9a231SMartin Jansen #include "ext/standard/head.h"
5186cf74a1SSascha Schumann 
529de9b7c1SSascha Schumann #include "mod_files.h"
539de9b7c1SSascha Schumann #include "mod_user.h"
549de9b7c1SSascha Schumann 
55087f2be5Sfoobar #ifdef HAVE_LIBMM
56087f2be5Sfoobar #include "mod_mm.h"
57087f2be5Sfoobar #endif
59a62d4e2cSJohannes Schlüter PHPAPI ZEND_DECLARE_MODULE_GLOBALS(ps)
60ca0c2340SFelipe Pena 
61bdeb220fSAnatol Belski static int php_session_rfc1867_callback(unsigned int event, void *event_data, void **extra);
62bdeb220fSAnatol Belski static int (*php_session_rfc1867_orig_callback)(unsigned int event, void *event_data, void **extra);
639b1a224dSStanislav Malyshev static void php_session_track_init(void);
64da9448f3SArnaud Le Blanc 
6547cfae87SArpad Ray /* SessionHandler class */
6647cfae87SArpad Ray zend_class_entry *php_session_class_entry;
6747cfae87SArpad Ray 
687486849bSArpad Ray /* SessionHandlerInterface */
697486849bSArpad Ray zend_class_entry *php_session_iface_entry;
707486849bSArpad Ray 
711e836cddSArpad Ray /* SessionIdInterface */
721e836cddSArpad Ray zend_class_entry *php_session_id_iface_entry;
731e836cddSArpad Ray 
74e6c8640aSYasuo Ohgaki /* SessionUpdateTimestampHandler class */
75e6c8640aSYasuo Ohgaki zend_class_entry *php_session_update_timestamp_class_entry;
76e6c8640aSYasuo Ohgaki 
77e6c8640aSYasuo Ohgaki /* SessionUpdateTimestampInterface */
78e6c8640aSYasuo Ohgaki zend_class_entry *php_session_update_timestamp_iface_entry;
79e6c8640aSYasuo Ohgaki 
803467526aSYasuo Ohgaki #define PS_MAX_SID_LENGTH 256
813467526aSYasuo Ohgaki 
82525f3c47SJani Taskinen /* ***********
83525f3c47SJani Taskinen    * Helpers *
84525f3c47SJani Taskinen    *********** */
85ca0c2340SFelipe Pena 
86525f3c47SJani Taskinen #define IF_SESSION_VARS() \
873647fc6fSXinchen Hui 	if (Z_ISREF_P(&PS(http_session_vars)) && Z_TYPE_P(Z_REFVAL(PS(http_session_vars))) == IS_ARRAY)
88ea563184SAndrei Zmievski 
89d3639b1aSIlia Alshanetsky #define SESSION_CHECK_ACTIVE_STATE	\
90d3639b1aSIlia Alshanetsky 	if (PS(session_status) == php_session_active) {	\
91bdeb220fSAnatol Belski 		php_error_docref(NULL, E_WARNING, "A session is active. You cannot change the session module's ini settings at this time");	\
92d3639b1aSIlia Alshanetsky 		return FAILURE;	\
93525f3c47SJani Taskinen 	}
94d3639b1aSIlia Alshanetsky 
957f196e32SYasuo Ohgaki #define SESSION_CHECK_OUTPUT_STATE										\
967f196e32SYasuo Ohgaki 	if (SG(headers_sent) && stage != ZEND_INI_STAGE_DEACTIVATE) {												\
977f196e32SYasuo Ohgaki 		php_error_docref(NULL, E_WARNING, "Headers already sent. You cannot change the session module's ini settings at this time");	\
987f196e32SYasuo Ohgaki 		return FAILURE;													\
997f196e32SYasuo Ohgaki 	}
1007f196e32SYasuo Ohgaki 
101f248df90SYasuo Ohgaki #define APPLY_TRANS_SID (PS(use_trans_sid) && !PS(use_only_cookies))
102f248df90SYasuo Ohgaki 
1037f196e32SYasuo Ohgaki static int php_session_send_cookie(void);
1047f196e32SYasuo Ohgaki static int php_session_abort(void);
10525e8fcc8SYasuo Ohgaki 
106bd00fe81SAnatol Belski /* Initialized in MINIT, readonly otherwise. */
107bd00fe81SAnatol Belski static int my_module_number = 0;
108bd00fe81SAnatol Belski 
109525f3c47SJani Taskinen /* Dispatched by RINIT and by php_session_destroy */
php_rinit_session_globals(void)110bdeb220fSAnatol Belski static inline void php_rinit_session_globals(void) /* {{{ */
1119bfd5e5eSZeev Suraski {
112e6c8640aSYasuo Ohgaki 	/* Do NOT init PS(mod_user_names) here! */
113bfb9307bSYasuo Ohgaki 	/* TODO: These could be moved to MINIT and removed. These should be initialized by php_rshutdown_session_globals() always when execution is finished. */
114525f3c47SJani Taskinen 	PS(id) = NULL;
115525f3c47SJani Taskinen 	PS(session_status) = php_session_none;
1163d6e9223SYasuo Ohgaki 	PS(in_save_handler) = 0;
117a93a51c3SYasuo Ohgaki 	PS(set_handler) = 0;
118525f3c47SJani Taskinen 	PS(mod_data) = NULL;
11947cfae87SArpad Ray 	PS(mod_user_is_open) = 0;
120e6c8640aSYasuo Ohgaki 	PS(define_sid) = 1;
121e6c8640aSYasuo Ohgaki 	PS(session_vars) = NULL;
122bd00fe81SAnatol Belski 	PS(module_number) = my_module_number;
123c9bca503SXinchen Hui 	ZVAL_UNDEF(&PS(http_session_vars));
124525f3c47SJani Taskinen }
125525f3c47SJani Taskinen /* }}} */
12638ad3918SSascha Schumann 
127525f3c47SJani Taskinen /* Dispatched by RSHUTDOWN and by php_session_destroy */
php_rshutdown_session_globals(void)128bdeb220fSAnatol Belski static inline void php_rshutdown_session_globals(void) /* {{{ */
129525f3c47SJani Taskinen {
130e6c8640aSYasuo Ohgaki 	/* Do NOT destroy PS(mod_user_names) here! */
131d8651fbeSXinchen Hui 	if (!Z_ISUNDEF(PS(http_session_vars))) {
132525f3c47SJani Taskinen 		zval_ptr_dtor(&PS(http_session_vars));
133c9bca503SXinchen Hui 		ZVAL_UNDEF(&PS(http_session_vars));
134525f3c47SJani Taskinen 	}
13547cfae87SArpad Ray 	if (PS(mod_data) || PS(mod_user_implemented)) {
136525f3c47SJani Taskinen 		zend_try {
137bdeb220fSAnatol Belski 			PS(mod)->s_close(&PS(mod_data));
138525f3c47SJani Taskinen 		} zend_end_try();
139525f3c47SJani Taskinen 	}
140525f3c47SJani Taskinen 	if (PS(id)) {
1415eb1f92fSDmitry Stogov 		zend_string_release_ex(PS(id), 0);
1424dba99c2SJulien Pauli 		PS(id) = NULL;
14338ad3918SSascha Schumann 	}
14434ff7bbeSYasuo Ohgaki 
145e6c8640aSYasuo Ohgaki 	if (PS(session_vars)) {
1465eb1f92fSDmitry Stogov 		zend_string_release_ex(PS(session_vars), 0);
1474d3a3811SJulien Pauli 		PS(session_vars) = NULL;
148e6c8640aSYasuo Ohgaki 	}
14934ff7bbeSYasuo Ohgaki 
150bfb9307bSYasuo Ohgaki 	/* User save handlers may end up directly here by misuse, bugs in user script, etc. */
151bfb9307bSYasuo Ohgaki 	/* Set session status to prevent error while restoring save handler INI value. */
152bfb9307bSYasuo Ohgaki 	PS(session_status) = php_session_none;
1539bfd5e5eSZeev Suraski }
154525f3c47SJani Taskinen /* }}} */
1559bfd5e5eSZeev Suraski 
php_session_destroy(void)156e10425feSdreamszhu PHPAPI int php_session_destroy(void) /* {{{ */
1579bfd5e5eSZeev Suraski {
158525f3c47SJani Taskinen 	int retval = SUCCESS;
159d3639b1aSIlia Alshanetsky 
160525f3c47SJani Taskinen 	if (PS(session_status) != php_session_active) {
161bdeb220fSAnatol Belski 		php_error_docref(NULL, E_WARNING, "Trying to destroy uninitialized session");
162525f3c47SJani Taskinen 		return FAILURE;
163a257d758SSascha Schumann 	}
164d3639b1aSIlia Alshanetsky 
165bdeb220fSAnatol Belski 	if (PS(id) && PS(mod)->s_destroy(&PS(mod_data), PS(id)) == FAILURE) {
166525f3c47SJani Taskinen 		retval = FAILURE;
167bdeb220fSAnatol Belski 		php_error_docref(NULL, E_WARNING, "Session object destruction failed");
168525f3c47SJani Taskinen 	}
169525f3c47SJani Taskinen 
170bdeb220fSAnatol Belski 	php_rshutdown_session_globals();
171bdeb220fSAnatol Belski 	php_rinit_session_globals();
172525f3c47SJani Taskinen 
173525f3c47SJani Taskinen 	return retval;
174d3639b1aSIlia Alshanetsky }
175525f3c47SJani Taskinen /* }}} */
176d3639b1aSIlia Alshanetsky 
php_add_session_var(zend_string * name)177bdeb220fSAnatol Belski PHPAPI void php_add_session_var(zend_string *name) /* {{{ */
178d3639b1aSIlia Alshanetsky {
179525f3c47SJani Taskinen 	IF_SESSION_VARS() {
180c91f652dSNikita Popov 		zval *sess_var = Z_REFVAL(PS(http_session_vars));
181c91f652dSNikita Popov 		SEPARATE_ARRAY(sess_var);
182c91f652dSNikita Popov 		if (!zend_hash_exists(Z_ARRVAL_P(sess_var), name)) {
183c91f652dSNikita Popov 			zval empty_var;
184c91f652dSNikita Popov 			ZVAL_NULL(&empty_var);
185c91f652dSNikita Popov 			zend_hash_update(Z_ARRVAL_P(sess_var), name, &empty_var);
186c91f652dSNikita Popov 		}
187c1ef1055SRasmus Lerdorf 	}
188c1ef1055SRasmus Lerdorf }
1899c558821SRasmus Lerdorf /* }}} */
190a1b42e3fSSascha Schumann 
php_set_session_var(zend_string * name,zval * state_val,php_unserialize_data_t * var_hash)191bdeb220fSAnatol Belski PHPAPI zval* php_set_session_var(zend_string *name, zval *state_val, php_unserialize_data_t *var_hash) /* {{{ */
19220190c96SAndrei Zmievski {
193febee112SKalle Sommer Nielsen 	IF_SESSION_VARS() {
194c91f652dSNikita Popov 		zval *sess_var = Z_REFVAL(PS(http_session_vars));
195c91f652dSNikita Popov 		SEPARATE_ARRAY(sess_var);
196c91f652dSNikita Popov 		return zend_hash_update(Z_ARRVAL_P(sess_var), name, state_val);
197375d7960SSander Roobol 	}
1986bfedfd2SDmitry Stogov 	return NULL;
19920190c96SAndrei Zmievski }
200525f3c47SJani Taskinen /* }}} */
20120190c96SAndrei Zmievski 
php_get_session_var(zend_string * name)202bdeb220fSAnatol Belski PHPAPI zval* php_get_session_var(zend_string *name) /* {{{ */
20320190c96SAndrei Zmievski {
204b9077e5aSSascha Schumann 	IF_SESSION_VARS() {
2053647fc6fSXinchen Hui 		return zend_hash_find(Z_ARRVAL_P(Z_REFVAL(PS(http_session_vars))), name);
206ff12826fSSascha Schumann 	}
207c9bca503SXinchen Hui 	return NULL;
20820190c96SAndrei Zmievski }
209525f3c47SJani Taskinen /* }}} */
2105c0f2053SSascha Schumann 
php_session_track_init(void)211bdeb220fSAnatol Belski static void php_session_track_init(void) /* {{{ */
2121b5fff69SSascha Schumann {
2133647fc6fSXinchen Hui 	zval session_vars;
214c3e3c98eSAnatol Belski 	zend_string *var_name = zend_string_init("_SESSION", sizeof("_SESSION") - 1, 0);
215a5304b13SKalle Sommer Nielsen 	/* Unconditionally destroy existing array -- possible dirty data */
216bdeb220fSAnatol Belski 	zend_delete_global_variable(var_name);
217375d7960SSander Roobol 
218d8651fbeSXinchen Hui 	if (!Z_ISUNDEF(PS(http_session_vars))) {
219525f3c47SJani Taskinen 		zval_ptr_dtor(&PS(http_session_vars));
220525f3c47SJani Taskinen 	}
2219fdec2e3SPreston L. Bannister 
2223647fc6fSXinchen Hui 	array_init(&session_vars);
2233647fc6fSXinchen Hui 	ZVAL_NEW_REF(&PS(http_session_vars), &session_vars);
224050d7e38SDmitry Stogov 	Z_ADDREF_P(&PS(http_session_vars));
225e10e151eSDmitry Stogov 	zend_hash_update_ind(&EG(symbol_table), var_name, &PS(http_session_vars));
2265eb1f92fSDmitry Stogov 	zend_string_release_ex(var_name, 0);
2271b5fff69SSascha Schumann }
228525f3c47SJani Taskinen /* }}} */
2291b5fff69SSascha Schumann 
php_session_encode(void)230bdeb220fSAnatol Belski static zend_string *php_session_encode(void) /* {{{ */
2311b5fff69SSascha Schumann {
232525f3c47SJani Taskinen 	IF_SESSION_VARS() {
233525f3c47SJani Taskinen 		if (!PS(serializer)) {
234bdeb220fSAnatol Belski 			php_error_docref(NULL, E_WARNING, "Unknown session.serialize_handler. Failed to encode session object");
235c9bca503SXinchen Hui 			return NULL;
236b7a7b1a6SStanislav Malyshev 		}
237bdeb220fSAnatol Belski 		return PS(serializer)->encode();
238525f3c47SJani Taskinen 	} else {
239bdeb220fSAnatol Belski 		php_error_docref(NULL, E_WARNING, "Cannot encode non-existent session");
240525f3c47SJani Taskinen 	}
241c9bca503SXinchen Hui 	return NULL;
242525f3c47SJani Taskinen }
243525f3c47SJani Taskinen /* }}} */
244ffd41a50SIlia Alshanetsky 
php_session_decode(zend_string * data)2450c9bfa96SYasuo Ohgaki static int php_session_decode(zend_string *data) /* {{{ */
246525f3c47SJani Taskinen {
247525f3c47SJani Taskinen 	if (!PS(serializer)) {
248bdeb220fSAnatol Belski 		php_error_docref(NULL, E_WARNING, "Unknown session.serialize_handler. Failed to decode session object");
2490c9bfa96SYasuo Ohgaki 		return FAILURE;
250525f3c47SJani Taskinen 	}
251ed3811e7SNikita Popov 	if (PS(serializer)->decode(ZSTR_VAL(data), ZSTR_LEN(data)) == FAILURE) {
252bdeb220fSAnatol Belski 		php_session_destroy();
2539b1a224dSStanislav Malyshev 		php_session_track_init();
254bdeb220fSAnatol Belski 		php_error_docref(NULL, E_WARNING, "Failed to decode session object. Session has been destroyed");
2550c9bfa96SYasuo Ohgaki 		return FAILURE;
256375d7960SSander Roobol 	}
2570c9bfa96SYasuo Ohgaki 	return SUCCESS;
258525f3c47SJani Taskinen }
259525f3c47SJani Taskinen /* }}} */
260375d7960SSander Roobol 
261525f3c47SJani Taskinen /*
262525f3c47SJani Taskinen  * Note that we cannot use the BASE64 alphabet here, because
263525f3c47SJani Taskinen  * it contains "/" and "+": both are unacceptable for simple inclusion
264525f3c47SJani Taskinen  * into URLs.
265525f3c47SJani Taskinen  */
266375d7960SSander Roobol 
267525f3c47SJani Taskinen static char hexconvtab[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,-";
2681b5fff69SSascha Schumann 
bin_to_readable(unsigned char * in,size_t inlen,char * out,size_t outlen,char nbits)269a57f370eSNikita Popov static void bin_to_readable(unsigned char *in, size_t inlen, char *out, size_t outlen, char nbits) /* {{{ */
270a1b42e3fSSascha Schumann {
271525f3c47SJani Taskinen 	unsigned char *p, *q;
272525f3c47SJani Taskinen 	unsigned short w;
273525f3c47SJani Taskinen 	int mask;
274525f3c47SJani Taskinen 	int have;
275375d7960SSander Roobol 
276c9bca503SXinchen Hui 	p = (unsigned char *)in;
277525f3c47SJani Taskinen 	q = (unsigned char *)in + inlen;
278db8b4c67SSascha Schumann 
279db8b4c67SSascha Schumann 	w = 0;
280db8b4c67SSascha Schumann 	have = 0;
281db8b4c67SSascha Schumann 	mask = (1 << nbits) - 1;
282525f3c47SJani Taskinen 
283a57f370eSNikita Popov 	while (outlen--) {
284db8b4c67SSascha Schumann 		if (have < nbits) {
285db8b4c67SSascha Schumann 			if (p < q) {
286db8b4c67SSascha Schumann 				w |= *p++ << have;
287db8b4c67SSascha Schumann 				have += 8;
288db8b4c67SSascha Schumann 			} else {
289a57f370eSNikita Popov 				/* Should never happen. Input must be large enough. */
290a57f370eSNikita Popov 				ZEND_ASSERT(0);
291a57f370eSNikita Popov 				break;
292db8b4c67SSascha Schumann 			}
293db8b4c67SSascha Schumann 		}
294db8b4c67SSascha Schumann 
295db8b4c67SSascha Schumann 		/* consume nbits */
296db8b4c67SSascha Schumann 		*out++ = hexconvtab[w & mask];
297db8b4c67SSascha Schumann 		w >>= nbits;
298db8b4c67SSascha Schumann 		have -= nbits;
299db8b4c67SSascha Schumann 	}
300525f3c47SJani Taskinen 
301db8b4c67SSascha Schumann 	*out = '\0';
302db8b4c67SSascha Schumann }
303525f3c47SJani Taskinen /* }}} */
304db8b4c67SSascha Schumann 
3053467526aSYasuo Ohgaki #define PS_EXTRA_RAND_BYTES 60
3063467526aSYasuo Ohgaki 
php_session_create_id(PS_CREATE_SID_ARGS)307c9bca503SXinchen Hui PHPAPI zend_string *php_session_create_id(PS_CREATE_SID_ARGS) /* {{{ */
308a1b42e3fSSascha Schumann {
3093467526aSYasuo Ohgaki 	unsigned char rbuf[PS_MAX_SID_LENGTH + PS_EXTRA_RAND_BYTES];
310c9bca503SXinchen Hui 	zend_string *outid;
311f2f1f94eSSascha Schumann 
312a57f370eSNikita Popov 	/* It would be enough to read ceil(sid_length * sid_bits_per_character / 8) bytes here.
313a57f370eSNikita Popov 	 * We read sid_length bytes instead for simplicity. */
3143467526aSYasuo Ohgaki 	/* Read additional PS_EXTRA_RAND_BYTES just in case CSPRNG is not safe enough */
3153467526aSYasuo Ohgaki 	if (php_random_bytes_throw(rbuf, PS(sid_length) + PS_EXTRA_RAND_BYTES) == FAILURE) {
3163467526aSYasuo Ohgaki 		return NULL;
317f2f1f94eSSascha Schumann 	}
318375d7960SSander Roobol 
3193467526aSYasuo Ohgaki 	outid = zend_string_alloc(PS(sid_length), 0);
320a57f370eSNikita Popov 	bin_to_readable(
321a57f370eSNikita Popov 		rbuf, PS(sid_length),
322a57f370eSNikita Popov 		ZSTR_VAL(outid), ZSTR_LEN(outid),
323a57f370eSNikita Popov 		(char)PS(sid_bits_per_character));
324525f3c47SJani Taskinen 
3252673b9beSGwynne Raskind 	return outid;
326375d7960SSander Roobol }
327525f3c47SJani Taskinen /* }}} */
3289fdec2e3SPreston L. Bannister 
32925e8fcc8SYasuo Ohgaki /* Default session id char validation function allowed by ps_modules.
33025e8fcc8SYasuo Ohgaki  * If you change the logic here, please also update the error message in
33125e8fcc8SYasuo Ohgaki  * ps_modules appropriately */
php_session_valid_key(const char * key)33225e8fcc8SYasuo Ohgaki PHPAPI int php_session_valid_key(const char *key) /* {{{ */
333a1b42e3fSSascha Schumann {
33425e8fcc8SYasuo Ohgaki 	size_t len;
33525e8fcc8SYasuo Ohgaki 	const char *p;
33625e8fcc8SYasuo Ohgaki 	char c;
33725e8fcc8SYasuo Ohgaki 	int ret = SUCCESS;
33825e8fcc8SYasuo Ohgaki 
33925e8fcc8SYasuo Ohgaki 	for (p = key; (c = *p); p++) {
34025e8fcc8SYasuo Ohgaki 		/* valid characters are a..z,A..Z,0..9 */
34125e8fcc8SYasuo Ohgaki 		if (!((c >= 'a' && c <= 'z')
34225e8fcc8SYasuo Ohgaki 				|| (c >= 'A' && c <= 'Z')
34325e8fcc8SYasuo Ohgaki 				|| (c >= '0' && c <= '9')
34425e8fcc8SYasuo Ohgaki 				|| c == ','
34525e8fcc8SYasuo Ohgaki 				|| c == '-')) {
34625e8fcc8SYasuo Ohgaki 			ret = FAILURE;
34725e8fcc8SYasuo Ohgaki 			break;
34825e8fcc8SYasuo Ohgaki 		}
34925e8fcc8SYasuo Ohgaki 	}
350375d7960SSander Roobol 
35125e8fcc8SYasuo Ohgaki 	len = p - key;
35225e8fcc8SYasuo Ohgaki 
35325e8fcc8SYasuo Ohgaki 	/* Somewhat arbitrary length limit here, but should be way more than
35425e8fcc8SYasuo Ohgaki 	   anyone needs and avoids file-level warnings later on if we exceed MAX_PATH */
3553467526aSYasuo Ohgaki 	if (len == 0 || len > PS_MAX_SID_LENGTH) {
35625e8fcc8SYasuo Ohgaki 		ret = FAILURE;
3573d80bd0cSIlia Alshanetsky 	}
3583d80bd0cSIlia Alshanetsky 
35925e8fcc8SYasuo Ohgaki 	return ret;
36025e8fcc8SYasuo Ohgaki }
36125e8fcc8SYasuo Ohgaki /* }}} */
36225e8fcc8SYasuo Ohgaki 
363e8f1c29cSYasuo Ohgaki 
php_session_gc(zend_bool immediate)364a4a2f66eSYasuo Ohgaki static zend_long php_session_gc(zend_bool immediate) /* {{{ */
365e8f1c29cSYasuo Ohgaki {
366e8f1c29cSYasuo Ohgaki 	int nrand;
367a4a2f66eSYasuo Ohgaki 	zend_long num = -1;
368e8f1c29cSYasuo Ohgaki 
369e8f1c29cSYasuo Ohgaki 	/* GC must be done before reading session data. */
370a4a2f66eSYasuo Ohgaki 	if ((PS(mod_data) || PS(mod_user_implemented))) {
371a4a2f66eSYasuo Ohgaki 		if (immediate) {
372a4a2f66eSYasuo Ohgaki 			PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &num);
373a4a2f66eSYasuo Ohgaki 			return num;
374a4a2f66eSYasuo Ohgaki 		}
375a4a2f66eSYasuo Ohgaki 		nrand = (zend_long) ((float) PS(gc_divisor) * php_combined_lcg());
376a4a2f66eSYasuo Ohgaki 		if (PS(gc_probability) > 0 && nrand < PS(gc_probability)) {
377a4a2f66eSYasuo Ohgaki 			PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &num);
378e8f1c29cSYasuo Ohgaki 		}
379e8f1c29cSYasuo Ohgaki 	}
380a4a2f66eSYasuo Ohgaki 	return num;
381e8f1c29cSYasuo Ohgaki } /* }}} */
382e8f1c29cSYasuo Ohgaki 
php_session_initialize(void)3837f196e32SYasuo Ohgaki static int php_session_initialize(void) /* {{{ */
38425e8fcc8SYasuo Ohgaki {
3853647fc6fSXinchen Hui 	zend_string *val = NULL;
38625e8fcc8SYasuo Ohgaki 
387a15e9ccbSYasuo Ohgaki 	PS(session_status) = php_session_active;
388a15e9ccbSYasuo Ohgaki 
3894c4d5a61SIlia Alshanetsky 	if (!PS(mod)) {
390a15e9ccbSYasuo Ohgaki 		PS(session_status) = php_session_disabled;
3917f196e32SYasuo Ohgaki 		php_error_docref(NULL, E_WARNING, "No storage module chosen - failed to initialize session");
3927f196e32SYasuo Ohgaki 		return FAILURE;
3934c4d5a61SIlia Alshanetsky 	}
3944c4d5a61SIlia Alshanetsky 
395375d7960SSander Roobol 	/* Open session handler first */
396e6c8640aSYasuo Ohgaki 	if (PS(mod)->s_open(&PS(mod_data), PS(save_path), PS(session_name)) == FAILURE
397e6c8640aSYasuo Ohgaki 		/* || PS(mod_data) == NULL */ /* FIXME: open must set valid PS(mod_data) with success */
398e6c8640aSYasuo Ohgaki 	) {
399224aaf94SYasuo Ohgaki 		php_session_abort();
4007f196e32SYasuo Ohgaki 		php_error_docref(NULL, E_WARNING, "Failed to initialize storage module: %s (path: %s)", PS(mod)->s_name, PS(save_path));
4017f196e32SYasuo Ohgaki 		return FAILURE;
402375d7960SSander Roobol 	}
403525f3c47SJani Taskinen 
404375d7960SSander Roobol 	/* If there is no ID, use session module to create one */
405132d919cSYasuo Ohgaki 	if (!PS(id) || !ZSTR_VAL(PS(id))[0]) {
4068c37a086SYasuo Ohgaki 		if (PS(id)) {
4075eb1f92fSDmitry Stogov 			zend_string_release_ex(PS(id), 0);
4088c37a086SYasuo Ohgaki 		}
409bdeb220fSAnatol Belski 		PS(id) = PS(mod)->s_create_sid(&PS(mod_data));
41025e8fcc8SYasuo Ohgaki 		if (!PS(id)) {
411224aaf94SYasuo Ohgaki 			php_session_abort();
412771e5cc2SAaron Piotrowski 			zend_throw_error(NULL, "Failed to create session ID: %s (path: %s)", PS(mod)->s_name, PS(save_path));
4137f196e32SYasuo Ohgaki 			return FAILURE;
41425e8fcc8SYasuo Ohgaki 		}
415e5a11823SIlia Alshanetsky 		if (PS(use_cookies)) {
416e5a11823SIlia Alshanetsky 			PS(send_cookie) = 1;
417e5a11823SIlia Alshanetsky 		}
418e6c8640aSYasuo Ohgaki 	} else if (PS(use_strict_mode) && PS(mod)->s_validate_sid &&
419e6c8640aSYasuo Ohgaki 		PS(mod)->s_validate_sid(&PS(mod_data), PS(id)) == FAILURE) {
420e6c8640aSYasuo Ohgaki 		if (PS(id)) {
4215eb1f92fSDmitry Stogov 			zend_string_release_ex(PS(id), 0);
422e6c8640aSYasuo Ohgaki 		}
423e6c8640aSYasuo Ohgaki 		PS(id) = PS(mod)->s_create_sid(&PS(mod_data));
424e6c8640aSYasuo Ohgaki 		if (!PS(id)) {
425e6c8640aSYasuo Ohgaki 			PS(id) = php_session_create_id(NULL);
426e6c8640aSYasuo Ohgaki 		}
427e6c8640aSYasuo Ohgaki 		if (PS(use_cookies)) {
428e6c8640aSYasuo Ohgaki 			PS(send_cookie) = 1;
429e6c8640aSYasuo Ohgaki 		}
430e5a11823SIlia Alshanetsky 	}
4317b179808SYasuo Ohgaki 
4327f196e32SYasuo Ohgaki 	if (php_session_reset_id() == FAILURE) {
4337f196e32SYasuo Ohgaki 		php_session_abort();
4347f196e32SYasuo Ohgaki 		return FAILURE;
4357f196e32SYasuo Ohgaki 	}
43625e8fcc8SYasuo Ohgaki 
437375d7960SSander Roobol 	/* Read data */
438bdeb220fSAnatol Belski 	php_session_track_init();
439741b5952SYasuo Ohgaki 	if (PS(mod)->s_read(&PS(mod_data), PS(id), &val, PS(gc_maxlifetime)) == FAILURE) {
440224aaf94SYasuo Ohgaki 		php_session_abort();
441631861e1SSjonHortensius 		/* FYI: Some broken save handlers return FAILURE for non-existent session ID, this is incorrect */
442224aaf94SYasuo Ohgaki 		php_error_docref(NULL, E_WARNING, "Failed to read session data: %s (path: %s)", PS(mod)->s_name, PS(save_path));
4437f196e32SYasuo Ohgaki 		return FAILURE;
44425e8fcc8SYasuo Ohgaki 	}
445d2c752d7SAnatol Belski 
446d2c752d7SAnatol Belski 	/* GC must be done after read */
447a4a2f66eSYasuo Ohgaki 	php_session_gc(0);
448d2c752d7SAnatol Belski 
449e6c8640aSYasuo Ohgaki 	if (PS(session_vars)) {
4505eb1f92fSDmitry Stogov 		zend_string_release_ex(PS(session_vars), 0);
451e6c8640aSYasuo Ohgaki 		PS(session_vars) = NULL;
452e6c8640aSYasuo Ohgaki 	}
45325e8fcc8SYasuo Ohgaki 	if (val) {
454e6c8640aSYasuo Ohgaki 		if (PS(lazy_write)) {
455e6c8640aSYasuo Ohgaki 			PS(session_vars) = zend_string_copy(val);
456e6c8640aSYasuo Ohgaki 		}
457e6c8640aSYasuo Ohgaki 		php_session_decode(val);
4585eb1f92fSDmitry Stogov 		zend_string_release_ex(val, 0);
45925e8fcc8SYasuo Ohgaki 	}
4607f196e32SYasuo Ohgaki 	return SUCCESS;
461a1b42e3fSSascha Schumann }
462525f3c47SJani Taskinen /* }}} */
463a1b42e3fSSascha Schumann 
php_session_save_current_state(int write)4644d747b13SYasuo Ohgaki static void php_session_save_current_state(int write) /* {{{ */
465b9077e5aSSascha Schumann {
466b9077e5aSSascha Schumann 	int ret = FAILURE;
467525f3c47SJani Taskinen 
4684d747b13SYasuo Ohgaki 	if (write) {
4694d747b13SYasuo Ohgaki 		IF_SESSION_VARS() {
4704d747b13SYasuo Ohgaki 			if (PS(mod_data) || PS(mod_user_implemented)) {
4714d747b13SYasuo Ohgaki 				zend_string *val;
4724d747b13SYasuo Ohgaki 
4734d747b13SYasuo Ohgaki 				val = php_session_encode();
4744d747b13SYasuo Ohgaki 				if (val) {
4754d747b13SYasuo Ohgaki 					if (PS(lazy_write) && PS(session_vars)
4764d747b13SYasuo Ohgaki 						&& PS(mod)->s_update_timestamp
4774d747b13SYasuo Ohgaki 						&& PS(mod)->s_update_timestamp != php_session_update_timestamp
4784a2e40bbSDmitry Stogov 						&& ZSTR_LEN(val) == ZSTR_LEN(PS(session_vars))
4794a2e40bbSDmitry Stogov 						&& !memcmp(ZSTR_VAL(val), ZSTR_VAL(PS(session_vars)), ZSTR_LEN(val))
4804d747b13SYasuo Ohgaki 					) {
481741b5952SYasuo Ohgaki 						ret = PS(mod)->s_update_timestamp(&PS(mod_data), PS(id), val, PS(gc_maxlifetime));
4824d747b13SYasuo Ohgaki 					} else {
483741b5952SYasuo Ohgaki 						ret = PS(mod)->s_write(&PS(mod_data), PS(id), val, PS(gc_maxlifetime));
4844d747b13SYasuo Ohgaki 					}
4855eb1f92fSDmitry Stogov 					zend_string_release_ex(val, 0);
486e6c8640aSYasuo Ohgaki 				} else {
4874bd22cf1SDmitry Stogov 					ret = PS(mod)->s_write(&PS(mod_data), PS(id), ZSTR_EMPTY_ALLOC(), PS(gc_maxlifetime));
488e6c8640aSYasuo Ohgaki 				}
489525f3c47SJani Taskinen 			}
490525f3c47SJani Taskinen 
4914d747b13SYasuo Ohgaki 			if ((ret == FAILURE) && !EG(exception)) {
49205e87fa4SYasuo Ohgaki 				if (!PS(mod_user_implemented)) {
49305e87fa4SYasuo Ohgaki 					php_error_docref(NULL, E_WARNING, "Failed to write session data (%s). Please "
49405e87fa4SYasuo Ohgaki 									 "verify that the current setting of session.save_path "
49505e87fa4SYasuo Ohgaki 									 "is correct (%s)",
49605e87fa4SYasuo Ohgaki 									 PS(mod)->s_name,
49705e87fa4SYasuo Ohgaki 									 PS(save_path));
49805e87fa4SYasuo Ohgaki 				} else {
49905e87fa4SYasuo Ohgaki 					php_error_docref(NULL, E_WARNING, "Failed to write session data using user "
50005e87fa4SYasuo Ohgaki 									 "defined save handler. (session.save_path: %s)", PS(save_path));
50105e87fa4SYasuo Ohgaki 				}
5024d747b13SYasuo Ohgaki 			}
503525f3c47SJani Taskinen 		}
504525f3c47SJani Taskinen 	}
505525f3c47SJani Taskinen 
50647cfae87SArpad Ray 	if (PS(mod_data) || PS(mod_user_implemented)) {
507bdeb220fSAnatol Belski 		PS(mod)->s_close(&PS(mod_data));
508525f3c47SJani Taskinen 	}
509525f3c47SJani Taskinen }
510525f3c47SJani Taskinen /* }}} */
511525f3c47SJani Taskinen 
php_session_normalize_vars()51205d53deeSXinchen Hui static void php_session_normalize_vars() /* {{{ */
51305d53deeSXinchen Hui {
51405d53deeSXinchen Hui 	PS_ENCODE_VARS;
51505d53deeSXinchen Hui 
51605d53deeSXinchen Hui 	IF_SESSION_VARS() {
51705d53deeSXinchen Hui 		PS_ENCODE_LOOP(
51805d53deeSXinchen Hui 			if (Z_TYPE_P(struc) == IS_PTR) {
51905d53deeSXinchen Hui 				zval *zv = (zval *)Z_PTR_P(struc);
52005d53deeSXinchen Hui 				ZVAL_COPY_VALUE(struc, zv);
52105d53deeSXinchen Hui 				ZVAL_UNDEF(zv);
52205d53deeSXinchen Hui 			}
52305d53deeSXinchen Hui 		);
52405d53deeSXinchen Hui 	}
52505d53deeSXinchen Hui }
52605d53deeSXinchen Hui /* }}} */
52705d53deeSXinchen Hui 
528525f3c47SJani Taskinen /* *************************
529525f3c47SJani Taskinen    * INI Settings/Handlers *
530525f3c47SJani Taskinen    ************************* */
531525f3c47SJani Taskinen 
PHP_INI_MH(OnUpdateSaveHandler)532525f3c47SJani Taskinen static PHP_INI_MH(OnUpdateSaveHandler) /* {{{ */
533525f3c47SJani Taskinen {
53483e495e0SDmitry Stogov 	const ps_module *tmp;
5357f196e32SYasuo Ohgaki 
536525f3c47SJani Taskinen 	SESSION_CHECK_ACTIVE_STATE;
5377f196e32SYasuo Ohgaki 	SESSION_CHECK_OUTPUT_STATE;
538525f3c47SJani Taskinen 
5394a2e40bbSDmitry Stogov 	tmp = _php_find_ps_module(ZSTR_VAL(new_value));
540525f3c47SJani Taskinen 
541525f3c47SJani Taskinen 	if (PG(modules_activated) && !tmp) {
542525f3c47SJani Taskinen 		int err_type;
543525f3c47SJani Taskinen 
544525f3c47SJani Taskinen 		if (stage == ZEND_INI_STAGE_RUNTIME) {
5456065b29fSAnatol Belski 			err_type = E_WARNING;
546525f3c47SJani Taskinen 		} else {
547525f3c47SJani Taskinen 			err_type = E_ERROR;
548525f3c47SJani Taskinen 		}
5499ece649fSJani Taskinen 
5509ece649fSJani Taskinen 		/* Do not output error when restoring ini options. */
551525f3c47SJani Taskinen 		if (stage != ZEND_INI_STAGE_DEACTIVATE) {
5524a2e40bbSDmitry Stogov 			php_error_docref(NULL, err_type, "Cannot find save handler '%s'", ZSTR_VAL(new_value));
553525f3c47SJani Taskinen 		}
554a93a51c3SYasuo Ohgaki 
555a93a51c3SYasuo Ohgaki 		return FAILURE;
556a93a51c3SYasuo Ohgaki 	}
557a93a51c3SYasuo Ohgaki 
558a93a51c3SYasuo Ohgaki 	/* "user" save handler should not be set by user */
559a93a51c3SYasuo Ohgaki 	if (!PS(set_handler) &&  tmp == ps_user_ptr) {
56022f3695fSGraham Campbell 		php_error_docref(NULL, E_RECOVERABLE_ERROR, "Cannot set 'user' save handler by ini_set() or session_module_name()");
561525f3c47SJani Taskinen 		return FAILURE;
562525f3c47SJani Taskinen 	}
56347cfae87SArpad Ray 
56447cfae87SArpad Ray 	PS(default_mod) = PS(mod);
565525f3c47SJani Taskinen 	PS(mod) = tmp;
566525f3c47SJani Taskinen 
567525f3c47SJani Taskinen 	return SUCCESS;
568525f3c47SJani Taskinen }
569525f3c47SJani Taskinen /* }}} */
570525f3c47SJani Taskinen 
PHP_INI_MH(OnUpdateSerializer)571525f3c47SJani Taskinen static PHP_INI_MH(OnUpdateSerializer) /* {{{ */
572525f3c47SJani Taskinen {
573525f3c47SJani Taskinen 	const ps_serializer *tmp;
5747f196e32SYasuo Ohgaki 
575525f3c47SJani Taskinen 	SESSION_CHECK_ACTIVE_STATE;
5767f196e32SYasuo Ohgaki 	SESSION_CHECK_OUTPUT_STATE;
577525f3c47SJani Taskinen 
5784a2e40bbSDmitry Stogov 	tmp = _php_find_ps_serializer(ZSTR_VAL(new_value));
579525f3c47SJani Taskinen 
580525f3c47SJani Taskinen 	if (PG(modules_activated) && !tmp) {
581525f3c47SJani Taskinen 		int err_type;
582525f3c47SJani Taskinen 
583525f3c47SJani Taskinen 		if (stage == ZEND_INI_STAGE_RUNTIME) {
5846065b29fSAnatol Belski 			err_type = E_WARNING;
585525f3c47SJani Taskinen 		} else {
586525f3c47SJani Taskinen 			err_type = E_ERROR;
587525f3c47SJani Taskinen 		}
5889ece649fSJani Taskinen 
5899ece649fSJani Taskinen 		/* Do not output error when restoring ini options. */
590525f3c47SJani Taskinen 		if (stage != ZEND_INI_STAGE_DEACTIVATE) {
5914a2e40bbSDmitry Stogov 			php_error_docref(NULL, err_type, "Cannot find serialization handler '%s'", ZSTR_VAL(new_value));
592525f3c47SJani Taskinen 		}
593525f3c47SJani Taskinen 		return FAILURE;
594525f3c47SJani Taskinen 	}
595525f3c47SJani Taskinen 	PS(serializer) = tmp;
596525f3c47SJani Taskinen 
597525f3c47SJani Taskinen 	return SUCCESS;
598525f3c47SJani Taskinen }
599525f3c47SJani Taskinen /* }}} */
600525f3c47SJani Taskinen 
PHP_INI_MH(OnUpdateTransSid)601525f3c47SJani Taskinen static PHP_INI_MH(OnUpdateTransSid) /* {{{ */
602525f3c47SJani Taskinen {
603525f3c47SJani Taskinen 	SESSION_CHECK_ACTIVE_STATE;
6047f196e32SYasuo Ohgaki 	SESSION_CHECK_OUTPUT_STATE;
605525f3c47SJani Taskinen 
6064a2e40bbSDmitry Stogov 	if (!strncasecmp(ZSTR_VAL(new_value), "on", sizeof("on"))) {
607525f3c47SJani Taskinen 		PS(use_trans_sid) = (zend_bool) 1;
608525f3c47SJani Taskinen 	} else {
6094a2e40bbSDmitry Stogov 		PS(use_trans_sid) = (zend_bool) atoi(ZSTR_VAL(new_value));
610525f3c47SJani Taskinen 	}
611525f3c47SJani Taskinen 
612525f3c47SJani Taskinen 	return SUCCESS;
613525f3c47SJani Taskinen }
614525f3c47SJani Taskinen /* }}} */
615525f3c47SJani Taskinen 
6167f196e32SYasuo Ohgaki 
PHP_INI_MH(OnUpdateSaveDir)617525f3c47SJani Taskinen static PHP_INI_MH(OnUpdateSaveDir) /* {{{ */
618525f3c47SJani Taskinen {
6197f196e32SYasuo Ohgaki 	SESSION_CHECK_ACTIVE_STATE;
6207f196e32SYasuo Ohgaki 	SESSION_CHECK_OUTPUT_STATE;
6217f196e32SYasuo Ohgaki 
622525f3c47SJani Taskinen 	/* Only do the safemode/open_basedir check at runtime */
623525f3c47SJani Taskinen 	if (stage == PHP_INI_STAGE_RUNTIME || stage == PHP_INI_STAGE_HTACCESS) {
624525f3c47SJani Taskinen 		char *p;
625525f3c47SJani Taskinen 
6264a2e40bbSDmitry Stogov 		if (memchr(ZSTR_VAL(new_value), '\0', ZSTR_LEN(new_value)) != NULL) {
627525f3c47SJani Taskinen 			return FAILURE;
628525f3c47SJani Taskinen 		}
629525f3c47SJani Taskinen 
630dff4e7fdSIlia Alshanetsky 		/* we do not use zend_memrchr() since path can contain ; itself */
6314a2e40bbSDmitry Stogov 		if ((p = strchr(ZSTR_VAL(new_value), ';'))) {
632dff4e7fdSIlia Alshanetsky 			char *p2;
633525f3c47SJani Taskinen 			p++;
634dff4e7fdSIlia Alshanetsky 			if ((p2 = strchr(p, ';'))) {
635dff4e7fdSIlia Alshanetsky 				p = p2 + 1;
636dff4e7fdSIlia Alshanetsky 			}
637525f3c47SJani Taskinen 		} else {
6384a2e40bbSDmitry Stogov 			p = ZSTR_VAL(new_value);
639525f3c47SJani Taskinen 		}
640525f3c47SJani Taskinen 
641bdeb220fSAnatol Belski 		if (PG(open_basedir) && *p && php_check_open_basedir(p)) {
642525f3c47SJani Taskinen 			return FAILURE;
643525f3c47SJani Taskinen 		}
644525f3c47SJani Taskinen 	}
6459ece649fSJani Taskinen 
6467f196e32SYasuo Ohgaki 	return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
647525f3c47SJani Taskinen }
648525f3c47SJani Taskinen /* }}} */
649525f3c47SJani Taskinen 
6507f196e32SYasuo Ohgaki 
PHP_INI_MH(OnUpdateName)65187dda666SYasuo Ohgaki static PHP_INI_MH(OnUpdateName) /* {{{ */
65287dda666SYasuo Ohgaki {
6537f196e32SYasuo Ohgaki 	SESSION_CHECK_ACTIVE_STATE;
6547f196e32SYasuo Ohgaki 	SESSION_CHECK_OUTPUT_STATE;
6557f196e32SYasuo Ohgaki 
65687dda666SYasuo Ohgaki 	/* Numeric session.name won't work at all */
6574a2e40bbSDmitry Stogov 	if ((!ZSTR_LEN(new_value) || is_numeric_string(ZSTR_VAL(new_value), ZSTR_LEN(new_value), NULL, NULL, 0))) {
65887dda666SYasuo Ohgaki 		int err_type;
65987dda666SYasuo Ohgaki 
660b777248dSXinchen Hui 		if (stage == ZEND_INI_STAGE_RUNTIME || stage == ZEND_INI_STAGE_ACTIVATE || stage == ZEND_INI_STAGE_STARTUP) {
6616065b29fSAnatol Belski 			err_type = E_WARNING;
66287dda666SYasuo Ohgaki 		} else {
66387dda666SYasuo Ohgaki 			err_type = E_ERROR;
66487dda666SYasuo Ohgaki 		}
66587dda666SYasuo Ohgaki 
66687dda666SYasuo Ohgaki 		/* Do not output error when restoring ini options. */
66787dda666SYasuo Ohgaki 		if (stage != ZEND_INI_STAGE_DEACTIVATE) {
6684a2e40bbSDmitry Stogov 			php_error_docref(NULL, err_type, "session.name cannot be a numeric or empty '%s'", ZSTR_VAL(new_value));
66987dda666SYasuo Ohgaki 		}
67087dda666SYasuo Ohgaki 		return FAILURE;
67187dda666SYasuo Ohgaki 	}
67287dda666SYasuo Ohgaki 
6737f196e32SYasuo Ohgaki 	return OnUpdateStringUnempty(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
67487dda666SYasuo Ohgaki }
67587dda666SYasuo Ohgaki /* }}} */
67687dda666SYasuo Ohgaki 
6777f196e32SYasuo Ohgaki 
PHP_INI_MH(OnUpdateCookieLifetime)6787f196e32SYasuo Ohgaki static PHP_INI_MH(OnUpdateCookieLifetime) /* {{{ */
6797f196e32SYasuo Ohgaki {
6807f196e32SYasuo Ohgaki 	SESSION_CHECK_ACTIVE_STATE;
6817f196e32SYasuo Ohgaki 	SESSION_CHECK_OUTPUT_STATE;
6827f196e32SYasuo Ohgaki 	if (atol(ZSTR_VAL(new_value)) < 0) {
6837f196e32SYasuo Ohgaki 		php_error_docref(NULL, E_WARNING, "CookieLifetime cannot be negative");
6847f196e32SYasuo Ohgaki 		return FAILURE;
6857f196e32SYasuo Ohgaki 	}
6867f196e32SYasuo Ohgaki 	return OnUpdateLongGEZero(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
6877f196e32SYasuo Ohgaki }
6887f196e32SYasuo Ohgaki /* }}} */
6897f196e32SYasuo Ohgaki 
6907f196e32SYasuo Ohgaki 
PHP_INI_MH(OnUpdateSessionLong)6917f196e32SYasuo Ohgaki static PHP_INI_MH(OnUpdateSessionLong) /* {{{ */
6927f196e32SYasuo Ohgaki {
6937f196e32SYasuo Ohgaki 	SESSION_CHECK_ACTIVE_STATE;
6947f196e32SYasuo Ohgaki 	SESSION_CHECK_OUTPUT_STATE;
6957f196e32SYasuo Ohgaki 	return OnUpdateLong(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
6967f196e32SYasuo Ohgaki }
6977f196e32SYasuo Ohgaki /* }}} */
6987f196e32SYasuo Ohgaki 
6997f196e32SYasuo Ohgaki 
PHP_INI_MH(OnUpdateSessionString)7007f196e32SYasuo Ohgaki static PHP_INI_MH(OnUpdateSessionString) /* {{{ */
7017f196e32SYasuo Ohgaki {
7027f196e32SYasuo Ohgaki 	SESSION_CHECK_ACTIVE_STATE;
7037f196e32SYasuo Ohgaki 	SESSION_CHECK_OUTPUT_STATE;
7047f196e32SYasuo Ohgaki 	return OnUpdateString(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
7057f196e32SYasuo Ohgaki }
7067f196e32SYasuo Ohgaki /* }}} */
7077f196e32SYasuo Ohgaki 
7087f196e32SYasuo Ohgaki 
PHP_INI_MH(OnUpdateSessionBool)7097f196e32SYasuo Ohgaki static PHP_INI_MH(OnUpdateSessionBool) /* {{{ */
7107f196e32SYasuo Ohgaki {
7117f196e32SYasuo Ohgaki 	SESSION_CHECK_OUTPUT_STATE;
7127f196e32SYasuo Ohgaki 	SESSION_CHECK_ACTIVE_STATE;
7137f196e32SYasuo Ohgaki 	return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
7147f196e32SYasuo Ohgaki }
7157f196e32SYasuo Ohgaki /* }}} */
7167f196e32SYasuo Ohgaki 
7177f196e32SYasuo Ohgaki 
PHP_INI_MH(OnUpdateSidLength)7183467526aSYasuo Ohgaki static PHP_INI_MH(OnUpdateSidLength) /* {{{ */
719525f3c47SJani Taskinen {
720c3e3c98eSAnatol Belski 	zend_long val;
721525f3c47SJani Taskinen 	char *endptr = NULL;
722525f3c47SJani Taskinen 
7237f196e32SYasuo Ohgaki 	SESSION_CHECK_OUTPUT_STATE;
7247f196e32SYasuo Ohgaki 	SESSION_CHECK_ACTIVE_STATE;
7254a2e40bbSDmitry Stogov 	val = ZEND_STRTOL(ZSTR_VAL(new_value), &endptr, 10);
7263467526aSYasuo Ohgaki 	if (endptr && (*endptr == '\0')
7273467526aSYasuo Ohgaki 		&& val >= 22 && val <= PS_MAX_SID_LENGTH) {
728525f3c47SJani Taskinen 		/* Numeric value */
7293467526aSYasuo Ohgaki 		PS(sid_length) = val;
730525f3c47SJani Taskinen 		return SUCCESS;
731525f3c47SJani Taskinen 	}
732525f3c47SJani Taskinen 
7333467526aSYasuo Ohgaki 	php_error_docref(NULL, E_WARNING, "session.configuration 'session.sid_length' must be between 22 and 256.");
7343467526aSYasuo Ohgaki 	return FAILURE;
7353467526aSYasuo Ohgaki }
7363467526aSYasuo Ohgaki /* }}} */
737525f3c47SJani Taskinen 
PHP_INI_MH(OnUpdateSidBits)7383467526aSYasuo Ohgaki static PHP_INI_MH(OnUpdateSidBits) /* {{{ */
739525f3c47SJani Taskinen {
7403467526aSYasuo Ohgaki 	zend_long val;
7413467526aSYasuo Ohgaki 	char *endptr = NULL;
742525f3c47SJani Taskinen 
7437f196e32SYasuo Ohgaki 	SESSION_CHECK_OUTPUT_STATE;
7447f196e32SYasuo Ohgaki 	SESSION_CHECK_ACTIVE_STATE;
7453467526aSYasuo Ohgaki 	val = ZEND_STRTOL(ZSTR_VAL(new_value), &endptr, 10);
7463467526aSYasuo Ohgaki 	if (endptr && (*endptr == '\0')
7473467526aSYasuo Ohgaki 		&& val >= 4 && val <=6) {
7483467526aSYasuo Ohgaki 		/* Numeric value */
7493467526aSYasuo Ohgaki 		PS(sid_bits_per_character) = val;
750525f3c47SJani Taskinen 		return SUCCESS;
751525f3c47SJani Taskinen 	}
752525f3c47SJani Taskinen 
753d20053a5SChristoph M. Becker 	php_error_docref(NULL, E_WARNING, "session.configuration 'session.sid_bits_per_character' must be between 4 and 6.");
754525f3c47SJani Taskinen 	return FAILURE;
755525f3c47SJani Taskinen }
756525f3c47SJani Taskinen /* }}} */
757525f3c47SJani Taskinen 
7583467526aSYasuo Ohgaki 
PHP_INI_MH(OnUpdateLazyWrite)7597f196e32SYasuo Ohgaki static PHP_INI_MH(OnUpdateLazyWrite) /* {{{ */
7607f196e32SYasuo Ohgaki {
7617f196e32SYasuo Ohgaki 	SESSION_CHECK_ACTIVE_STATE;
7627f196e32SYasuo Ohgaki 	SESSION_CHECK_OUTPUT_STATE;
7637f196e32SYasuo Ohgaki 	return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
7647f196e32SYasuo Ohgaki }
7657f196e32SYasuo Ohgaki /* }}} */
7667f196e32SYasuo Ohgaki 
7677f196e32SYasuo Ohgaki 
7687f196e32SYasuo Ohgaki 
PHP_INI_MH(OnUpdateRfc1867Freq)769da9448f3SArnaud Le Blanc static PHP_INI_MH(OnUpdateRfc1867Freq) /* {{{ */
770da9448f3SArnaud Le Blanc {
771512429ffSAnatol Belski 	int tmp;
7720d1eeeb6SAnatol Belski 	tmp = zend_atoi(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
773da9448f3SArnaud Le Blanc 	if(tmp < 0) {
774bdeb220fSAnatol Belski 		php_error_docref(NULL, E_WARNING, "session.upload_progress.freq must be greater than or equal to zero");
775da9448f3SArnaud Le Blanc 		return FAILURE;
776da9448f3SArnaud Le Blanc 	}
7774a2e40bbSDmitry Stogov 	if(ZSTR_LEN(new_value) > 0 && ZSTR_VAL(new_value)[ZSTR_LEN(new_value)-1] == '%') {
778da9448f3SArnaud Le Blanc 		if(tmp > 100) {
779bdeb220fSAnatol Belski 			php_error_docref(NULL, E_WARNING, "session.upload_progress.freq cannot be over 100%%");
780da9448f3SArnaud Le Blanc 			return FAILURE;
781da9448f3SArnaud Le Blanc 		}
782da9448f3SArnaud Le Blanc 		PS(rfc1867_freq) = -tmp;
783da9448f3SArnaud Le Blanc 	} else {
784da9448f3SArnaud Le Blanc 		PS(rfc1867_freq) = tmp;
785da9448f3SArnaud Le Blanc 	}
786da9448f3SArnaud Le Blanc 	return SUCCESS;
787da9448f3SArnaud Le Blanc } /* }}} */
788da9448f3SArnaud Le Blanc 
789525f3c47SJani Taskinen /* {{{ PHP_INI
790525f3c47SJani Taskinen  */
791525f3c47SJani Taskinen PHP_INI_BEGIN()
7927f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.save_path",          "",          PHP_INI_ALL, OnUpdateSaveDir,       save_path,          php_ps_globals,    ps_globals)
7937f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.name",               "PHPSESSID", PHP_INI_ALL, OnUpdateName,          session_name,       php_ps_globals,    ps_globals)
794525f3c47SJani Taskinen 	PHP_INI_ENTRY("session.save_handler",           "files",     PHP_INI_ALL, OnUpdateSaveHandler)
7957f196e32SYasuo Ohgaki 	STD_PHP_INI_BOOLEAN("session.auto_start",       "0",         PHP_INI_PERDIR, OnUpdateBool,       auto_start,         php_ps_globals,    ps_globals)
7967f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.gc_probability",     "1",         PHP_INI_ALL, OnUpdateSessionLong,          gc_probability,     php_ps_globals,    ps_globals)
7977f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.gc_divisor",         "100",       PHP_INI_ALL, OnUpdateSessionLong,          gc_divisor,         php_ps_globals,    ps_globals)
7987f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.gc_maxlifetime",     "1440",      PHP_INI_ALL, OnUpdateSessionLong,          gc_maxlifetime,     php_ps_globals,    ps_globals)
799525f3c47SJani Taskinen 	PHP_INI_ENTRY("session.serialize_handler",      "php",       PHP_INI_ALL, OnUpdateSerializer)
8007f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.cookie_lifetime",    "0",         PHP_INI_ALL, OnUpdateCookieLifetime,cookie_lifetime,    php_ps_globals,    ps_globals)
8017f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.cookie_path",        "/",         PHP_INI_ALL, OnUpdateSessionString, cookie_path,        php_ps_globals,    ps_globals)
8027f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.cookie_domain",      "",          PHP_INI_ALL, OnUpdateSessionString, cookie_domain,      php_ps_globals,    ps_globals)
8037f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.cookie_secure",      "0",         PHP_INI_ALL, OnUpdateSessionBool,   cookie_secure,      php_ps_globals,    ps_globals)
8047f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.cookie_httponly",    "0",         PHP_INI_ALL, OnUpdateSessionBool,   cookie_httponly,    php_ps_globals,    ps_globals)
80508b9310eSFrederik Bosch 	STD_PHP_INI_ENTRY("session.cookie_samesite",    "",          PHP_INI_ALL, OnUpdateString,        cookie_samesite,    php_ps_globals,    ps_globals)
8067f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.use_cookies",        "1",         PHP_INI_ALL, OnUpdateSessionBool,   use_cookies,        php_ps_globals,    ps_globals)
8077f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.use_only_cookies",   "1",         PHP_INI_ALL, OnUpdateSessionBool,   use_only_cookies,   php_ps_globals,    ps_globals)
8087f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.use_strict_mode",    "0",         PHP_INI_ALL, OnUpdateSessionBool,   use_strict_mode,    php_ps_globals,    ps_globals)
8097f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.referer_check",      "",          PHP_INI_ALL, OnUpdateSessionString, extern_referer_chk, php_ps_globals,    ps_globals)
8107f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.cache_limiter",      "nocache",   PHP_INI_ALL, OnUpdateSessionString, cache_limiter,      php_ps_globals,    ps_globals)
8117f196e32SYasuo Ohgaki 	STD_PHP_INI_ENTRY("session.cache_expire",       "180",       PHP_INI_ALL, OnUpdateSessionLong,   cache_expire,       php_ps_globals,    ps_globals)
812525f3c47SJani Taskinen 	PHP_INI_ENTRY("session.use_trans_sid",          "0",         PHP_INI_ALL, OnUpdateTransSid)
8133467526aSYasuo Ohgaki 	PHP_INI_ENTRY("session.sid_length",             "32",        PHP_INI_ALL, OnUpdateSidLength)
8143467526aSYasuo Ohgaki 	PHP_INI_ENTRY("session.sid_bits_per_character", "4",         PHP_INI_ALL, OnUpdateSidBits)
8157f196e32SYasuo Ohgaki 	STD_PHP_INI_BOOLEAN("session.lazy_write",       "1",         PHP_INI_ALL, OnUpdateLazyWrite,     lazy_write,         php_ps_globals,    ps_globals)
816525f3c47SJani Taskinen 
817da9448f3SArnaud Le Blanc 	/* Upload progress */
818da9448f3SArnaud Le Blanc 	STD_PHP_INI_BOOLEAN("session.upload_progress.enabled",
819da9448f3SArnaud Le Blanc 	                                                "1",     ZEND_INI_PERDIR, OnUpdateBool,        rfc1867_enabled, php_ps_globals, ps_globals)
8204f3b6196SArnaud Le Blanc 	STD_PHP_INI_BOOLEAN("session.upload_progress.cleanup",
8214f3b6196SArnaud Le Blanc 	                                                "1",     ZEND_INI_PERDIR, OnUpdateBool,        rfc1867_cleanup, php_ps_globals, ps_globals)
822da9448f3SArnaud Le Blanc 	STD_PHP_INI_ENTRY("session.upload_progress.prefix",
8235c1595caSXinchen Hui 	                                     "upload_progress_", ZEND_INI_PERDIR, OnUpdateString,      rfc1867_prefix,  php_ps_globals, ps_globals)
824da9448f3SArnaud Le Blanc 	STD_PHP_INI_ENTRY("session.upload_progress.name",
8255c1595caSXinchen Hui 	                          "PHP_SESSION_UPLOAD_PROGRESS", ZEND_INI_PERDIR, OnUpdateString,      rfc1867_name,    php_ps_globals, ps_globals)
826da9448f3SArnaud Le Blanc 	STD_PHP_INI_ENTRY("session.upload_progress.freq",  "1%", ZEND_INI_PERDIR, OnUpdateRfc1867Freq, rfc1867_freq,    php_ps_globals, ps_globals)
827da9448f3SArnaud Le Blanc 	STD_PHP_INI_ENTRY("session.upload_progress.min_freq",
828da9448f3SArnaud Le Blanc 	                                                   "1",  ZEND_INI_PERDIR, OnUpdateReal,        rfc1867_min_freq,php_ps_globals, ps_globals)
829da9448f3SArnaud Le Blanc 
830525f3c47SJani Taskinen 	/* Commented out until future discussion */
831525f3c47SJani Taskinen 	/* PHP_INI_ENTRY("session.encode_sources", "globals,track", PHP_INI_ALL, NULL) */
PHP_INI_END()832525f3c47SJani Taskinen PHP_INI_END()
833525f3c47SJani Taskinen /* }}} */
834525f3c47SJani Taskinen 
835525f3c47SJani Taskinen /* ***************
836525f3c47SJani Taskinen    * Serializers *
837525f3c47SJani Taskinen    *************** */
838c51f77feSYasuo Ohgaki PS_SERIALIZER_ENCODE_FUNC(php_serialize) /* {{{ */
839c51f77feSYasuo Ohgaki {
840c51f77feSYasuo Ohgaki 	smart_str buf = {0};
841c51f77feSYasuo Ohgaki 	php_serialize_data_t var_hash;
842c51f77feSYasuo Ohgaki 
843e6c8640aSYasuo Ohgaki 	IF_SESSION_VARS() {
844e6c8640aSYasuo Ohgaki 		PHP_VAR_SERIALIZE_INIT(var_hash);
845e6c8640aSYasuo Ohgaki 		php_var_serialize(&buf, Z_REFVAL(PS(http_session_vars)), &var_hash);
846e6c8640aSYasuo Ohgaki 		PHP_VAR_SERIALIZE_DESTROY(var_hash);
847e6c8640aSYasuo Ohgaki 	}
848c9bca503SXinchen Hui 	return buf.s;
849c51f77feSYasuo Ohgaki }
850c51f77feSYasuo Ohgaki /* }}} */
851c51f77feSYasuo Ohgaki 
PS_SERIALIZER_DECODE_FUNC(php_serialize)852c51f77feSYasuo Ohgaki PS_SERIALIZER_DECODE_FUNC(php_serialize) /* {{{ */
853c51f77feSYasuo Ohgaki {
854c51f77feSYasuo Ohgaki 	const char *endptr = val + vallen;
855c9bca503SXinchen Hui 	zval session_vars;
856c51f77feSYasuo Ohgaki 	php_unserialize_data_t var_hash;
857e0f9fbdfSNikita Popov 	int result;
858c3e3c98eSAnatol Belski 	zend_string *var_name = zend_string_init("_SESSION", sizeof("_SESSION") - 1, 0);
859c51f77feSYasuo Ohgaki 
8603647fc6fSXinchen Hui 	ZVAL_NULL(&session_vars);
861c51f77feSYasuo Ohgaki 	PHP_VAR_UNSERIALIZE_INIT(var_hash);
862e0f9fbdfSNikita Popov 	result = php_var_unserialize(
863e0f9fbdfSNikita Popov 		&session_vars, (const unsigned char **)&val, (const unsigned char *)endptr, &var_hash);
864c51f77feSYasuo Ohgaki 	PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
865e0f9fbdfSNikita Popov 	if (!result) {
866e0f9fbdfSNikita Popov 		zval_ptr_dtor(&session_vars);
867e0f9fbdfSNikita Popov 		ZVAL_NULL(&session_vars);
868e0f9fbdfSNikita Popov 	}
869e0f9fbdfSNikita Popov 
870d8651fbeSXinchen Hui 	if (!Z_ISUNDEF(PS(http_session_vars))) {
871c51f77feSYasuo Ohgaki 		zval_ptr_dtor(&PS(http_session_vars));
872c51f77feSYasuo Ohgaki 	}
873c9bca503SXinchen Hui 	if (Z_TYPE(session_vars) == IS_NULL) {
8743647fc6fSXinchen Hui 		array_init(&session_vars);
875b7a7b1a6SStanislav Malyshev 	}
8763647fc6fSXinchen Hui 	ZVAL_NEW_REF(&PS(http_session_vars), &session_vars);
877050d7e38SDmitry Stogov 	Z_ADDREF_P(&PS(http_session_vars));
878e10e151eSDmitry Stogov 	zend_hash_update_ind(&EG(symbol_table), var_name, &PS(http_session_vars));
8795eb1f92fSDmitry Stogov 	zend_string_release_ex(var_name, 0);
880c51f77feSYasuo Ohgaki 	return SUCCESS;
881c51f77feSYasuo Ohgaki }
882c51f77feSYasuo Ohgaki /* }}} */
883525f3c47SJani Taskinen 
884525f3c47SJani Taskinen #define PS_BIN_NR_OF_BITS 8
885525f3c47SJani Taskinen #define PS_BIN_UNDEF (1<<(PS_BIN_NR_OF_BITS-1))
886525f3c47SJani Taskinen #define PS_BIN_MAX (PS_BIN_UNDEF-1)
887525f3c47SJani Taskinen 
PS_SERIALIZER_ENCODE_FUNC(php_binary)888525f3c47SJani Taskinen PS_SERIALIZER_ENCODE_FUNC(php_binary) /* {{{ */
889525f3c47SJani Taskinen {
890525f3c47SJani Taskinen 	smart_str buf = {0};
891525f3c47SJani Taskinen 	php_serialize_data_t var_hash;
892525f3c47SJani Taskinen 	PS_ENCODE_VARS;
893525f3c47SJani Taskinen 
894525f3c47SJani Taskinen 	PHP_VAR_SERIALIZE_INIT(var_hash);
895525f3c47SJani Taskinen 
896525f3c47SJani Taskinen 	PS_ENCODE_LOOP(
8974a2e40bbSDmitry Stogov 			if (ZSTR_LEN(key) > PS_BIN_MAX) continue;
8984a2e40bbSDmitry Stogov 			smart_str_appendc(&buf, (unsigned char)ZSTR_LEN(key));
8994a2e40bbSDmitry Stogov 			smart_str_appendl(&buf, ZSTR_VAL(key), ZSTR_LEN(key));
900bdeb220fSAnatol Belski 			php_var_serialize(&