diff -ur php-4.3.5/ext/session/php_session.h php-4.3.5.sess/ext/session/php_session.h --- php-4.3.5/ext/session/php_session.h 2004-04-06 21:50:28.000000000 +0200 +++ php-4.3.5.sess/ext/session/php_session.h 2004-04-07 12:47:25.000000000 +0200 @@ -123,7 +123,10 @@ /* ++++++ BEGIN SESFIX */ zend_bool checkip; + zend_bool classmask; + zend_bool checkattrs; char *ipname; + char *signname; /* ++++++ END SESFIX */ } php_ps_globals; diff -ur php-4.3.5/ext/session/session.c php-4.3.5.sess/ext/session/session.c --- php-4.3.5/ext/session/session.c 2004-04-06 21:50:28.000000000 +0200 +++ php-4.3.5.sess/ext/session/session.c 2004-04-07 13:13:07.000000000 +0200 @@ -146,7 +146,10 @@ /* ++++++ BEGIN SESFIX */ STD_PHP_INI_BOOLEAN("session.checkip", "1", PHP_INI_ALL, OnUpdateBool, checkip, php_ps_globals, ps_globals) + STD_PHP_INI_BOOLEAN("session.classmask", "1", PHP_INI_ALL, OnUpdateBool, classmask, php_ps_globals, ps_globals) + STD_PHP_INI_BOOLEAN("session.checkattrs", "1", PHP_INI_ALL, OnUpdateBool, checkattrs, php_ps_globals, ps_globals) STD_PHP_INI_ENTRY("session.ipname", "_SESSIP_", PHP_INI_SYSTEM, OnUpdateString, ipname, php_ps_globals, ps_globals) + STD_PHP_INI_ENTRY("session.signname", "_SESSSIGN_", PHP_INI_SYSTEM, OnUpdateString, signname, php_ps_globals, ps_globals) /* ++++++ END SESFIX */ PHP_INI_END() @@ -590,6 +593,177 @@ return estrdup(buf); } +/* + * ++++++ BEGIN SESFIX + * To minimise session fixation risk, we create a session variable + * which value is the client IP address if this is a session creation, + * otherwise we check the value of the currently saved IP address: + */ +static void session_fix_md5(char md5str[], zval **lang, zval **agent) +{ + /* taken from ext/standard/md5.c file: */ + PHP_MD5_CTX context; + unsigned char digest[16]; + + md5str[0] = '\0'; + PHP_MD5Init(&context); + if (lang) PHP_MD5Update(&context,Z_STRVAL_PP(lang),Z_STRLEN_PP(lang)); + if (agent) PHP_MD5Update(&context,Z_STRVAL_PP(agent),Z_STRLEN_PP(agent)); + PHP_MD5Final(digest,&context); + make_digest(md5str,digest); +} + +static void session_fix_get_browser(char md5str[], zval **data) +{ + char *httplang = "HTTP_ACCEPT_LANGUAGE"; + char *httpusag = "HTTP_USER_AGENT"; + zval **lang = NULL; + zval **agent = NULL; + zend_hash_find(Z_ARRVAL_PP(data), httplang, + strlen(httplang) + 1, (void **) &lang); + zend_hash_find(Z_ARRVAL_PP(data), httpusag, + strlen(httpusag) + 1, (void **) &agent); + session_fix_md5(md5str,lang,agent); +} + +static void session_fix_error() +{ + void php_session_initialize(TSRMLS_D); + + /* create a new session: */ + PS(id) = NULL; + php_session_initialize(TSRMLS_C); +} + +static int session_fix_compareip(char *rip, char *ipval) +{ + if (PS(classmask)) { + unsigned long ip1,ip2; + inet_aton(rip,(struct in_addr *)&ip1); + inet_aton(ipval,(struct in_addr *)&ip2); + ip1 = ntohl(ip1); + ip2 = ntohl(ip2); + + /* Determine the class of "ip1" (A,B or C) */ + if (ip1 < 0x80000000) { + /* A class: */ + return ((ip1 & 0xFF000000) == (ip2 & 0xFF000000)); + } + else if (ip1 < 0xC0000000) { + /* B class: */ + return ((ip1 & 0xFFFF0000) == (ip2 & 0xFFFF0000)); + } + else { + /* C class: */ + return ((ip1 & 0xFFFFFF00) == (ip2 & 0xFFFFFF00)); + } + } + + return !strcmp(rip,ipval); +} + +static void session_fix_checkip(zval **data) +{ + void php_register_var(zval** entry TSRMLS_DC); + + char *remoteip = "REMOTE_ADDR"; + int lenvar = strlen(remoteip); + zval **rip; + + /* 1-Get the client IP address: */ + if (zend_hash_find(Z_ARRVAL_PP(data), remoteip, + lenvar + 1, (void **) &rip) == SUCCESS) { + + /* 2-Check if the session already contains a client IP address: */ + char *varname = PS(ipname); + zval **ipval; + lenvar = strlen(varname); + + if (php_get_session_var(varname,lenvar,&ipval TSRMLS_CC) == SUCCESS) { + /* 3a-saved and current IP address must match: */ + convert_to_string_ex(rip); + convert_to_string_ex(ipval); + + if (!session_fix_compareip(Z_STRVAL_PP(rip),Z_STRVAL_PP(ipval))) { + char buff[256]; + sprintf(buff,"PHP/Session: [Address mismatch] " + "Client with IP Address '%s' tries to use " + "the session defined by Client with IP " + "Address '%s'.", + Z_STRVAL_PP(rip),Z_STRVAL_PP(ipval)); + php_log_err(buff); + session_fix_error(); + return; + } + } + else { + /* 4-Add the client IP addr in the session variables: */ + zval *newvar; + MAKE_STD_ZVAL(newvar); + ZVAL_STRING(newvar,varname,0); + lenvar = strlen(varname); + php_register_var(&newvar TSRMLS_CC); + php_set_session_var(varname,lenvar,*rip,NULL TSRMLS_CC); + } + } + else { + php_log_err("The remote IP address is not available (?) - " + "the session could not be handled"); + } +} + +static void session_fix_checkattrs(zval **data) +{ + void php_register_var(zval** entry TSRMLS_DC); + + char *md5name = PS(signname); + int lenvar = strlen(md5name); + zval **md5val; + char md5str[33]; + + session_fix_get_browser(md5str,data); + /* php_log_err(md5str); */ + + if (php_get_session_var(md5name,lenvar,&md5val TSRMLS_CC) == SUCCESS) { + convert_to_string_ex(md5val); + if (strcmp(Z_STRVAL_PP(md5val),md5str)) { + char buff[256]; + char *remoteip = "REMOTE_ADDR"; + int lenvar = strlen(remoteip); + zval **rip; + + if (zend_hash_find(Z_ARRVAL_PP(data),remoteip,lenvar+1, + (void **)&rip) == SUCCESS) { + sprintf(buff,"PHP/Session: [Attributes mismatch] " + "Client with IP Address '%s' tries to use " + "the session defined by another Client.", + Z_STRVAL_PP(rip)); + } + else { + sprintf(buff,"PHP/Session: [Attributes mismatch] " + "Client tries to use " + "the session defined by another Client."); + } + + php_log_err(buff); + session_fix_error(); + return; + } + } + else { + zval *newvar; + zval *md5val; + + MAKE_STD_ZVAL(md5val); + ZVAL_STRING(md5val,md5str,1); + MAKE_STD_ZVAL(newvar); + ZVAL_STRING(newvar,md5name,0); + php_register_var(&newvar TSRMLS_CC); + php_set_session_var(md5name,lenvar,md5val,NULL TSRMLS_CC); + } +} +/* ++++++ END SESFIX */ + static void php_session_initialize(TSRMLS_D) { char *val; @@ -622,73 +796,17 @@ efree(val); } - /* - * ++++++ BEGIN SESFIX - * To minimise session fixation risk, we create a session variable - * which value is the client IP address if this is a session creation, - * otherwise we check the value of the currently saved IP address: - */ + /* +++++ BEGIN SESFIX */ { - void php_register_var(zval** entry TSRMLS_DC); - - char *remoteip = "REMOTE_ADDR"; - int lenvar = strlen(remoteip); zval **data; - zval **rip; - - /* 0-test enabled ? */ - if (!PS(checkip)) - return; - - /* 1-Get the client IP address: */ if (zend_hash_find(&EG(symbol_table), "_SERVER", - sizeof("_SERVER"), (void **) &data) == SUCCESS && - Z_TYPE_PP(data) == IS_ARRAY && - zend_hash_find(Z_ARRVAL_PP(data), remoteip, - lenvar + 1, (void **) &rip) == SUCCESS) { - - /* 2-Check if the session already contains a client IP address: */ - char *varname = PS(ipname); - int len = strlen(varname); - zval **ipval; - - if (php_get_session_var(varname,len,&ipval TSRMLS_CC) == SUCCESS) { - /* 3-saved and current IP address must match: */ - convert_to_string_ex(rip); - convert_to_string_ex(ipval); - if (strcmp(Z_STRVAL_PP(rip),Z_STRVAL_PP(ipval))) { - char buff[256]; - sprintf(buff,"PHP/Session: " - "Client with IP Address '%s' tries to use " - "the session defined by Client with IP " - "Adresse '%s'.", - Z_STRVAL_PP(rip),Z_STRVAL_PP(ipval)); - php_log_err(buff); - - /* create a new session: */ - PS(id) = NULL; - php_session_initialize(TSRMLS_C); - return; - } - else { - /* Add info in debug mode ? */ - } - } - else { - /* 4-Add the client IP addr in the session variables: */ - zval *newvar; - MAKE_STD_ZVAL(newvar); - ZVAL_STRING(newvar,varname,0); - php_register_var(&newvar TSRMLS_CC); - php_set_session_var(varname, len, *rip, NULL TSRMLS_CC); - } - } - else { - php_log_err("The remote IP address is not available (?) - " - "the session could not be handled"); + sizeof("_SERVER"), (void **) &data) == SUCCESS && + Z_TYPE_PP(data) == IS_ARRAY) { + if (PS(checkip)) session_fix_checkip(data); + if (PS(checkattrs)) session_fix_checkattrs(data); } } - /* ++++++ END SESFIX */ + /* +++++ END SESFIX */ } static int migrate_global(HashTable *ht, HashPosition *pos TSRMLS_DC) @@ -1698,6 +1816,7 @@ /* ++++++ BEGIN SESFIX */ ps_globals->ipname = NULL; + ps_globals->signname = NULL; /* ++++++ END SESFIX */ }