From 7ce0f98b0be3ad15a664e506dff461cf6d633a69 Mon Sep 17 00:00:00 2001 From: jvoisin Date: Sun, 13 Oct 2019 12:35:52 +0200 Subject: Add more patches --- 0.2.7/hardened-php-4.3.10-0.2.7.patch | 5918 ++++++++++ 0.2.7/hardened-php-4.3.11-0.2.7.patch | 3417 ++++++ 0.2.7/hardened-php-5.0.4-0.2.7.patch | 3100 +++++ 0.3.2/hardening-patch-4.3.11-0.3.2.patch | 12205 ++++++++++++++++++++ 0.3.2/hardening-patch-4.4.0RC2-0.3.2.patch | 4959 ++++++++ 0.3.2/hardening-patch-5.0.4-0.3.2.patch | 11892 +++++++++++++++++++ 0.4.2/hardening-patch-4.3.11-0.4.2.patch | 14426 ++++++++++++++++++++++++ 0.4.2/hardening-patch-4.4.0-0.4.2.patch | 14668 ++++++++++++++++++++++++ 0.4.2/hardening-patch-5.0.5-0.4.2.patch | 6671 +++++++++++ 0.4.3/.hardening-patch-5.0.5-0.4.3.patch.swp | Bin 0 -> 16384 bytes 0.4.3/hardening-patch-4.4.0-0.4.3.patch | 15043 +++++++++++++++++++++++++ 0.4.3/hardening-patch-5.0.5-0.4.3.patch | 7046 ++++++++++++ 12 files changed, 99345 insertions(+) create mode 100644 0.2.7/hardened-php-4.3.10-0.2.7.patch create mode 100644 0.2.7/hardened-php-4.3.11-0.2.7.patch create mode 100644 0.2.7/hardened-php-5.0.4-0.2.7.patch create mode 100644 0.3.2/hardening-patch-4.3.11-0.3.2.patch create mode 100644 0.3.2/hardening-patch-4.4.0RC2-0.3.2.patch create mode 100644 0.3.2/hardening-patch-5.0.4-0.3.2.patch create mode 100644 0.4.2/hardening-patch-4.3.11-0.4.2.patch create mode 100644 0.4.2/hardening-patch-4.4.0-0.4.2.patch create mode 100644 0.4.2/hardening-patch-5.0.5-0.4.2.patch create mode 100644 0.4.3/.hardening-patch-5.0.5-0.4.3.patch.swp create mode 100644 0.4.3/hardening-patch-4.4.0-0.4.3.patch create mode 100644 0.4.3/hardening-patch-5.0.5-0.4.3.patch diff --git a/0.2.7/hardened-php-4.3.10-0.2.7.patch b/0.2.7/hardened-php-4.3.10-0.2.7.patch new file mode 100644 index 0000000..cb5c546 --- /dev/null +++ b/0.2.7/hardened-php-4.3.10-0.2.7.patch @@ -0,0 +1,5918 @@ +diff -Nur php-4.3.10/README.input_filter hardened-php-4.3.10-0.2.7/README.input_filter +--- php-4.3.10/README.input_filter 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/README.input_filter 2005-04-07 01:51:16.000000000 +0200 +@@ -0,0 +1,193 @@ ++Input Filter Support ported from PHP 5 ++-------------------------------------- ++ ++XSS (Cross Site Scripting) hacks are becoming more and more prevalent, ++and can be quite difficult to prevent. Whenever you accept user data ++and somehow display this data back to users, you are likely vulnerable ++to XSS hacks. ++ ++The Input Filter support in PHP 5 is aimed at providing the framework ++through which a company-wide or site-wide security policy can be ++enforced. It is implemented as a SAPI hook and is called from the ++treat_data and post handler functions. To implement your own security ++policy you will need to write a standard PHP extension. ++ ++A simple implementation might look like the following. This stores the ++original raw user data and adds a my_get_raw() function while the normal ++$_POST, $_GET and $_COOKIE arrays are only populated with stripped ++data. In this simple example all I am doing is calling strip_tags() on ++the data. If register_globals is turned on, the default globals that ++are created will be stripped ($foo) while a $RAW_foo is created with the ++original user input. ++ ++ZEND_BEGIN_MODULE_GLOBALS(my_input_filter) ++ zval *post_array; ++ zval *get_array; ++ zval *cookie_array; ++ZEND_END_MODULE_GLOBALS(my_input_filter) ++ ++#ifdef ZTS ++#define IF_G(v) TSRMG(my_input_filter_globals_id, zend_my_input_filter_globals *, v) ++#else ++#define IF_G(v) (my_input_filter_globals.v) ++#endif ++ ++ZEND_DECLARE_MODULE_GLOBALS(my_input_filter) ++ ++function_entry my_input_filter_functions[] = { ++ PHP_FE(my_get_raw, NULL) ++ {NULL, NULL, NULL} ++}; ++ ++zend_module_entry my_input_filter_module_entry = { ++ STANDARD_MODULE_HEADER, ++ "my_input_filter", ++ my_input_filter_functions, ++ PHP_MINIT(my_input_filter), ++ PHP_MSHUTDOWN(my_input_filter), ++ NULL, ++ PHP_RSHUTDOWN(my_input_filter), ++ PHP_MINFO(my_input_filter), ++ "0.1", ++ STANDARD_MODULE_PROPERTIES ++}; ++ ++PHP_MINIT_FUNCTION(my_input_filter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(my_input_filter, php_my_input_filter_init_globals, NULL); ++ ++ REGISTER_LONG_CONSTANT("POST", PARSE_POST, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("GET", PARSE_GET, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("COOKIE", PARSE_COOKIE, CONST_CS | CONST_PERSISTENT); ++ ++ sapi_register_input_filter(my_sapi_input_filter); ++ return SUCCESS; ++} ++ ++PHP_RSHUTDOWN_FUNCTION(my_input_filter) ++{ ++ if(IF_G(get_array)) { ++ zval_ptr_dtor(&IF_G(get_array)); ++ IF_G(get_array) = NULL; ++ } ++ if(IF_G(post_array)) { ++ zval_ptr_dtor(&IF_G(post_array)); ++ IF_G(post_array) = NULL; ++ } ++ if(IF_G(cookie_array)) { ++ zval_ptr_dtor(&IF_G(cookie_array)); ++ IF_G(cookie_array) = NULL; ++ } ++ return SUCCESS; ++} ++ ++PHP_MINFO_FUNCTION(my_input_filter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_row( 2, "My Input Filter Support", "enabled" ); ++ php_info_print_table_row( 2, "Revision", "$Revision: 1.1 $"); ++ php_info_print_table_end(); ++} ++ ++/* The filter handler. If you return 1 from it, then PHP also registers the ++ * (modified) variable. Returning 0 prevents PHP from registering the variable; ++ * you can use this if your filter already registers the variable under a ++ * different name, or if you just don't want the variable registered at all. */ ++SAPI_INPUT_FILTER_FUNC(my_sapi_input_filter) ++{ ++ zval new_var; ++ zval *array_ptr = NULL; ++ char *raw_var; ++ int var_len; ++ ++ assert(*val != NULL); ++ ++ switch(arg) { ++ case PARSE_GET: ++ if(!IF_G(get_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(get_array) = array_ptr; ++ break; ++ case PARSE_POST: ++ if(!IF_G(post_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(post_array) = array_ptr; ++ break; ++ case PARSE_COOKIE: ++ if(!IF_G(cookie_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(cookie_array) = array_ptr; ++ break; ++ } ++ Z_STRLEN(new_var) = val_len; ++ Z_STRVAL(new_var) = estrndup(*val, val_len); ++ Z_TYPE(new_var) = IS_STRING; ++ ++ var_len = strlen(var); ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ ++ php_register_variable_ex(raw_var, &new_var, array_ptr TSRMLS_DC); ++ ++ php_strip_tags(*val, val_len, NULL, NULL, 0); ++ ++ *new_val_len = strlen(*val); ++ return 1; ++} ++ ++PHP_FUNCTION(my_get_raw) ++{ ++ long arg; ++ char *var; ++ int var_len; ++ zval **tmp; ++ zval *array_ptr = NULL; ++ HashTable *hash_ptr; ++ char *raw_var; ++ ++ if(zend_parse_parameters(2 TSRMLS_CC, "ls", &arg, &var, &var_len) == FAILURE) { ++ return; ++ } ++ ++ switch(arg) { ++ case PARSE_GET: ++ array_ptr = IF_G(get_array); ++ break; ++ case PARSE_POST: ++ array_ptr = IF_G(post_array); ++ break; ++ case PARSE_COOKIE: ++ array_ptr = IF_G(post_array); ++ break; ++ } ++ ++ if(!array_ptr) RETURN_FALSE; ++ ++ /* ++ * I'm changing the variable name here because when running with register_globals on, ++ * the variable will end up in the global symbol table ++ */ ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ hash_ptr = HASH_OF(array_ptr); ++ ++ if(zend_hash_find(hash_ptr, raw_var, var_len+5, (void **)&tmp) == SUCCESS) { ++ *return_value = **tmp; ++ zval_copy_ctor(return_value); ++ } else { ++ RETVAL_FALSE; ++ } ++ efree(raw_var); ++} ++ +diff -Nur php-4.3.10/TSRM/TSRM.h hardened-php-4.3.10-0.2.7/TSRM/TSRM.h +--- php-4.3.10/TSRM/TSRM.h 2002-10-05 13:26:17.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/TSRM/TSRM.h 2005-04-07 01:51:16.000000000 +0200 +@@ -33,6 +33,13 @@ + # define TSRM_API + #endif + ++#if HARDENED_PHP ++# if HAVE_REALPATH ++# undef realpath ++# define realpath php_realpath ++# endif ++#endif ++ + /* Only compile multi-threading functions if we're in ZTS mode */ + #ifdef ZTS + +@@ -90,6 +97,7 @@ + + #define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts + ++ + #ifdef __cplusplus + extern "C" { + #endif +diff -Nur php-4.3.10/TSRM/tsrm_virtual_cwd.c hardened-php-4.3.10-0.2.7/TSRM/tsrm_virtual_cwd.c +--- php-4.3.10/TSRM/tsrm_virtual_cwd.c 2004-12-02 02:04:46.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/TSRM/tsrm_virtual_cwd.c 2005-04-07 01:51:16.000000000 +0200 +@@ -17,7 +17,7 @@ + +----------------------------------------------------------------------+ + */ + +-/* $Id: tsrm_virtual_cwd.c,v 1.41.2.8 2004/12/02 01:04:46 sesser Exp $ */ ++/* $Id: tsrm_virtual_cwd.c,v 1.41.2.4 2003/07/28 18:35:34 iliaa Exp $ */ + + #include + #include +@@ -192,6 +192,165 @@ + return p; + } + ++#if HARDENED_PHP ++CWD_API char *php_realpath(const char *path, char *resolved) ++{ ++ struct stat sb; ++ char *p, *q, *s; ++ size_t left_len, resolved_len; ++ unsigned symlinks; ++ int serrno, slen; ++ int is_dir = 1; ++ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; ++ ++ serrno = errno; ++ symlinks = 0; ++ if (path[0] == '/') { ++ resolved[0] = '/'; ++ resolved[1] = '\0'; ++ if (path[1] == '\0') ++ return (resolved); ++ resolved_len = 1; ++ left_len = strlcpy(left, path + 1, sizeof(left)); ++ } else { ++ if (getcwd(resolved, PATH_MAX) == NULL) { ++ strlcpy(resolved, ".", PATH_MAX); ++ return (NULL); ++ } ++ resolved_len = strlen(resolved); ++ left_len = strlcpy(left, path, sizeof(left)); ++ } ++ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ ++ /* ++ * Iterate over path components in `left'. ++ */ ++ while (left_len != 0) { ++ /* ++ * Extract the next path component and adjust `left' ++ * and its length. ++ */ ++ p = strchr(left, '/'); ++ s = p ? p : left + left_len; ++ if (s - left >= sizeof(next_token)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ memcpy(next_token, left, s - left); ++ next_token[s - left] = '\0'; ++ left_len -= s - left; ++ if (p != NULL) ++ memmove(left, s + 1, left_len + 1); ++ if (resolved[resolved_len - 1] != '/') { ++ if (resolved_len + 1 >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ resolved[resolved_len++] = '/'; ++ resolved[resolved_len] = '\0'; ++ } ++ if (next_token[0] == '\0') ++ continue; ++ else if (strcmp(next_token, ".") == 0) ++ continue; ++ else if (strcmp(next_token, "..") == 0) { ++ /* ++ * Strip the last path component except when we have ++ * single "/" ++ */ ++ if (!is_dir) { ++ errno = ENOENT; ++ return (NULL); ++ } ++ if (resolved_len > 1) { ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ continue; ++ } ++ ++ /* ++ * Append the next path component and lstat() it. If ++ * lstat() fails we still can return successfully if ++ * there are no more path components left. ++ */ ++ resolved_len = strlcat(resolved, next_token, PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ if (lstat(resolved, &sb) != 0) { ++ if (errno == ENOENT && p == NULL) { ++ errno = serrno; ++ return (resolved); ++ } ++ return (NULL); ++ } ++ if (S_ISLNK(sb.st_mode)) { ++ if (symlinks++ > MAXSYMLINKS) { ++ errno = ELOOP; ++ return (NULL); ++ } ++ slen = readlink(resolved, symlink, sizeof(symlink) - 1); ++ if (slen < 0) ++ return (NULL); ++ symlink[slen] = '\0'; ++ if (symlink[0] == '/') { ++ resolved[1] = 0; ++ resolved_len = 1; ++ } else if (resolved_len > 1) { ++ /* Strip the last path component. */ ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ ++ /* ++ * If there are any path components left, then ++ * append them to symlink. The result is placed ++ * in `left'. ++ */ ++ if (p != NULL) { ++ if (symlink[slen - 1] != '/') { ++ if (slen + 1 >= sizeof(symlink)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ symlink[slen] = '/'; ++ symlink[slen + 1] = 0; ++ } ++ left_len = strlcat(symlink, left, sizeof(left)); ++ if (left_len >= sizeof(left)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ } ++ left_len = strlcpy(left, symlink, sizeof(left)); ++ } else { ++ if (S_ISDIR(sb.st_mode)) { ++ is_dir = 1; ++ } else { ++ is_dir = 0; ++ } ++ } ++ } ++ ++ /* ++ * Remove trailing slash except when the resolved pathname ++ * is a single "/". ++ */ ++ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') ++ resolved[resolved_len - 1] = '\0'; ++ return (resolved); ++} ++#endif ++ + CWD_API void virtual_cwd_startup(void) + { + char cwd[MAXPATHLEN]; +@@ -314,8 +473,7 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now +- return 1; */ ++ return 1; + } + } + } else { /* Concat current directory with relative path and then run realpath() on it */ +@@ -341,9 +499,8 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now + free(tmp); +- return 1; */ ++ return 1; + } + } + free(tmp); +@@ -852,7 +1009,7 @@ + dir_length = CWDG(cwd).cwd_length; + dir = CWDG(cwd).cwd; + +- ptr = command_line = (char *) malloc(command_length + sizeof("cd '' ; ") + dir_length +1+1); ++ ptr = command_line = (char *) malloc(command_length + sizeof("cd '' ; ") + dir_length +extra+1+1); + if (!command_line) { + return NULL; + } +diff -Nur php-4.3.10/TSRM/tsrm_virtual_cwd.h hardened-php-4.3.10-0.2.7/TSRM/tsrm_virtual_cwd.h +--- php-4.3.10/TSRM/tsrm_virtual_cwd.h 2003-09-20 04:08:12.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/TSRM/tsrm_virtual_cwd.h 2005-04-07 01:51:16.000000000 +0200 +@@ -128,6 +128,22 @@ + + typedef int (*verify_path_func)(const cwd_state *); + ++#ifndef HAVE_STRLCPY ++CWD_API size_t php_strlcpy(char *dst, const char *src, size_t siz); ++#undef strlcpy ++#define strlcpy php_strlcpy ++#endif ++ ++#ifndef HAVE_STRLCAT ++CWD_API size_t php_strlcat(char *dst, const char *src, size_t siz); ++#undef strlcat ++#define strlcat php_strlcat ++#endif ++ ++ ++#if HARDENED_PHP ++CWD_API char *php_realpath(const char *path, char *resolved); ++#endif + CWD_API void virtual_cwd_startup(void); + CWD_API void virtual_cwd_shutdown(void); + CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC); +diff -Nur php-4.3.10/Zend/zend.c hardened-php-4.3.10-0.2.7/Zend/zend.c +--- php-4.3.10/Zend/zend.c 2004-12-06 16:35:03.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/Zend/zend.c 2005-04-07 01:51:16.000000000 +0200 +@@ -53,6 +53,12 @@ + ZEND_API void (*zend_unblock_interruptions)(void); + ZEND_API void (*zend_ticks_function)(int ticks); + ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); ++#if HARDENED_PHP ++ZEND_API void (*zend_security_log)(char *str); ++#endif ++#if HARDENED_PHP_INC_PROTECT ++ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + + void (*zend_on_timeout)(int seconds TSRMLS_DC); + +@@ -424,6 +430,14 @@ + extern zend_scanner_globals language_scanner_globals; + #endif + ++ /* Set up Hardened-PHP utility functions first */ ++#if HARDENED_PHP ++ zend_security_log = utility_functions->security_log_function; ++#endif ++#if HARDENED_PHP_INC_PROTECT ++ zend_is_valid_include = utility_functions->is_valid_include; ++#endif ++ + #ifdef ZTS + ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); + #else +diff -Nur php-4.3.10/Zend/zend.h hardened-php-4.3.10-0.2.7/Zend/zend.h +--- php-4.3.10/Zend/zend.h 2004-07-28 21:06:48.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/Zend/zend.h 2005-04-07 01:51:16.000000000 +0200 +@@ -261,9 +261,9 @@ + struct _zval_struct { + /* Variable information */ + zvalue_value value; /* value */ ++ zend_uint refcount; + zend_uchar type; /* active type */ + zend_uchar is_ref; +- zend_ushort refcount; + }; + + +@@ -324,6 +324,12 @@ + void (*ticks_function)(int ticks); + void (*on_timeout)(int seconds TSRMLS_DC); + zend_bool (*open_function)(const char *filename, struct _zend_file_handle *); ++#if HARDENED_PHP ++ void (*security_log_function)(char *str); ++#endif ++#if HARDENED_PHP_INC_PROTECT ++ int (*is_valid_include)(zval *z); ++#endif + } zend_utility_functions; + + +@@ -455,7 +461,16 @@ + extern ZEND_API void (*zend_ticks_function)(int ticks); + extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); + extern void (*zend_on_timeout)(int seconds TSRMLS_DC); ++#if HARDENED_PHP ++extern ZEND_API void (*zend_security_log)(char *str); ++#endif ++#if HARDENED_PHP_INC_PROTECT ++extern ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + ++#if HARDENED_PHP_MM_PROTECT || HARDENED_PHP_LL_PROTECT || HARDENED_PHP_HASH_PROTECT ++ZEND_API unsigned int zend_canary(void); ++#endif + + ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 2, 3); + +@@ -574,6 +589,10 @@ + #define EMPTY_SWITCH_DEFAULT_CASE() + #endif + ++#if HARDENED_PHP ++#include "hardened_globals.h" ++#endif ++ + #endif /* ZEND_H */ + + /* +diff -Nur php-4.3.10/Zend/zend_alloc.c hardened-php-4.3.10-0.2.7/Zend/zend_alloc.c +--- php-4.3.10/Zend/zend_alloc.c 2004-08-27 18:51:25.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/Zend/zend_alloc.c 2005-04-07 01:51:16.000000000 +0200 +@@ -56,6 +56,11 @@ + # define END_MAGIC_SIZE 0 + #endif + ++#if HARDENED_PHP_MM_PROTECT ++# define CANARY_SIZE sizeof(unsigned int) ++#else ++# define CANARY_SIZE 0 ++#endif + + # if MEMORY_LIMIT + # if ZEND_DEBUG +@@ -95,9 +100,17 @@ + if (p==AG(head)) { \ + AG(head) = p->pNext; \ + } else { \ ++ if (p != p->pLast->pNext) { \ ++ zend_security_log("linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pLast->pNext = p->pNext; \ + } \ + if (p->pNext) { \ ++ if (p != p->pNext->pLast) { \ ++ zend_security_log("linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pNext->pLast = p->pLast; \ + } + +@@ -129,6 +142,12 @@ + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENED_PHP_MM_PROTECT ++ if (size > LONG_MAX - sizeof(zend_mem_header) - MEM_HEADER_PADDING - END_MAGIC_SIZE - CANARY_SIZE) { ++ zend_security_log("emalloc() - requested size would result in integer overflow"); ++ exit(1); ++ } ++#endif + CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size); + + if (!ZEND_DISABLE_MEMORY_CACHE && (CACHE_INDEX < MAX_CACHED_MEMORY) && (AG(cache_count)[CACHE_INDEX] > 0)) { +@@ -146,6 +165,10 @@ + AG(cache_stats)[CACHE_INDEX][1]++; + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif ++#if HARDENED_PHP_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->cached = 0; + p->size = size; + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); +@@ -161,7 +184,7 @@ + AG(allocated_memory_peak) = AG(allocated_memory); + } + #endif +- p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE + CANARY_SIZE); + } + + HANDLE_BLOCK_INTERRUPTIONS(); +@@ -191,7 +214,10 @@ + # endif + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif +- ++#if HARDENED_PHP_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); + } +@@ -218,17 +244,33 @@ + return emalloc_rel(lval + offset); + } + } +- ++ ++#if HARDENED_PHP ++ zend_security_log("Possible integer overflow catched by safe_emalloc()"); ++#endif + zend_error(E_ERROR, "Possible integer overflow in memory allocation (%ld * %ld + %ld)", nmemb, size, offset); + return 0; + } + + ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENED_PHP_MM_PROTECT ++ unsigned int *canary_2; ++#endif + zend_mem_header *p = (zend_mem_header *) ((char *)ptr - sizeof(zend_mem_header) - MEM_HEADER_PADDING); + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENED_PHP_MM_PROTECT ++ canary_2 = (unsigned int *)(((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE); ++ if (p->canary != HG(canary_1) || *canary_2 != HG(canary_2)) { ++ zend_security_log("canary mismatch on efree() - heap overflow or double efree detected"); ++ exit(1); ++ } ++ /* to catch double efree()s */ ++ *canary_2 = p->canary = 0; ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + tsrm_error(TSRM_ERROR_LEVEL_ERROR, "Memory block allocated at %s:(%d) on thread %x freed at %s:(%d) on thread %x, ignoring", +@@ -273,6 +315,9 @@ + size_t _size = nmemb * size; + + if (nmemb && (_size/nmemb!=size)) { ++#if HARDENED_PHP ++ zend_security_log("Possible integer overflow catched by ecalloc()"); ++#endif + fprintf(stderr,"FATAL: ecalloc(): Unable to allocate %ld * %ld bytes\n", (long) nmemb, (long) size); + #if ZEND_DEBUG && HAVE_KILL && HAVE_GETPID + kill(getpid(), SIGSEGV); +@@ -292,6 +337,9 @@ + + ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENED_PHP_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p; + zend_mem_header *orig; + DECLARE_CACHE_VARS(); +@@ -303,6 +351,14 @@ + + p = orig = (zend_mem_header *) ((char *)ptr-sizeof(zend_mem_header)-MEM_HEADER_PADDING); + ++#if HARDENED_PHP_MM_PROTECT ++ canary_2 = *(unsigned int *)(((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE); ++ if (p->canary != HG(canary_1) || canary_2 != HG(canary_2)) { ++ zend_security_log("canary mismatch on erealloc() - heap overflow detected"); ++ exit(1); ++ } ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + void *new_p; +@@ -326,7 +382,7 @@ + } + #endif + REMOVE_POINTER_FROM_LIST(p); +- p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE+CANARY_SIZE); + if (!p) { + if (!allow_failure) { + fprintf(stderr,"FATAL: erealloc(): Unable to allocate %ld bytes\n", (long) size); +@@ -348,6 +404,9 @@ + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif + ++#if HARDENED_PHP_MM_PROTECT ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->size = size; + + HANDLE_UNBLOCK_INTERRUPTIONS(); +@@ -423,6 +482,10 @@ + { + AG(head) = NULL; + ++#if HARDENED_PHP_MM_PROTECT ++ HG(canary_1) = zend_canary(); ++ HG(canary_2) = zend_canary(); ++#endif + #if MEMORY_LIMIT + AG(memory_limit) = 1<<30; /* ridiculous limit, effectively no limit */ + AG(allocated_memory) = 0; +diff -Nur php-4.3.10/Zend/zend_alloc.h hardened-php-4.3.10-0.2.7/Zend/zend_alloc.h +--- php-4.3.10/Zend/zend_alloc.h 2004-08-11 08:10:46.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/Zend/zend_alloc.h 2005-04-07 01:51:16.000000000 +0200 +@@ -32,6 +32,9 @@ + #define MEM_BLOCK_CACHED_MAGIC 0xFB8277DCL + + typedef struct _zend_mem_header { ++#if HARDENED_PHP_MM_PROTECT ++ unsigned int canary; ++#endif + #if ZEND_DEBUG + long magic; + char *filename; +diff -Nur php-4.3.10/Zend/zend_builtin_functions.c hardened-php-4.3.10-0.2.7/Zend/zend_builtin_functions.c +--- php-4.3.10/Zend/zend_builtin_functions.c 2004-04-01 21:05:01.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/Zend/zend_builtin_functions.c 2005-04-07 01:51:16.000000000 +0200 +@@ -49,6 +49,9 @@ + static ZEND_FUNCTION(crash); + #endif + #endif ++#if HARDENED_PHP_MM_PROTECT_DEBUG ++static ZEND_FUNCTION(heap_overflow); ++#endif + static ZEND_FUNCTION(get_included_files); + static ZEND_FUNCTION(is_subclass_of); + static ZEND_FUNCTION(is_a); +@@ -101,6 +104,9 @@ + ZEND_FE(crash, NULL) + #endif + #endif ++#if HARDENED_PHP_MM_PROTECT_DEBUG ++ ZEND_FE(heap_overflow, NULL) ++#endif + ZEND_FE(get_included_files, NULL) + ZEND_FALIAS(get_required_files, get_included_files, NULL) + ZEND_FE(is_subclass_of, NULL) +@@ -805,6 +811,19 @@ + + #endif /* ZEND_DEBUG */ + ++ ++#if HARDENED_PHP_MM_PROTECT_DEBUG ++ZEND_FUNCTION(heap_overflow) ++{ ++ char *nowhere = emalloc(10); ++ ++ memcpy(nowhere, "something1234567890", sizeof("something1234567890")); ++ ++ efree(nowhere); ++} ++#endif ++ ++ + /* {{{ proto array get_included_files(void) + Returns an array with the file names that were include_once()'d */ + ZEND_FUNCTION(get_included_files) +diff -Nur php-4.3.10/Zend/zend_canary.c hardened-php-4.3.10-0.2.7/Zend/zend_canary.c +--- php-4.3.10/Zend/zend_canary.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/Zend/zend_canary.c 2005-04-07 01:51:16.000000000 +0200 +@@ -0,0 +1,58 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: zend_canary.c,v 1.1 2004/11/26 12:45:41 ionic Exp $ */ ++ ++#include "zend.h" ++ ++#include ++#include ++ ++ ++#if HARDENED_PHP_MM_PROTECT || HARDENED_PHP_LL_PROTECT ++ ++/* will be replaced later with more compatible method */ ++ZEND_API unsigned int zend_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nur php-4.3.10/Zend/zend_execute.c hardened-php-4.3.10-0.2.7/Zend/zend_execute.c +--- php-4.3.10/Zend/zend_execute.c 2004-11-03 12:23:59.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/Zend/zend_execute.c 2005-04-07 01:51:16.000000000 +0200 +@@ -2149,7 +2149,12 @@ + int dummy = 1; + zend_file_handle file_handle = {0}; + ++#if HARDENED_PHP_INC_PROTECT ++ if (zend_is_valid_include(inc_filename) ++ && zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#else + if (zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#endif + && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) { + + file_handle.filename = inc_filename->value.str.val; +@@ -2178,6 +2183,11 @@ + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: ++#if HARDENED_PHP_INC_PROTECT ++ if (!zend_is_valid_include(inc_filename)) { ++ break; ++ } ++#endif + new_op_array = compile_filename(EX(opline)->op2.u.constant.value.lval, inc_filename TSRMLS_CC); + break; + case ZEND_EVAL: { +diff -Nur php-4.3.10/Zend/zend_extensions.h hardened-php-4.3.10-0.2.7/Zend/zend_extensions.h +--- php-4.3.10/Zend/zend_extensions.h 2002-12-31 17:23:02.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/Zend/zend_extensions.h 2005-04-07 01:51:16.000000000 +0200 +@@ -23,7 +23,9 @@ + + #include "zend_compile.h" + +-#define ZEND_EXTENSION_API_NO 20021010 ++/* Create own API version number for Hardened-PHP */ ++ ++#define ZEND_EXTENSION_API_NO 1020041222 + + typedef struct _zend_extension_version_info { + int zend_extension_api_no; +diff -Nur php-4.3.10/Zend/zend_hash.c hardened-php-4.3.10-0.2.7/Zend/zend_hash.c +--- php-4.3.10/Zend/zend_hash.c 2004-07-12 23:26:46.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/Zend/zend_hash.c 2005-04-07 01:51:16.000000000 +0200 +@@ -26,6 +26,17 @@ + # include + #endif + ++#if HARDENED_PHP_HASH_PROTECT ++ unsigned int zend_hash_canary = 0x1234567; ++ zend_bool zend_hash_canary_inited = 0; ++#endif ++ ++#define CHECK_HASH_CANARY(hash) \ ++ if (zend_hash_canary != (hash)->canary) { \ ++ zend_security_log("Zend HashTable canary was overwritten"); \ ++ exit(1); \ ++ } ++ + #define HANDLE_NUMERIC(key, length, func) { \ + register char *tmp=key; \ + \ +@@ -175,6 +186,9 @@ + { + uint i = 3; + Bucket **tmp; ++#if HARDENED_PHP_HASH_PROTECT ++ TSRMLS_FETCH(); ++#endif + + SET_INCONSISTENT(HT_OK); + +@@ -184,6 +198,13 @@ + + ht->nTableSize = 1 << i; + ht->nTableMask = ht->nTableSize - 1; ++#if HARDENED_PHP_HASH_PROTECT ++ if (zend_hash_canary_inited==0) { ++ zend_hash_canary = zend_canary(); ++ zend_hash_canary_inited = 1; ++ } ++ ht->canary = zend_hash_canary; ++#endif + ht->pDestructor = pDestructor; + ht->pListHead = NULL; + ht->pListTail = NULL; +@@ -259,6 +280,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -327,6 +351,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -402,6 +429,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -450,7 +480,7 @@ + IS_CONSISTENT(ht); + + if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */ +- t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); ++ t = (Bucket **) perealloc(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); + if (t) { + HANDLE_BLOCK_INTERRUPTIONS(); + ht->arBuckets = t; +@@ -460,6 +490,7 @@ + HANDLE_UNBLOCK_INTERRUPTIONS(); + return SUCCESS; + } ++ zend_error(E_ERROR, "zend_hash_do_resize - out of memory"); + return FAILURE; + } + return SUCCESS; +@@ -524,6 +555,9 @@ + ht->pInternalPointer = p->pListNext; + } + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +@@ -553,6 +587,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -579,6 +616,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -608,6 +648,9 @@ + HANDLE_BLOCK_INTERRUPTIONS(); + + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +diff -Nur php-4.3.10/Zend/zend_hash.h hardened-php-4.3.10-0.2.7/Zend/zend_hash.h +--- php-4.3.10/Zend/zend_hash.h 2002-12-31 17:23:03.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/Zend/zend_hash.h 2005-04-07 01:51:16.000000000 +0200 +@@ -54,6 +54,9 @@ + } Bucket; + + typedef struct _hashtable { ++#if HARDENED_PHP_HASH_PROTECT ++ unsigned int canary; ++#endif + uint nTableSize; + uint nTableMask; + uint nNumOfElements; +diff -Nur php-4.3.10/Zend/zend_llist.c hardened-php-4.3.10-0.2.7/Zend/zend_llist.c +--- php-4.3.10/Zend/zend_llist.c 2002-12-31 17:23:04.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/Zend/zend_llist.c 2005-04-07 01:51:16.000000000 +0200 +@@ -21,9 +21,34 @@ + #include "zend.h" + #include "zend_llist.h" + #include "zend_qsort.h" ++#include "zend_globals.h" ++ ++#define CHECK_LIST_CANARY(list) \ ++ if (HG(canary_3) != (list)->canary_h || HG(canary_4) != (list)->canary_t) { \ ++ zend_security_log("linked list canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++#define CHECK_LISTELEMENT_CANARY(elem) \ ++ if (HG(canary_3) != (elem)->canary) { \ ++ zend_security_log("linked list element canary was overwritten"); \ ++ exit(1); \ ++ } ++ + + ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent) + { ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ ++ if (!HG(ll_canary_inited)) { ++ HG(canary_3) = zend_canary(); ++ HG(canary_4) = zend_canary(); ++ HG(ll_canary_inited) = 1; ++ } ++ l->canary_h = HG(canary_3); ++ l->canary_t = HG(canary_4); ++#endif + l->head = NULL; + l->tail = NULL; + l->count = 0; +@@ -37,6 +62,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->prev = l->tail; + tmp->next = NULL; + if (l->tail) { +@@ -55,6 +85,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->next = l->head; + tmp->prev = NULL; + if (l->head) { +@@ -91,10 +126,20 @@ + zend_llist_element *current=l->head; + zend_llist_element *next; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (compare(current->data, element)) { + DEL_LLIST_ELEMENT(current, l); ++#if HARDENED_PHP_LL_PROTECT ++ current->canary = 0; ++#endif + break; + } + current = next; +@@ -106,7 +151,14 @@ + { + zend_llist_element *current=l->head, *next; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (l->dtor) { + l->dtor(current->data); +@@ -131,7 +183,14 @@ + zend_llist_element *old_tail; + void *data; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if ((old_tail = l->tail)) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(old_tail) ++#endif + if (l->tail->prev) { + l->tail->prev->next = NULL; + } +@@ -157,9 +216,16 @@ + { + zend_llist_element *ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(src) ++#endif + zend_llist_init(dst, src->size, src->dtor, src->persistent); + ptr = src->head; + while (ptr) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(ptr) ++#endif + zend_llist_add_element(dst, ptr->data); + ptr = ptr->next; + } +@@ -170,11 +236,21 @@ + { + zend_llist_element *element, *next; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + element=l->head; + while (element) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + next = element->next; + if (func(element->data)) { + DEL_LLIST_ELEMENT(element, l); ++#if HARDENED_PHP_LL_PROTECT ++ element->canary = 0; ++#endif + } + element = next; + } +@@ -185,7 +261,13 @@ + { + zend_llist_element *element; + ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data TSRMLS_CC); + } + } +@@ -197,6 +279,9 @@ + zend_llist_element **elements; + zend_llist_element *element, **ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + if (l->count <= 0) { + return; + } +@@ -206,6 +291,9 @@ + ptr = &elements[0]; + + for (element=l->head; element; element=element->next) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + *ptr++ = element; + } + +@@ -228,7 +316,13 @@ + { + zend_llist_element *element; + ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, arg TSRMLS_CC); + } + } +@@ -239,8 +333,14 @@ + zend_llist_element *element; + va_list args; + ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + va_start(args, num_args); + for (element=l->head; element; element=element->next) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, num_args, args TSRMLS_CC); + } + va_end(args); +@@ -249,6 +349,10 @@ + + ZEND_API int zend_llist_count(zend_llist *l) + { ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + return l->count; + } + +@@ -256,8 +360,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->head; + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -269,8 +380,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->tail; + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -282,9 +400,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->next; + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +@@ -296,9 +424,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->prev; + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +diff -Nur php-4.3.10/Zend/zend_llist.h hardened-php-4.3.10-0.2.7/Zend/zend_llist.h +--- php-4.3.10/Zend/zend_llist.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/Zend/zend_llist.h 2005-04-07 01:51:16.000000000 +0200 +@@ -24,6 +24,9 @@ + #include + + typedef struct _zend_llist_element { ++#if HARDENED_PHP_LL_PROTECT ++ unsigned int canary; ++#endif + struct _zend_llist_element *next; + struct _zend_llist_element *prev; + char data[1]; /* Needs to always be last in the struct */ +@@ -36,6 +39,9 @@ + typedef void (*llist_apply_func_t)(void * TSRMLS_DC); + + typedef struct _zend_llist { ++#if HARDENED_PHP_LL_PROTECT ++ unsigned int canary_h; /* head */ ++#endif + zend_llist_element *head; + zend_llist_element *tail; + size_t size; +@@ -43,6 +49,9 @@ + llist_dtor_func_t dtor; + unsigned char persistent; + zend_llist_element *traverse_ptr; ++#if HARDENED_PHP_LL_PROTECT ++ unsigned int canary_t; /* tail */ ++#endif + } zend_llist; + + typedef zend_llist_element* zend_llist_position; +diff -Nur php-4.3.10/Zend/zend_modules.h hardened-php-4.3.10-0.2.7/Zend/zend_modules.h +--- php-4.3.10/Zend/zend_modules.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/Zend/zend_modules.h 2005-04-07 01:51:16.000000000 +0200 +@@ -34,7 +34,7 @@ + ZEND_API extern unsigned char second_arg_force_ref[]; + ZEND_API extern unsigned char third_arg_force_ref[]; + +-#define ZEND_MODULE_API_NO 20020429 ++#define ZEND_MODULE_API_NO 1020041222 + #ifdef ZTS + #define USING_ZTS 1 + #else +diff -Nur php-4.3.10/acinclude.m4 hardened-php-4.3.10-0.2.7/acinclude.m4 +--- php-4.3.10/acinclude.m4 2004-12-11 12:17:21.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/acinclude.m4 2005-04-07 01:51:16.000000000 +0200 +@@ -1153,6 +1153,36 @@ + fi + ]) + ++dnl ++dnl Check for broken realpath() ++dnl ++dnl realpath("/etc/hosts/../passwd",XXX) should not return ++dnl "/etc/passwd" ++dnl ++AC_DEFUN([PHP_AC_BROKEN_REALPATH],[ ++ AC_CACHE_CHECK(whether realpath is broken, ac_cv_broken_realpath,[ ++ AC_TRY_RUN([ ++main() { ++ char buf[4096+1]; ++ buf[0] = 0; ++ realpath("/etc/hosts/../passwd", buf); ++ exit(strcmp(buf, "/etc/passwd")==0); ++} ++ ],[ ++ ac_cv_broken_realpath=no ++ ],[ ++ ac_cv_broken_realpath=yes ++ ],[ ++ ac_cv_broken_realpath=no ++ ]) ++ ]) ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ AC_DEFINE(PHP_BROKEN_REALPATH, 1, [Whether realpath is broken]) ++ else ++ AC_DEFINE(PHP_BROKEN_REALPATH, 0, [Whether realpath is broken]) ++ fi ++]) ++ + dnl PHP_SHARED_MODULE(module-name, object-var, build-dir, cxx) + dnl + dnl Basically sets up the link-stage for building module-name +diff -Nur php-4.3.10/configure hardened-php-4.3.10-0.2.7/configure +--- php-4.3.10/configure 2004-12-14 18:55:18.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/configure 2005-04-07 01:51:16.000000000 +0200 +@@ -389,6 +389,16 @@ + ac_default_prefix=/usr/local + # Any additions from configure.in: + ac_help="$ac_help ++ --disable-hardened-php-mm-protect Disable the Memory Manager protection." ++ac_help="$ac_help ++ --disable-hardened-php-ll-protect Disable the Linked List protection." ++ac_help="$ac_help ++ --disable-hardened-php-inc-protect Disable include/require protection." ++ac_help="$ac_help ++ --disable-hardened-php-fmt-protect Disable format string protection." ++ac_help="$ac_help ++ --disable-hardened-php-hash-protect Disable Zend HashTable DTOR protection." ++ac_help="$ac_help + + SAPI modules: + " +@@ -831,6 +841,8 @@ + ac_help="$ac_help + --disable-tokenizer Disable tokenizer support" + ac_help="$ac_help ++ --disable-varfilter Disable Hardened-PHP's variable filter" ++ac_help="$ac_help + --enable-wddx Enable WDDX support." + ac_help="$ac_help + --disable-xml Disable XML support using bundled expat lib" +@@ -2643,6 +2655,157 @@ + + + ++# Check whether --enable-hardened-php-mm-protect or --disable-hardened-php-mm-protect was given. ++if test "${enable_hardened_php_mm_protect+set}" = set; then ++ enableval="$enable_hardened_php_mm_protect" ++ ++ DO_HARDENED_PHP_MM_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_MM_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardened-php-ll-protect or --disable-hardened-php-ll-protect was given. ++if test "${enable_hardened_php_ll_protect+set}" = set; then ++ enableval="$enable_hardened_php_ll_protect" ++ ++ DO_HARDENED_PHP_LL_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_LL_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardened-php-inc-protect or --disable-hardened-php-inc-protect was given. ++if test "${enable_hardened_php_inc_protect+set}" = set; then ++ enableval="$enable_hardened_php_inc_protect" ++ ++ DO_HARDENED_PHP_INC_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_INC_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardened-php-fmt-protect or --disable-hardened-php-fmt-protect was given. ++if test "${enable_hardened_php_fmt_protect+set}" = set; then ++ enableval="$enable_hardened_php_fmt_protect" ++ ++ DO_HARDENED_PHP_FMT_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_FMT_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardened-php-hash-protect or --disable-hardened-php-hash-protect was given. ++if test "${enable_hardened_php_hash_protect+set}" = set; then ++ enableval="$enable_hardened_php_hash_protect" ++ ++ DO_HARDENED_PHP_HASH_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_HASH_PROTECT=yes ++ ++fi ++ ++ ++echo $ac_n "checking whether to protect the Zend Memory Manager""... $ac_c" 1>&6 ++echo "configure:2725: checking whether to protect the Zend Memory Manager" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_MM_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend Linked Lists""... $ac_c" 1>&6 ++echo "configure:2729: checking whether to protect the Zend Linked Lists" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_LL_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect include/require statements""... $ac_c" 1>&6 ++echo "configure:2733: checking whether to protect include/require statements" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_INC_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect PHP Format String functions""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect PHP Format String functions" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_FMT_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend HashTable Destructors""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect the Zend HashTable Destructors" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_HASH_PROTECT" 1>&6 ++ ++ ++cat >> confdefs.h <<\EOF ++#define HARDENED_PHP 1 ++EOF ++ ++ ++ ++if test "$DO_HARDENED_PHP_MM_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_MM_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_MM_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENED_PHP_LL_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_LL_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_LL_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENED_PHP_INC_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_INC_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_INC_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENED_PHP_FMT_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_FMT_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_FMT_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENED_PHP_HASH_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_HASH_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_HASH_PROTECT 0 ++EOF ++ ++fi + + + +@@ -14890,6 +15053,62 @@ + fi + + ++ echo $ac_n "checking whether realpath is broken""... $ac_c" 1>&6 ++echo "configure:14928: checking whether realpath is broken" >&5 ++if eval "test \"`echo '$''{'ac_cv_broken_realpath'+set}'`\" = set"; then ++ echo $ac_n "(cached) $ac_c" 1>&6 ++else ++ ++ if test "$cross_compiling" = yes; then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null ++then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ echo "configure: failed program was:" >&5 ++ cat conftest.$ac_ext >&5 ++ rm -fr conftest* ++ ++ ac_cv_broken_realpath=yes ++ ++fi ++rm -fr conftest* ++fi ++ ++ ++fi ++ ++echo "$ac_t""$ac_cv_broken_realpath" 1>&6 ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 1 ++EOF ++ ++ else ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 0 ++EOF ++ ++ fi ++ ++ + echo $ac_n "checking for declared timezone""... $ac_c" 1>&6 + echo "configure:14895: checking for declared timezone" >&5 + if eval "test \"`echo '$''{'ac_cv_declared_timezone'+set}'`\" = set"; then +@@ -82014,6 +82233,265 @@ + fi + + ++echo $ac_n "checking whether to enable Hardened-PHP's variable filter""... $ac_c" 1>&6 ++echo "configure:82041: checking whether to enable Hardened-PHP's variable filter" >&5 ++# Check whether --enable-varfilter or --disable-varfilter was given. ++if test "${enable_varfilter+set}" = set; then ++ enableval="$enable_varfilter" ++ PHP_VARFILTER=$enableval ++else ++ ++ PHP_VARFILTER=yes ++ ++ if test "$PHP_ENABLE_ALL" && test "yes" = "yes"; then ++ PHP_VARFILTER=$PHP_ENABLE_ALL ++ fi ++ ++fi ++ ++ ++ ++ext_output="yes, shared" ++ext_shared=yes ++case $PHP_VARFILTER in ++shared,*) ++ PHP_VARFILTER=`echo "$PHP_VARFILTER"|sed 's/^shared,//'` ++ ;; ++shared) ++ PHP_VARFILTER=yes ++ ;; ++no) ++ ext_output=no ++ ext_shared=no ++ ;; ++*) ++ ext_output=yes ++ ext_shared=no ++ ;; ++esac ++ ++ ++ ++echo "$ac_t""$ext_output" 1>&6 ++ ++ ++ ++ ++if test "$PHP_VARFILTER" != "no"; then ++ cat >> confdefs.h <<\EOF ++#define HAVE_VARFILTER 1 ++EOF ++ ++ ++ ext_builddir=ext/varfilter ++ ext_srcdir=$abs_srcdir/ext/varfilter ++ ++ ac_extra= ++ ++ if test "$ext_shared" != "shared" && test "$ext_shared" != "yes" && test "" != "cli"; then ++ ++ ++ ++ case ext/varfilter in ++ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;; ++ /*) ac_srcdir=`echo "ext/varfilter"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;; ++ *) ac_srcdir="$abs_srcdir/ext/varfilter/"; ac_bdir="ext/varfilter/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;; ++ esac ++ ++ ++ ++ b_c_pre=$php_c_pre ++ b_cxx_pre=$php_cxx_pre ++ b_c_meta=$php_c_meta ++ b_cxx_meta=$php_cxx_meta ++ b_c_post=$php_c_post ++ b_cxx_post=$php_cxx_post ++ b_lo=$php_lo ++ ++ ++ old_IFS=$IFS ++ for ac_src in varfilter.c; do ++ ++ IFS=. ++ set $ac_src ++ ac_obj=$1 ++ IFS=$old_IFS ++ ++ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo" ++ ++ case $ac_src in ++ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;; ++ *.cpp) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;; ++ esac ++ ++ cat >>Makefile.objects<>Makefile.objects<>Makefile.objects<> confdefs.h <>Makefile.objects<>Makefile.objects<&6 +@@ -94503,7 +94981,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c; do ++ output.c memory_streams.c user_streams.c hardened_php.c; do + + IFS=. + set $ac_src +@@ -94676,7 +95154,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c; do ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c; do + + IFS=. + set $ac_src +diff -Nur php-4.3.10/configure.in hardened-php-4.3.10-0.2.7/configure.in +--- php-4.3.10/configure.in 2004-12-14 17:07:49.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/configure.in 2005-04-07 01:51:16.000000000 +0200 +@@ -205,7 +205,7 @@ + sinclude(Zend/acinclude.m4) + sinclude(Zend/Zend.m4) + sinclude(TSRM/tsrm.m4) +- ++sinclude(main/hardened_php.m4) + + + divert(2) +@@ -573,6 +573,7 @@ + AC_FUNC_ALLOCA + dnl PHP_AC_BROKEN_SPRINTF + dnl PHP_AC_BROKEN_SNPRINTF ++PHP_AC_BROKEN_REALPATH + PHP_DECLARED_TIMEZONE + PHP_TIME_R_TYPE + PHP_READDIR_R_TYPE +@@ -1201,7 +1202,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c) ++ output.c memory_streams.c user_streams.c hardened_php.c) + PHP_ADD_SOURCES(/main, internal_functions.c,, sapi) + PHP_ADD_SOURCES(/main, internal_functions_cli.c,, cli) + +@@ -1214,7 +1215,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c) ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c ) + + if test -r "$abs_srcdir/Zend/zend_objects.c"; then + PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_mm.c) +diff -Nur php-4.3.10/ext/curl/curl.c hardened-php-4.3.10-0.2.7/ext/curl/curl.c +--- php-4.3.10/ext/curl/curl.c 2004-11-01 05:56:10.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/curl/curl.c 2005-04-07 01:51:16.000000000 +0200 +@@ -16,7 +16,7 @@ + +----------------------------------------------------------------------+ + */ + +-/* $Id: curl.c,v 1.124.2.27 2004/11/01 04:56:10 iliaa Exp $ */ ++/* $Id: curl.c,v 1.124.2.29 2005/03/14 09:03:09 sniper Exp $ */ + + #ifdef HAVE_CONFIG_H + #include "config.h" +@@ -50,6 +50,7 @@ + #include "ext/standard/php_smart_str.h" + #include "ext/standard/info.h" + #include "ext/standard/file.h" ++#include "ext/standard/url.h" + #include "php_curl.h" + + static int le_curl; +@@ -64,6 +65,26 @@ + #define CAAS(s, v) add_assoc_string_ex(return_value, s, sizeof(s), (char *) v, 1); + #define CAAZ(s, v) add_assoc_zval_ex(return_value, s, sizeof(s), (zval *) v); + ++#define PHP_CURL_CHECK_OPEN_BASEDIR(str, len) \ ++ if (PG(open_basedir) && *PG(open_basedir) && \ ++ strncasecmp(str, "file://", sizeof("file://") - 1) == 0) \ ++ { \ ++ php_url *tmp_url; \ ++ \ ++ if (!(tmp_url = php_url_parse_ex(str, len))) { \ ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid url '%s'", str); \ ++ RETURN_FALSE; \ ++ } \ ++ \ ++ if (php_check_open_basedir(tmp_url->path TSRMLS_CC) || \ ++ (PG(safe_mode) && !php_checkuid(tmp_url->path, "rb+", CHECKUID_CHECK_MODE_PARAM)) \ ++ ) { \ ++ php_url_free(tmp_url); \ ++ RETURN_FALSE; \ ++ } \ ++ php_url_free(tmp_url); \ ++ } ++ + /* {{{ curl_functions[] + */ + function_entry curl_functions[] = { +@@ -682,6 +703,11 @@ + WRONG_PARAM_COUNT; + } + ++ if (argc > 0) { ++ convert_to_string_ex(url); ++ PHP_CURL_CHECK_OPEN_BASEDIR(Z_STRVAL_PP(url), Z_STRLEN_PP(url)); ++ } ++ + alloc_curl_handle(&ch); + + ch->cp = curl_easy_init(); +@@ -712,7 +738,6 @@ + + if (argc > 0) { + char *urlcopy; +- convert_to_string_ex(url); + + urlcopy = estrndup(Z_STRVAL_PP(url), Z_STRLEN_PP(url)); + curl_easy_setopt(ch->cp, CURLOPT_URL, urlcopy); +@@ -724,7 +749,7 @@ + } + /* }}} */ + +-/* {{{ proto bool curl_setopt(resource ch, string option, mixed value) ++/* {{{ proto bool curl_setopt(resource ch, int option, mixed value) + Set an option for a CURL transfer */ + PHP_FUNCTION(curl_setopt) + { +@@ -819,8 +844,12 @@ + char *copystr = NULL; + + convert_to_string_ex(zvalue); +- copystr = estrndup(Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue)); + ++ if (option == CURLOPT_URL) { ++ PHP_CURL_CHECK_OPEN_BASEDIR(Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue)); ++ } ++ ++ copystr = estrndup(Z_STRVAL_PP(zvalue), Z_STRLEN_PP(zvalue)); + error = curl_easy_setopt(ch->cp, option, copystr); + zend_llist_add_element(&ch->to_free.str, ©str); + +@@ -955,16 +984,16 @@ + if (*postval == '@') { + error = curl_formadd(&first, &last, + CURLFORM_COPYNAME, string_key, +- CURLFORM_NAMELENGTH, string_key_len - 1, ++ CURLFORM_NAMELENGTH, (long)string_key_len - 1, + CURLFORM_FILE, ++postval, + CURLFORM_END); + } + else { + error = curl_formadd(&first, &last, + CURLFORM_COPYNAME, string_key, +- CURLFORM_NAMELENGTH, string_key_len - 1, ++ CURLFORM_NAMELENGTH, (long)string_key_len - 1, + CURLFORM_COPYCONTENTS, postval, +- CURLFORM_CONTENTSLENGTH, Z_STRLEN_PP(current), ++ CURLFORM_CONTENTSLENGTH, (long)Z_STRLEN_PP(current), + CURLFORM_END); + } + } +diff -Nur php-4.3.10/ext/exif/exif.c hardened-php-4.3.10-0.2.7/ext/exif/exif.c +--- php-4.3.10/ext/exif/exif.c 2004-11-10 02:44:58.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/exif/exif.c 2005-04-07 01:51:16.000000000 +0200 +@@ -17,7 +17,7 @@ + +----------------------------------------------------------------------+ + */ + +-/* $Id: exif.c,v 1.118.2.29 2004/11/10 01:44:58 iliaa Exp $ */ ++/* $Id: exif.c,v 1.118.2.37 2005/03/22 22:07:03 edink Exp $ */ + + /* ToDos + * +@@ -58,7 +58,7 @@ + #include "ext/standard/php_image.h" + #include "ext/standard/info.h" + +-#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) ++#if defined(PHP_WIN32) || (HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)) + #define EXIF_USE_MBSTRING 1 + #else + #define EXIF_USE_MBSTRING 0 +@@ -68,6 +68,12 @@ + #include "ext/mbstring/mbstring.h" + #endif + ++/* needed for ssize_t definition */ ++#include ++#if defined(PHP_WIN32) && !defined(ssize_t) ++typedef SSIZE_T ssize_t; ++#endif ++ + typedef unsigned char uchar; + + #ifndef safe_emalloc +@@ -85,6 +91,8 @@ + + #define EFREE_IF(ptr) if (ptr) efree(ptr) + ++#define MAX_IFD_NESTING_LEVEL 100 ++ + static unsigned char exif_thumbnail_force_ref[] = {2, BYREF_NONE, BYREF_FORCE_REST}; + + /* {{{ exif_functions[] +@@ -99,7 +107,7 @@ + }; + /* }}} */ + +-#define EXIF_VERSION "1.4 $Id: exif.c,v 1.118.2.29 2004/11/10 01:44:58 iliaa Exp $" ++#define EXIF_VERSION "1.4 $Id: exif.c,v 1.118.2.37 2005/03/22 22:07:03 edink Exp $" + + /* {{{ PHP_MINFO_FUNCTION + */ +@@ -1430,6 +1438,7 @@ + /* for parsing */ + int read_thumbnail; + int read_all; ++ int ifd_nesting_level; + /* internal */ + file_section_list file; + } image_info_type; +@@ -2689,6 +2698,13 @@ + size_t byte_count, offset_val, fpos, fgot; + xp_field_type *tmp_xp; + ++ /* Protect against corrupt headers */ ++ if (ImageInfo->ifd_nesting_level > MAX_IFD_NESTING_LEVEL) { ++ exif_error_docref("exif_read_data#error_ifd" TSRMLS_CC, ImageInfo, E_WARNING, "corrupt EXIF header: maximum directory nesting level reached"); ++ return FALSE; ++ } ++ ImageInfo->ifd_nesting_level++; ++ + tag = php_ifd_get16u(dir_entry, ImageInfo->motorola_intel); + format = php_ifd_get16u(dir_entry+2, ImageInfo->motorola_intel); + components = php_ifd_get32u(dir_entry+4, ImageInfo->motorola_intel); +@@ -2702,6 +2718,11 @@ + + byte_count = components * php_tiff_bytes_per_format[format]; + ++ if ((ssize_t)byte_count < 0) { ++ exif_error_docref("exif_read_data#error_ifd" TSRMLS_CC, ImageInfo, E_WARNING, "Process tag(x%04X=%s): Illegal byte_count(%ld)", tag, exif_get_tagname(tag, tagname, -12, tag_table TSRMLS_CC), byte_count); ++ return FALSE; ++ } ++ + if (byte_count > 4) { + offset_val = php_ifd_get32u(dir_entry+8, ImageInfo->motorola_intel); + /* If its bigger than 4 bytes, the dir entry contains an offset. */ +@@ -3372,7 +3393,7 @@ + return FALSE; + } + php_stream_read(ImageInfo->infile, (char*)(ImageInfo->file.list[sn].data+2), dir_size-2); +- /*exif_error_docref(NULL EXIFERR_CC, ImageInfo, E_NOTICE, "Dump: %s", exif_char_dump(ImageInfo->file.list[sn].data, dir_size, 0));*/ ++ /*exif_error_docref(NULL TSRMLS_CC, ImageInfo, E_NOTICE, "Dump: %s", exif_char_dump(ImageInfo->file.list[sn].data, dir_size, 0));*/ + next_offset = php_ifd_get32u(ImageInfo->file.list[sn].data + dir_size - 4, ImageInfo->motorola_intel); + #ifdef EXIF_DEBUG + exif_error_docref(NULL TSRMLS_CC, ImageInfo, E_NOTICE, "read from TIFF done, next offset x%04X", next_offset); +@@ -3713,6 +3734,8 @@ + } + } + ++ ImageInfo->ifd_nesting_level = 0; ++ + /* Scan the JPEG headers. */ + ret = exif_scan_FILE_header(ImageInfo TSRMLS_CC); + +diff -Nur php-4.3.10/ext/fbsql/php_fbsql.c hardened-php-4.3.10-0.2.7/ext/fbsql/php_fbsql.c +--- php-4.3.10/ext/fbsql/php_fbsql.c 2004-08-24 20:00:05.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/ext/fbsql/php_fbsql.c 2005-04-07 01:51:16.000000000 +0200 +@@ -16,7 +16,7 @@ + +----------------------------------------------------------------------+ + */ + +-/* $Id: php_fbsql.c,v 1.86.2.9 2004/08/24 18:00:05 fmk Exp $ */ ++/* $Id: php_fbsql.c,v 1.86.2.14 2005/02/09 19:33:32 fmk Exp $ */ + + /* TODO: + * +@@ -459,11 +459,11 @@ + + if (FB_SQL_G(allowPersistent)) + { +- sprintf(buf, "%ld", FB_SQL_G(persistentCount)); ++ snprintf(buf, sizeof(buf), "%ld", FB_SQL_G(persistentCount)); + php_info_print_table_row(2, "Active Persistent Links", buf); + } + +- sprintf(buf, "%ld", FB_SQL_G(linkCount)); ++ snprintf(buf, sizeof(buf), "%ld", FB_SQL_G(linkCount)); + php_info_print_table_row(2, "Active Links", buf); + + /* +@@ -507,7 +507,9 @@ + if (userName == NULL) userName = FB_SQL_G(userName); + if (userPassword == NULL) userPassword = FB_SQL_G(userPassword); + +- sprintf(name, "fbsql_%s_%s_%s", hostName, userName, userPassword); ++ if (snprintf(name, sizeof(name), "fbsql_%s_%s_%s", hostName, userName, userPassword) < 0) { ++ RETURN_FALSE; ++ } + + if (!FB_SQL_G(allowPersistent)) { + persistent=0; +@@ -818,9 +820,21 @@ + WRONG_PARAM_COUNT; + break; + } ++ ++ if (Z_LVAL_PP(Locking) < 0 || Z_LVAL_PP(Locking) > 2) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid locking type."); ++ RETURN_FALSE; ++ } ++ if (Z_LVAL_PP(Isolation) < 0 || Z_LVAL_PP(Isolation) > 4) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid isolation type."); ++ RETURN_FALSE; ++ } ++ + ZEND_FETCH_RESOURCE2(phpLink, PHPFBLink *, fbsql_link_index, -1, "FrontBase-Link", le_link, le_plink); + +- sprintf(strSQL, "SET TRANSACTION LOCKING %s, ISOLATION %s;", strLocking[Z_LVAL_PP(Locking)], strIsolation[Z_LVAL_PP(Isolation)]); ++ if (snprintf(strSQL, sizeof(strSQL) , "SET TRANSACTION LOCKING %s, ISOLATION %s;", strLocking[Z_LVAL_PP(Locking)], strIsolation[Z_LVAL_PP(Isolation)]) < 0) { ++ RETURN_FALSE; ++ } + + md = fbcdcExecuteDirectSQL(phpLink->connection, strSQL); + fbcmdRelease(md); +@@ -1417,7 +1431,9 @@ + convert_to_string_ex(password); + userPassword = Z_STRVAL_PP(password); + +- sprintf(buffer, "SET AUTHORIZATION %s;", userName); ++ if (snprintf(buffer, sizeof(buffer), "SET AUTHORIZATION %s;", userName) < 0) { ++ RETURN_FALSE; ++ } + + phpfbQuery(INTERNAL_FUNCTION_PARAM_PASSTHRU, buffer, phpLink); + if (Z_LVAL_P(return_value)) +@@ -1791,11 +1807,28 @@ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "No message"); + } + link->errorText = strdup(emg); +- link->errorNo = fbcemdErrorCodeAtIndex(emd, 0);; ++ link->errorNo = fbcemdErrorCodeAtIndex(emd, 0); + free(emg); + fbcemdRelease(emd); + result = 0; + } ++ else if (fbcmdWarningsFound(md)) ++ { ++ FBCErrorMetaData* emd = fbcdcErrorMetaData(c, md); ++ char* emg = fbcemdAllErrorMessages(emd); ++ if (FB_SQL_G(generateWarnings)) ++ { ++ if (emg) ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Warning in statement: '%s' %s", sql, emg); ++ else ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "No message"); ++ } ++ link->errorText = strdup(emg); ++ link->errorNo = fbcemdErrorCodeAtIndex(emd, 0); ++ free(emg); ++ fbcemdRelease(emd); ++ result = 1; ++ } + return result; + } + /* }}} */ +@@ -1824,9 +1857,12 @@ + md = meta; + + tp = fbcmdStatementType(md); +- +- if ((tp[0] == 'C') || (tp[0] == 'R')) +- { ++ if (tp == NULL) { ++ fbcmdRelease(meta); ++ ZVAL_BOOL(return_value, 1) ++ } ++ else if ((tp[0] == 'C') || (tp[0] == 'R')) ++ { + if (sR == 1 && md) fbcmdRelease(md); + ZVAL_BOOL(return_value, 1) + } +@@ -2084,7 +2120,9 @@ + RETURN_FALSE; + } + +- sprintf(sql, "SELECT * FROM %s WHERE 1=0;", tableName); ++ if (snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE 1=0;", tableName) < 0) { ++ RETURN_FALSE; ++ } + + phpfbQuery(INTERNAL_FUNCTION_PARAM_PASSTHRU, sql, phpLink); + } +@@ -2268,7 +2306,7 @@ + { + int v = *((int*)data); + char b[128]; +- sprintf(b, "%d", v); ++ snprintf(b, sizeof(b), "%d", v); + phpfbestrdup(b, length, value); + } + break; +@@ -2277,7 +2315,7 @@ + { + short int v = *((FBTinyInteger*)data); + char b[128]; +- sprintf(b, "%d", v); ++ snprintf(b, sizeof(b), "%d", v); + phpfbestrdup(b, length, value); + } + break; +@@ -2288,9 +2326,9 @@ + FBLongInteger v = *((FBLongInteger*)data); + char b[128]; + #ifdef PHP_WIN32 +- sprintf(b, "%I64i", v); ++ snprintf(b, sizeof(b), "%I64i", v); + #else +- sprintf(b, "%ll", v); ++ snprintf(b, sizeof(b), "%ll", v); + #endif + phpfbestrdup(b, length, value); + } +@@ -2300,7 +2338,7 @@ + { + short v = *((short*)data); + char b[128]; +- sprintf(b, "%d", v); ++ snprintf(b, sizeof(b), "%d", v); + phpfbestrdup(b, length, value); + } + break; +@@ -2313,7 +2351,7 @@ + { + double v = *((double*)data); + char b[128]; +- sprintf(b, "%f", v); ++ snprintf(b, sizeof(b), "%f", v); + phpfbestrdup(b, length, value); + } + break; +@@ -2346,7 +2384,7 @@ + *length = l*2+3+1; + if (value) + { +- char* r = emalloc(l*2+3+1); ++ char* r = safe_emalloc(l, 2, 4); + r[0] = 'X'; + r[1] = '\''; + for (i = 0; i < nBits / 8; i++) +@@ -2368,7 +2406,7 @@ + *length = l*2+3+1; + if (value) + { +- char* r = emalloc(l*2+3+1); ++ char* r = safe_emalloc(l, 2, 4); + r[0] = 'B'; + r[1] = '\''; + for (i = 0; i < nBits; i++) +@@ -2400,7 +2438,7 @@ + { + char b[128]; + int v = *((unsigned int*)data); +- sprintf(b, "%d", v); ++ snprintf(b, sizeof(b), "%d", v); + phpfbestrdup(b, length, value); + } + break; +@@ -2409,7 +2447,7 @@ + { + char b[128]; + double seconds = *((double*)data); +- sprintf(b, "%f", seconds); ++ snprintf(b, sizeof(b), "%f", seconds); + phpfbestrdup(b, length, value); + } + break; +diff -Nur php-4.3.10/ext/mbstring/mbstring.c hardened-php-4.3.10-0.2.7/ext/mbstring/mbstring.c +--- php-4.3.10/ext/mbstring/mbstring.c 2004-06-24 00:07:01.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/ext/mbstring/mbstring.c 2005-04-07 01:51:16.000000000 +0200 +@@ -1467,12 +1467,13 @@ + + /* {{{ static void php_mbstr_encoding_handler() */ + static void +-php_mbstr_encoding_handler(zval *arg, char *res, char *separator TSRMLS_DC) ++php_mbstr_encoding_handler(zval *arg, int parse_type, char *res, char *separator TSRMLS_DC) + { + char *var, *val, *s1, *s2; + char *strtok_buf = NULL, **val_list; + zval *array_ptr = (zval *) arg; + int n, num, val_len, *len_list, elistsz; ++ unsigned int new_val_len; + enum mbfl_no_encoding from_encoding, to_encoding, *elist; + mbfl_string string, resvar, resval; + mbfl_encoding_detector *identd = NULL; +@@ -1593,8 +1594,14 @@ + val_len = len_list[n]; + } + n++; +- /* add variable to symbol table */ +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ /* we need val to be emalloc()ed */ ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(parse_type, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ /* add variable to symbol table */ ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); ++ + if (convd != NULL){ + mbfl_string_clear(&resvar); + mbfl_string_clear(&resval); +@@ -1620,7 +1627,7 @@ + { + MBSTRG(http_input_identify_post) = mbfl_no_encoding_invalid; + +- php_mbstr_encoding_handler(arg, SG(request_info).post_data, "&" TSRMLS_CC); ++ php_mbstr_encoding_handler(arg, PARSE_POST, SG(request_info).post_data, "&" TSRMLS_CC); + + if (MBSTRG(http_input_identify) != mbfl_no_encoding_invalid) { + MBSTRG(http_input_identify_post) = MBSTRG(http_input_identify); +@@ -1720,7 +1727,7 @@ + break; + } + +- php_mbstr_encoding_handler(array_ptr, res, separator TSRMLS_CC); ++ php_mbstr_encoding_handler(array_ptr, arg, res, separator TSRMLS_CC); + + if (MBSTRG(http_input_identify) != mbfl_no_encoding_invalid) { + switch(arg){ +diff -Nur php-4.3.10/ext/session/session.c hardened-php-4.3.10-0.2.7/ext/session/session.c +--- php-4.3.10/ext/session/session.c 2004-12-09 18:16:57.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/session/session.c 2005-04-07 01:54:27.000000000 +0200 +@@ -408,7 +408,7 @@ + p += namelen + 1; + + if (has_value) { +- MAKE_STD_ZVAL(current); ++ ALLOC_INIT_ZVAL(current); + if (php_var_unserialize(¤t, (const unsigned char **)&p, endptr, &var_hash TSRMLS_CC)) { + php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC); + } +@@ -488,7 +488,7 @@ + q++; + + if (has_value) { +- MAKE_STD_ZVAL(current); ++ ALLOC_INIT_ZVAL(current); + if (php_var_unserialize(¤t, (const unsigned char **)&q, endptr, &var_hash TSRMLS_CC)) { + php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC); + } +diff -Nur php-4.3.10/ext/standard/array.c hardened-php-4.3.10-0.2.7/ext/standard/array.c +--- php-4.3.10/ext/standard/array.c 2004-12-02 17:36:41.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/standard/array.c 2005-04-07 01:51:16.000000000 +0200 +@@ -1153,6 +1153,31 @@ + } + } + } ++ ++ if (var_name[0] == 'H') { ++ if ((strcmp(var_name, "HTTP_GET_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_FILES")==0)|| ++ (strcmp(var_name, "HTTP_ENV_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(var_name, "HTTP_COOKIE_VARS")==0)) { ++ return 0; ++ } ++ } else if (var_name[0] == '_') { ++ if ((strcmp(var_name, "_COOKIE")==0)|| ++ (strcmp(var_name, "_ENV")==0)|| ++ (strcmp(var_name, "_FILES")==0)|| ++ (strcmp(var_name, "_GET")==0)|| ++ (strcmp(var_name, "_POST")==0)|| ++ (strcmp(var_name, "_REQUEST")==0)|| ++ (strcmp(var_name, "_SESSION")==0)|| ++ (strcmp(var_name, "_SERVER")==0)) { ++ return 0; ++ } ++ } else if (strcmp(var_name, "GLOBALS")==0) { ++ return 0; ++ } + + return 1; + } +diff -Nur php-4.3.10/ext/standard/basic_functions.c hardened-php-4.3.10-0.2.7/ext/standard/basic_functions.c +--- php-4.3.10/ext/standard/basic_functions.c 2004-11-16 00:26:40.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/standard/basic_functions.c 2005-04-07 01:51:16.000000000 +0200 +@@ -687,7 +687,7 @@ + PHP_FALIAS(socket_get_status, stream_get_meta_data, NULL) + + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +- PHP_FE(realpath, NULL) ++ PHP_STATIC_FE("realpath", zif_real_path, NULL) + #endif + + #ifdef HAVE_FNMATCH +@@ -3008,6 +3008,34 @@ + memcpy(new_key, prefix, prefix_len); + memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + ++ if (new_key[0] == 'H') { ++ if ((strcmp(new_key, "HTTP_GET_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_FILES")==0)|| ++ (strcmp(new_key, "HTTP_ENV_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(new_key, "HTTP_COOKIE_VARS")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (new_key[0] == '_') { ++ if ((strcmp(new_key, "_COOKIE")==0)|| ++ (strcmp(new_key, "_ENV")==0)|| ++ (strcmp(new_key, "_FILES")==0)|| ++ (strcmp(new_key, "_GET")==0)|| ++ (strcmp(new_key, "_POST")==0)|| ++ (strcmp(new_key, "_REQUEST")==0)|| ++ (strcmp(new_key, "_SESSION")==0)|| ++ (strcmp(new_key, "_SERVER")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (strcmp(new_key, "GLOBALS")==0) { ++ efree(new_key); ++ return 0; ++ } ++ + zend_hash_del(&EG(symbol_table), new_key, new_key_len); + ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, (*var)->refcount+1, 0); + +diff -Nur php-4.3.10/ext/standard/file.c hardened-php-4.3.10-0.2.7/ext/standard/file.c +--- php-4.3.10/ext/standard/file.c 2004-12-08 22:15:02.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/standard/file.c 2005-04-07 01:51:16.000000000 +0200 +@@ -2472,7 +2472,7 @@ + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) + /* {{{ proto string realpath(string path) + Return the resolved path */ +-PHP_FUNCTION(realpath) ++PHP_FUNCTION(real_path) + { + zval **path; + char resolved_path_buff[MAXPATHLEN]; +diff -Nur php-4.3.10/ext/standard/file.h hardened-php-4.3.10-0.2.7/ext/standard/file.h +--- php-4.3.10/ext/standard/file.h 2004-06-21 21:33:47.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/ext/standard/file.h 2005-04-07 01:51:16.000000000 +0200 +@@ -64,7 +64,7 @@ + PHP_FUNCTION(fd_set); + PHP_FUNCTION(fd_isset); + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +-PHP_FUNCTION(realpath); ++PHP_FUNCTION(real_path); + #endif + #ifdef HAVE_FNMATCH + PHP_FUNCTION(fnmatch); +diff -Nur php-4.3.10/ext/standard/image.c hardened-php-4.3.10-0.2.7/ext/standard/image.c +--- php-4.3.10/ext/standard/image.c 2004-10-04 22:44:07.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/ext/standard/image.c 2005-04-07 01:51:16.000000000 +0200 +@@ -17,7 +17,7 @@ + +----------------------------------------------------------------------+ + */ + +-/* $Id: image.c,v 1.72.2.15 2004/10/04 20:44:07 iliaa Exp $ */ ++/* $Id: image.c,v 1.72.2.18 2005/03/06 17:05:41 iliaa Exp $ */ + + #include "php.h" + #include +@@ -363,7 +363,7 @@ + /* just return 0 if we hit the end-of-file */ + if((php_stream_read(stream, a, sizeof(a))) <= 0) return 0; + +- return (((unsigned short) a[ 0 ]) << 8) + ((unsigned short) a[ 1 ]); ++ return (((unsigned short)a[0]) << 8) + ((unsigned short)a[1]); + } + /* }}} */ + +@@ -374,7 +374,7 @@ + int a=0, marker; + + /* get marker byte, swallowing possible padding */ +- if ( last_marker==M_COM && comment_correction) { ++ if (last_marker==M_COM && comment_correction) { + /* some software does not count the length bytes of COM section */ + /* one company doing so is very much envolved in JPEG... so we accept too */ + /* by the way: some of those companies changed their code now... */ +@@ -383,7 +383,7 @@ + last_marker = 0; + comment_correction = 0; + } +- if ( ff_read) { ++ if (ff_read) { + a = 1; /* already read 0xff in filetype detection */ + } + do { +@@ -391,9 +391,9 @@ + { + return M_EOI;/* we hit EOF */ + } +- if ( last_marker==M_COM && comment_correction>0) ++ if (last_marker==M_COM && comment_correction>0) + { +- if ( marker != 0xFF) ++ if (marker != 0xFF) + { + marker = 0xff; + comment_correction--; +@@ -401,14 +401,14 @@ + last_marker = M_PSEUDO; /* stop skipping non 0xff for M_COM */ + } + } +- if ( ++a > 10) ++ if (++a > 10) + { + /* who knows the maxim amount of 0xff? though 7 */ + /* but found other implementations */ + return M_EOI; + } +- } while ( marker == 0xff); +- if ( a < 2) ++ } while (marker == 0xff); ++ if (a < 2) + { + return M_EOI; /* at least one 0xff is needed before marker code */ + } +@@ -422,35 +422,39 @@ + + /* {{{ php_skip_variable + * skip over a variable-length block; assumes proper length marker */ +-static void php_skip_variable(php_stream * stream TSRMLS_DC) ++static int php_skip_variable(php_stream * stream TSRMLS_DC) + { + off_t length = ((unsigned int)php_read2(stream TSRMLS_CC)); + +- length = length-2; +- if (length) +- { +- php_stream_seek(stream, (long)length, SEEK_CUR); ++ if (length < 2) { ++ return 0; + } ++ length = length - 2; ++ php_stream_seek(stream, (long)length, SEEK_CUR); ++ return 1; + } + /* }}} */ + + /* {{{ php_read_APP + */ +-static void php_read_APP(php_stream * stream, unsigned int marker, zval *info TSRMLS_DC) ++static int php_read_APP(php_stream * stream, unsigned int marker, zval *info TSRMLS_DC) + { + unsigned short length; + unsigned char *buffer; +- unsigned char markername[ 16 ]; ++ unsigned char markername[16]; + zval *tmp; + + length = php_read2(stream TSRMLS_CC); ++ if (length < 2) { ++ return 0; ++ } + length -= 2; /* length includes itself */ + + buffer = emalloc(length); + + if (php_stream_read(stream, buffer, (long) length) <= 0) { + efree(buffer); +- return; ++ return 0; + } + + sprintf(markername, "APP%d", marker - M_APP0); +@@ -461,6 +465,7 @@ + } + + efree(buffer); ++ return 1; + } + /* }}} */ + +@@ -497,12 +502,16 @@ + result->height = php_read2(stream TSRMLS_CC); + result->width = php_read2(stream TSRMLS_CC); + result->channels = php_stream_getc(stream); +- if (!info || length<8) /* if we don't want an extanded info -> return */ ++ if (!info || length < 8) { /* if we don't want an extanded info -> return */ + return result; +- if (php_stream_seek(stream, length-8, SEEK_CUR)) /* file error after info */ ++ } ++ if (php_stream_seek(stream, length - 8, SEEK_CUR)) { /* file error after info */ + return result; ++ } + } else { +- php_skip_variable(stream TSRMLS_CC); ++ if (!php_skip_variable(stream TSRMLS_CC)) { ++ return result; ++ } + } + break; + +@@ -523,9 +532,13 @@ + case M_APP14: + case M_APP15: + if (info) { +- php_read_APP(stream, marker, info TSRMLS_CC); /* read all the app markes... */ ++ if (!php_read_APP(stream, marker, info TSRMLS_CC)) { /* read all the app markes... */ ++ return result; ++ } + } else { +- php_skip_variable(stream TSRMLS_CC); ++ if (!php_skip_variable(stream TSRMLS_CC)) { ++ return result; ++ } + } + break; + +@@ -534,7 +547,9 @@ + return result; /* we're about to hit image data, or are at EOF. stop processing. */ + + default: +- php_skip_variable(stream TSRMLS_CC); /* anything else isn't interesting */ ++ if (!php_skip_variable(stream TSRMLS_CC)) { /* anything else isn't interesting */ ++ return result; ++ } + break; + } + } +@@ -613,17 +628,28 @@ + + dummy_short = php_read2(stream TSRMLS_CC); /* Lsiz */ + dummy_short = php_read2(stream TSRMLS_CC); /* Rsiz */ +- result->height = php_read4(stream TSRMLS_CC); /* Xsiz */ + result->width = php_read4(stream TSRMLS_CC); /* Ysiz */ ++ result->height = php_read4(stream TSRMLS_CC); /* Xsiz */ + ++#if MBO_0 + dummy_int = php_read4(stream TSRMLS_CC); /* XOsiz */ + dummy_int = php_read4(stream TSRMLS_CC); /* YOsiz */ + dummy_int = php_read4(stream TSRMLS_CC); /* XTsiz */ + dummy_int = php_read4(stream TSRMLS_CC); /* YTsiz */ + dummy_int = php_read4(stream TSRMLS_CC); /* XTOsiz */ + dummy_int = php_read4(stream TSRMLS_CC); /* YTOsiz */ ++#else ++ if (php_stream_seek(stream, 24, SEEK_CUR)) { ++ efree(result); ++ return NULL; ++ } ++#endif + + result->channels = php_read2(stream TSRMLS_CC); /* Csiz */ ++ if (result->channels < 0 || result->channels > 256) { ++ efree(result); ++ return NULL; ++ } + + /* Collect bit depth info */ + highest_bit_depth = bit_depth = 0; +@@ -685,8 +711,15 @@ + break; + } + ++ /* Stop if this was the last box */ ++ if ((int)box_length <= 0) { ++ break; ++ } ++ + /* Skip over LBox (Which includes both TBox and LBox itself */ +- php_stream_seek(stream, box_length - 8, SEEK_CUR); ++ if (php_stream_seek(stream, box_length - 8, SEEK_CUR)) { ++ break; ++ } + } + + if (result == NULL) { +@@ -849,43 +882,49 @@ + */ + static struct gfxinfo *php_handle_iff(php_stream * stream TSRMLS_DC) + { +- struct gfxinfo *result = NULL; ++ struct gfxinfo * result; + unsigned char a[10]; + int chunkId; + int size; ++ short width, height, bits; + +- if (php_stream_read(stream, a, 8) != 8) ++ if (php_stream_read(stream, a, 8) != 8) { + return NULL; +- if (strncmp(a+4, "ILBM", 4) && strncmp(a+4, "PBM ", 4)) ++ } ++ if (strncmp(a+4, "ILBM", 4) && strncmp(a+4, "PBM ", 4)) { + return NULL; +- +- result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); ++ } + + /* loop chunks to find BMHD chunk */ + do { + if (php_stream_read(stream, a, 8) != 8) { +- efree(result); + return NULL; + } + chunkId = php_ifd_get32s(a+0, 1); + size = php_ifd_get32s(a+4, 1); ++ if (size < 0) { ++ return NULL; ++ } + if ((size & 1) == 1) { + size++; + } + if (chunkId == 0x424d4844) { /* BMHD chunk */ +- if (php_stream_read(stream, a, 9) != 9) { +- efree(result); ++ if (size < 9 || php_stream_read(stream, a, 9) != 9) { + return NULL; + } +- result->width = php_ifd_get16s(a+0, 1); +- result->height = php_ifd_get16s(a+2, 1); +- result->bits = a[8] & 0xff; ++ width = php_ifd_get16s(a+0, 1); ++ height = php_ifd_get16s(a+2, 1); ++ bits = a[8] & 0xff; ++ if (width > 0 && height > 0 && bits > 0 && bits < 33) { ++ result = (struct gfxinfo *) ecalloc(1, sizeof(struct gfxinfo)); ++ result->width = width; ++ result->height = height; ++ result->bits = bits; + result->channels = 0; +- if (result->width > 0 && result->height > 0 && result->bits > 0 && result->bits < 33) + return result; ++ } + } else { + if (php_stream_seek(stream, size, SEEK_CUR)) { +- efree(result); + return NULL; + } + } +@@ -1230,11 +1269,14 @@ + case IMAGE_FILETYPE_SWF: + result = php_handle_swf(stream TSRMLS_CC); + break; +-#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB) + case IMAGE_FILETYPE_SWC: ++#if HAVE_ZLIB && !defined(COMPILE_DL_ZLIB) + result = php_handle_swc(stream TSRMLS_CC); +- break; ++#else ++ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "The image is a compressed SWF file, but you do not have a static version of the zlib extension enabled."); ++ + #endif ++ break; + case IMAGE_FILETYPE_PSD: + result = php_handle_psd(stream TSRMLS_CC); + break; +diff -Nur php-4.3.10/ext/standard/info.c hardened-php-4.3.10-0.2.7/ext/standard/info.c +--- php-4.3.10/ext/standard/info.c 2004-06-09 17:10:19.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/ext/standard/info.c 2005-04-07 01:51:16.000000000 +0200 +@@ -397,7 +397,7 @@ + + if (flag & PHP_INFO_GENERAL) { + char *zend_version = get_zend_version(); +- char temp_api[9]; ++ char temp_api[11]; + + php_uname = php_get_uname('a'); + +@@ -417,11 +417,22 @@ + } + } + ++#if HARDENED_PHP ++ if (!sapi_module.phpinfo_as_text) { ++ php_printf("

Hardened-PHP Version %s/%s

\n", PHP_VERSION, HARDENED_PHP_VERSION); ++ } else { ++ char temp_ver[40]; ++ ++ snprintf(temp_ver, sizeof(temp_ver), "%s/%s", PHP_VERSION, HARDENED_PHP_VERSION); ++ php_info_print_table_row(2, "Hardened-PHP Version", temp_ver); ++ } ++#else + if (!sapi_module.phpinfo_as_text) { + php_printf("

PHP Version %s

\n", PHP_VERSION); + } else { + php_info_print_table_row(2, "PHP Version", PHP_VERSION); + } ++#endif + php_info_print_box_end(); + php_info_print_table_start(); + php_info_print_table_row(2, "System", php_uname ); +diff -Nur php-4.3.10/ext/standard/pack.c hardened-php-4.3.10-0.2.7/ext/standard/pack.c +--- php-4.3.10/ext/standard/pack.c 2004-11-28 13:44:56.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/standard/pack.c 2005-04-07 01:51:16.000000000 +0200 +@@ -15,7 +15,7 @@ + | Author: Chris Schneider | + +----------------------------------------------------------------------+ + */ +-/* $Id: pack.c,v 1.40.2.6 2004/11/28 12:44:56 sesser Exp $ */ ++/* $Id: pack.c,v 1.40.2.7 2005/01/25 22:52:19 iliaa Exp $ */ + + #include "php.h" + +@@ -833,7 +833,9 @@ + + inputpos += size; + if (inputpos < 0) { +- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", type); ++ if (size != -1) { /* only print warning if not working with * */ ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Type %c: outside of string", type); ++ } + inputpos = 0; + } + } else if (arg < 0) { +diff -Nur php-4.3.10/ext/standard/php_var.h hardened-php-4.3.10-0.2.7/ext/standard/php_var.h +--- php-4.3.10/ext/standard/php_var.h 2004-09-24 23:57:18.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/ext/standard/php_var.h 2005-04-07 01:51:16.000000000 +0200 +@@ -16,7 +16,7 @@ + +----------------------------------------------------------------------+ + */ + +-/* $Id: php_var.h,v 1.21.4.4 2004/09/24 21:57:18 helly Exp $ */ ++/* $Id: php_var.h,v 1.21.4.5 2005/01/15 18:44:29 sesser Exp $ */ + + #ifndef PHP_VAR_H + #define PHP_VAR_H +@@ -41,6 +41,7 @@ + + struct php_unserialize_data { + void *first; ++ void *first_dtor; + }; + + typedef struct php_unserialize_data php_unserialize_data_t; +@@ -54,7 +55,8 @@ + zend_hash_destroy(&(var_hash)) + + #define PHP_VAR_UNSERIALIZE_INIT(var_hash) \ +- (var_hash).first = 0 ++ (var_hash).first = 0; \ ++ (var_hash).first_dtor = 0 + #define PHP_VAR_UNSERIALIZE_DESTROY(var_hash) \ + var_destroy(&(var_hash)) + +diff -Nur php-4.3.10/ext/standard/var_unserializer.c hardened-php-4.3.10-0.2.7/ext/standard/var_unserializer.c +--- php-4.3.10/ext/standard/var_unserializer.c 2004-12-14 18:55:22.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/standard/var_unserializer.c 2005-04-07 01:51:16.000000000 +0200 +@@ -1,4 +1,4 @@ +-/* Generated by re2c 0.5 on Thu Nov 18 17:11:01 2004 */ ++/* Generated by re2c 0.9.4 on Thu Mar 10 02:59:20 2005 */ + /* + +----------------------------------------------------------------------+ + | PHP Version 4 | +@@ -17,7 +17,7 @@ + +----------------------------------------------------------------------+ + */ + +-/* $Id: var_unserializer.c,v 1.18.4.14 2004/12/03 16:09:19 sesser Exp $ */ ++/* $Id: var_unserializer.c,v 1.18.4.23 2005/03/10 02:01:40 helly Exp $ */ + + #include "php.h" + #include "ext/standard/php_var.h" +@@ -28,7 +28,7 @@ + + typedef struct { + zval *data[VAR_ENTRIES_MAX]; +- int used_slots; ++ long used_slots; + void *next; + } var_entries; + +@@ -55,9 +55,33 @@ + var_hash->data[var_hash->used_slots++] = *rval; + } + ++static inline void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval) ++{ ++ var_entries *var_hash = var_hashx->first_dtor, *prev = NULL; ++ ++ while (var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) { ++ prev = var_hash; ++ var_hash = var_hash->next; ++ } ++ ++ if (!var_hash) { ++ var_hash = emalloc(sizeof(var_entries)); ++ var_hash->used_slots = 0; ++ var_hash->next = 0; ++ ++ if (!var_hashx->first_dtor) ++ var_hashx->first_dtor = var_hash; ++ else ++ prev->next = var_hash; ++ } ++ ++ (*rval)->refcount++; ++ var_hash->data[var_hash->used_slots++] = *rval; ++} ++ + PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **nzval) + { +- int i; ++ long i; + var_entries *var_hash = var_hashx->first; + + while (var_hash) { +@@ -71,7 +95,7 @@ + } + } + +-static int var_access(php_unserialize_data_t *var_hashx, int id, zval ***store) ++static int var_access(php_unserialize_data_t *var_hashx, long id, zval ***store) + { + var_entries *var_hash = var_hashx->first; + +@@ -92,6 +116,7 @@ + PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) + { + void *next; ++ long i; + var_entries *var_hash = var_hashx->first; + + while (var_hash) { +@@ -99,6 +124,17 @@ + efree(var_hash); + var_hash = next; + } ++ ++ var_hash = var_hashx->first_dtor; ++ ++ while (var_hash) { ++ for (i = 0; i < var_hash->used_slots; i++) { ++ zval_ptr_dtor(&var_hash->data[i]); ++ } ++ next = var_hash->next; ++ efree(var_hash); ++ var_hash = next; ++ } + } + + /* }}} */ +@@ -114,10 +150,10 @@ + + + +-static inline int parse_iv2(const unsigned char *p, const unsigned char **q) ++static inline long parse_iv2(const unsigned char *p, const unsigned char **q) + { + char cursor; +- int result = 0; ++ long result = 0; + int neg = 0; + + switch (*p) { +@@ -142,7 +178,7 @@ + return result; + } + +-static inline int parse_iv(const unsigned char *p) ++static inline long parse_iv(const unsigned char *p) + { + return parse_iv2(p, NULL); + } +@@ -172,10 +208,10 @@ + #define UNSERIALIZE_PARAMETER zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC + #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC + +-static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, int elements) ++static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long elements) + { + while (elements-- > 0) { +- zval *key, *data, *old_data; ++ zval *key, *data, **old_data; + + ALLOC_INIT_ZVAL(key); + +@@ -203,14 +239,14 @@ + + switch (Z_TYPE_P(key)) { + case IS_LONG: +- if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)) { +- var_replace(var_hash, old_data, rval); ++ if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)==SUCCESS) { ++ var_push_dtor(var_hash, old_data); + } + zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL); + break; + case IS_STRING: +- if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)) { +- var_replace(var_hash, old_data, rval); ++ if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) { ++ var_push_dtor(var_hash, old_data); + } + zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL); + break; +@@ -241,7 +277,7 @@ + + static inline int object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) + { +- int elements; ++ long elements; + + elements = parse_iv2((*p) + 2, p); + +@@ -251,7 +287,7 @@ + return elements; + } + +-static inline int object_common2(UNSERIALIZE_PARAMETER, int elements) ++static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) + { + zval *retval_ptr = NULL; + zval fname; +@@ -300,6 +336,7 @@ + + + ++ + { + YYCTYPE yych; + unsigned int yyaccept; +@@ -378,7 +415,8 @@ + goto yy16; + } else { + if(yych <= '}') goto yy14; +- if(yych <= '\277') goto yy16; ++ if(yych <= 0xBF) goto yy16; ++ goto yy2; + } + } + } +@@ -389,8 +427,9 @@ + yy3: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy87; ++ goto yy4; + yy4: +- { return 0; } ++{ return 0; } + yy5: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy81; +@@ -426,9 +465,10 @@ + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy17; + goto yy4; +-yy14: yych = *++YYCURSOR; ++yy14: ++YYCURSOR; ++ goto yy15; + yy15: +- { ++{ + /* this is the case where we have less data than planned */ + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data"); + return 0; /* not sure if it should be 0 or 1 here? */ +@@ -438,21 +478,26 @@ + yy17: yych = *++YYCURSOR; + if(yybm[0+yych] & 128) goto yy19; + if(yych != '+') goto yy2; ++ goto yy18; + yy18: yych = *++YYCURSOR; + if(yybm[0+yych] & 128) goto yy19; + goto yy2; + yy19: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy20; + yy20: if(yybm[0+yych] & 128) goto yy19; + if(yych != ':') goto yy2; ++ goto yy21; + yy21: yych = *++YYCURSOR; + if(yych != '"') goto yy2; +-yy22: yych = *++YYCURSOR; ++ goto yy22; ++yy22: ++YYCURSOR; ++ goto yy23; + yy23: +- { +- size_t len, len2, maxlen; +- int elements; ++{ ++ size_t len, len2, len3, maxlen; ++ long elements; + char *class_name; + zend_class_entry *ce; + int incomplete_class = 0; +@@ -486,6 +531,14 @@ + class_name = str_tolower_copy((char *)emalloc(len+1), class_name, len); + class_name[len] = '\0'; + ++ len3 = strspn(class_name, "0123456789_abcdefghijklmnopqrstuvwxyz"); ++ if (len3 != len) ++ { ++ *p = YYCURSOR + len3 - len; ++ efree(class_name); ++ return 0; ++ } ++ + if (zend_hash_find(CG(class_table), class_name, len + 1, (void **) &ce) != SUCCESS) { + if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) { + incomplete_class = 1; +@@ -533,6 +586,7 @@ + yy24: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy2; ++ goto yy25; + } else { + if(yych <= '-') goto yy25; + if(yych <= '/') goto yy2; +@@ -542,17 +596,22 @@ + yy25: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy26; + yy26: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy27; + yy27: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy26; + if(yych >= ';') goto yy2; ++ goto yy28; + yy28: yych = *++YYCURSOR; + if(yych != '"') goto yy2; +-yy29: yych = *++YYCURSOR; ++ goto yy29; ++yy29: ++YYCURSOR; ++ goto yy30; + yy30: +- { ++{ + + INIT_PZVAL(*rval); + +@@ -567,21 +626,34 @@ + yy32: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy33; + yy33: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy34; + yy34: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy33; + if(yych >= ';') goto yy2; ++ goto yy35; + yy35: yych = *++YYCURSOR; + if(yych != '{') goto yy2; +-yy36: yych = *++YYCURSOR; ++ goto yy36; ++yy36: ++YYCURSOR; ++ goto yy37; + yy37: +- { +- int elements = parse_iv(start + 2); +- ++{ ++ long elements = parse_iv(start + 2); ++ /* use iv() not uiv() in order to check data range */ + *p = YYCURSOR; + ++ if (elements < 0) { ++ return 0; ++ } ++ ++ if (elements < 0) { ++ return 0; ++ } ++ + INIT_PZVAL(*rval); + Z_TYPE_PP(rval) = IS_ARRAY; + ALLOC_HASHTABLE(Z_ARRVAL_PP(rval)); +@@ -602,17 +674,22 @@ + yy39: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy40; + yy40: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy41; + yy41: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy40; + if(yych >= ';') goto yy2; ++ goto yy42; + yy42: yych = *++YYCURSOR; + if(yych != '"') goto yy2; +-yy43: yych = *++YYCURSOR; ++ goto yy43; ++yy43: ++YYCURSOR; ++ goto yy44; + yy44: +- { ++{ + size_t len, maxlen; + char *str; + +@@ -656,6 +733,7 @@ + goto yy48; + } else { + if(yych != 'N') goto yy2; ++ goto yy46; + } + } + yy46: yych = *++YYCURSOR; +@@ -668,6 +746,7 @@ + } else { + if(yych <= '9') goto yy50; + if(yych != 'I') goto yy2; ++ goto yy48; + } + yy48: yych = *++YYCURSOR; + if(yych == 'N') goto yy64; +@@ -676,9 +755,11 @@ + if(yych == '.') goto yy52; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy50; + yy50: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy51; + yy51: if(yych <= ':'){ + if(yych <= '.'){ + if(yych <= '-') goto yy2; +@@ -701,13 +782,16 @@ + yy52: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy53; + yy53: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy54; + yy54: if(yych <= ';'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy53; + if(yych <= ':') goto yy2; ++ goto yy55; + } else { + if(yych <= 'E'){ + if(yych <= 'D') goto yy2; +@@ -717,17 +801,19 @@ + goto yy2; + } + } +-yy55: yych = *++YYCURSOR; ++yy55: ++YYCURSOR; ++ goto yy56; + yy56: +- { ++{ + *p = YYCURSOR; + INIT_PZVAL(*rval); +- ZVAL_DOUBLE(*rval, atof(start + 2)); ++ ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); + return 1; + } + yy57: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy2; ++ goto yy58; + } else { + if(yych <= '-') goto yy58; + if(yych <= '/') goto yy2; +@@ -742,10 +828,12 @@ + if(yych <= '-') goto yy61; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy59; + } + yy59: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy60; + yy60: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy59; + if(yych == ';') goto yy55; +@@ -757,6 +845,7 @@ + yy62: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 4) YYFILL(4); + yych = *YYCURSOR; ++ goto yy63; + yy63: if(yych <= ';'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy62; +@@ -773,16 +862,17 @@ + } + yy64: yych = *++YYCURSOR; + if(yych != 'F') goto yy2; ++ goto yy65; + yy65: yych = *++YYCURSOR; + if(yych != ';') goto yy2; +-yy66: yych = *++YYCURSOR; ++ goto yy66; ++yy66: ++YYCURSOR; ++ goto yy67; + yy67: +- { ++{ + *p = YYCURSOR; + INIT_PZVAL(*rval); +-#if defined(HAVE_ATOF_ACCEPTS_NAN) && defined(HAVE_ATOF_ACCEPTS_INF) +- ZVAL_DOUBLE(*rval, atof(start + 2)); +-#else ++ + if (!strncmp(start + 2, "NAN", 3)) { + ZVAL_DOUBLE(*rval, php_get_nan()); + } else if (!strncmp(start + 2, "INF", 3)) { +@@ -790,7 +880,7 @@ + } else if (!strncmp(start + 2, "-INF", 4)) { + ZVAL_DOUBLE(*rval, -php_get_inf()); + } +-#endif ++ + return 1; + } + yy68: yych = *++YYCURSOR; +@@ -799,6 +889,7 @@ + yy69: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy2; ++ goto yy70; + } else { + if(yych <= '-') goto yy70; + if(yych <= '/') goto yy2; +@@ -808,15 +899,19 @@ + yy70: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy71; + yy71: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy72; + yy72: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy71; + if(yych != ';') goto yy2; +-yy73: yych = *++YYCURSOR; ++ goto yy73; ++yy73: ++YYCURSOR; ++ goto yy74; + yy74: +- { ++{ + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_LONG(*rval, parse_iv(start + 2)); +@@ -825,19 +920,23 @@ + yy75: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= '2') goto yy2; ++ goto yy76; + yy76: yych = *++YYCURSOR; + if(yych != ';') goto yy2; +-yy77: yych = *++YYCURSOR; ++ goto yy77; ++yy77: ++YYCURSOR; ++ goto yy78; + yy78: +- { ++{ + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_BOOL(*rval, parse_iv(start + 2)); + return 1; + } +-yy79: yych = *++YYCURSOR; ++yy79: ++YYCURSOR; ++ goto yy80; + yy80: +- { ++{ + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_NULL(*rval); +@@ -846,6 +945,7 @@ + yy81: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy2; ++ goto yy82; + } else { + if(yych <= '-') goto yy82; + if(yych <= '/') goto yy2; +@@ -855,16 +955,20 @@ + yy82: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy83; + yy83: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy84; + yy84: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy83; + if(yych != ';') goto yy2; +-yy85: yych = *++YYCURSOR; ++ goto yy85; ++yy85: ++YYCURSOR; ++ goto yy86; + yy86: +- { +- int id; ++{ ++ long id; + + *p = YYCURSOR; + if (!var_hash) return 0; +@@ -873,7 +977,7 @@ + if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) { + return 0; + } +- ++ + if (*rval == *rval_ref) return 0; + + if (*rval != NULL) { +@@ -888,6 +992,7 @@ + yy87: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy2; ++ goto yy88; + } else { + if(yych <= '-') goto yy88; + if(yych <= '/') goto yy2; +@@ -897,16 +1002,20 @@ + yy88: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy89; + yy89: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy90; + yy90: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy89; + if(yych != ';') goto yy2; +-yy91: yych = *++YYCURSOR; ++ goto yy91; ++yy91: ++YYCURSOR; ++ goto yy92; + yy92: +- { +- int id; ++{ ++ long id; + + *p = YYCURSOR; + if (!var_hash) return 0; +diff -Nur php-4.3.10/ext/standard/var_unserializer.c.orig hardened-php-4.3.10-0.2.7/ext/standard/var_unserializer.c.orig +--- php-4.3.10/ext/standard/var_unserializer.c.orig 2004-12-14 18:55:22.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/standard/var_unserializer.c.orig 2005-04-07 01:51:16.000000000 +0200 +@@ -1,5 +1,5 @@ +-/* Generated by re2c 0.5 on Thu Nov 18 17:11:01 2004 */ +-#line 1 "/home/rei/php4/ext/standard/var_unserializer.re" ++/* Generated by re2c 0.9.4 on Thu Mar 10 02:59:20 2005 */ ++#line 1 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" + /* + +----------------------------------------------------------------------+ + | PHP Version 4 | +@@ -18,7 +18,7 @@ + +----------------------------------------------------------------------+ + */ + +-/* $Id: var_unserializer.c,v 1.18.4.14 2004/12/03 16:09:19 sesser Exp $ */ ++/* $Id: var_unserializer.c,v 1.18.4.23 2005/03/10 02:01:40 helly Exp $ */ + + #include "php.h" + #include "ext/standard/php_var.h" +@@ -29,7 +29,7 @@ + + typedef struct { + zval *data[VAR_ENTRIES_MAX]; +- int used_slots; ++ long used_slots; + void *next; + } var_entries; + +@@ -56,9 +56,33 @@ + var_hash->data[var_hash->used_slots++] = *rval; + } + ++static inline void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval) ++{ ++ var_entries *var_hash = var_hashx->first_dtor, *prev = NULL; ++ ++ while (var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) { ++ prev = var_hash; ++ var_hash = var_hash->next; ++ } ++ ++ if (!var_hash) { ++ var_hash = emalloc(sizeof(var_entries)); ++ var_hash->used_slots = 0; ++ var_hash->next = 0; ++ ++ if (!var_hashx->first_dtor) ++ var_hashx->first_dtor = var_hash; ++ else ++ prev->next = var_hash; ++ } ++ ++ (*rval)->refcount++; ++ var_hash->data[var_hash->used_slots++] = *rval; ++} ++ + PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **nzval) + { +- int i; ++ long i; + var_entries *var_hash = var_hashx->first; + + while (var_hash) { +@@ -72,7 +96,7 @@ + } + } + +-static int var_access(php_unserialize_data_t *var_hashx, int id, zval ***store) ++static int var_access(php_unserialize_data_t *var_hashx, long id, zval ***store) + { + var_entries *var_hash = var_hashx->first; + +@@ -93,6 +117,7 @@ + PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) + { + void *next; ++ long i; + var_entries *var_hash = var_hashx->first; + + while (var_hash) { +@@ -100,6 +125,17 @@ + efree(var_hash); + var_hash = next; + } ++ ++ var_hash = var_hashx->first_dtor; ++ ++ while (var_hash) { ++ for (i = 0; i < var_hash->used_slots; i++) { ++ zval_ptr_dtor(&var_hash->data[i]); ++ } ++ next = var_hash->next; ++ efree(var_hash); ++ var_hash = next; ++ } + } + + /* }}} */ +@@ -111,15 +147,15 @@ + #define YYMARKER marker + + +-#line 118 ++#line 154 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" + + + + +-static inline int parse_iv2(const unsigned char *p, const unsigned char **q) ++static inline long parse_iv2(const unsigned char *p, const unsigned char **q) + { + char cursor; +- int result = 0; ++ long result = 0; + int neg = 0; + + switch (*p) { +@@ -144,7 +180,7 @@ + return result; + } + +-static inline int parse_iv(const unsigned char *p) ++static inline long parse_iv(const unsigned char *p) + { + return parse_iv2(p, NULL); + } +@@ -174,10 +210,10 @@ + #define UNSERIALIZE_PARAMETER zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC + #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC + +-static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, int elements) ++static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long elements) + { + while (elements-- > 0) { +- zval *key, *data, *old_data; ++ zval *key, *data, **old_data; + + ALLOC_INIT_ZVAL(key); + +@@ -205,14 +241,14 @@ + + switch (Z_TYPE_P(key)) { + case IS_LONG: +- if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)) { +- var_replace(var_hash, old_data, rval); ++ if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)==SUCCESS) { ++ var_push_dtor(var_hash, old_data); + } + zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL); + break; + case IS_STRING: +- if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)) { +- var_replace(var_hash, old_data, rval); ++ if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) { ++ var_push_dtor(var_hash, old_data); + } + zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL); + break; +@@ -243,7 +279,7 @@ + + static inline int object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) + { +- int elements; ++ long elements; + + elements = parse_iv2((*p) + 2, p); + +@@ -253,7 +289,7 @@ + return elements; + } + +-static inline int object_common2(UNSERIALIZE_PARAMETER, int elements) ++static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) + { + zval *retval_ptr = NULL; + zval fname; +@@ -302,6 +338,8 @@ + + + ++ ++#line 7 "" + { + YYCTYPE yych; + unsigned int yyaccept; +@@ -380,7 +418,8 @@ + goto yy16; + } else { + if(yych <= '}') goto yy14; +- if(yych <= '\277') goto yy16; ++ if(yych <= 0xBF) goto yy16; ++ goto yy2; + } + } + } +@@ -391,9 +430,11 @@ + yy3: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy87; ++ goto yy4; + yy4: +-#line 532 +- { return 0; } ++#line 590 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" ++{ return 0; } ++#line 102 "" + yy5: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy81; +@@ -429,35 +470,42 @@ + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy17; + goto yy4; +-yy14: yych = *++YYCURSOR; ++yy14: ++YYCURSOR; ++ goto yy15; + yy15: +-#line 526 +- { ++#line 584 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" ++{ + /* this is the case where we have less data than planned */ + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data"); + return 0; /* not sure if it should be 0 or 1 here? */ + } ++#line 147 "" + yy16: yych = *++YYCURSOR; + goto yy4; + yy17: yych = *++YYCURSOR; + if(yybm[0+yych] & 128) goto yy19; + if(yych != '+') goto yy2; ++ goto yy18; + yy18: yych = *++YYCURSOR; + if(yybm[0+yych] & 128) goto yy19; + goto yy2; + yy19: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy20; + yy20: if(yybm[0+yych] & 128) goto yy19; + if(yych != ':') goto yy2; ++ goto yy21; + yy21: yych = *++YYCURSOR; + if(yych != '"') goto yy2; +-yy22: yych = *++YYCURSOR; ++ goto yy22; ++yy22: ++YYCURSOR; ++ goto yy23; + yy23: +-#line 445 +- { +- size_t len, len2, maxlen; +- int elements; ++#line 495 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" ++{ ++ size_t len, len2, len3, maxlen; ++ long elements; + char *class_name; + zend_class_entry *ce; + int incomplete_class = 0; +@@ -491,6 +539,14 @@ + class_name = str_tolower_copy((char *)emalloc(len+1), class_name, len); + class_name[len] = '\0'; + ++ len3 = strspn(class_name, "0123456789_abcdefghijklmnopqrstuvwxyz"); ++ if (len3 != len) ++ { ++ *p = YYCURSOR + len3 - len; ++ efree(class_name); ++ return 0; ++ } ++ + if (zend_hash_find(CG(class_table), class_name, len + 1, (void **) &ce) != SUCCESS) { + if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) { + incomplete_class = 1; +@@ -535,9 +591,11 @@ + + return object_common2(UNSERIALIZE_PASSTHRU, elements); + } ++#line 260 "" + yy24: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy2; ++ goto yy25; + } else { + if(yych <= '-') goto yy25; + if(yych <= '/') goto yy2; +@@ -547,24 +605,30 @@ + yy25: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy26; + yy26: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy27; + yy27: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy26; + if(yych >= ';') goto yy2; ++ goto yy28; + yy28: yych = *++YYCURSOR; + if(yych != '"') goto yy2; +-yy29: yych = *++YYCURSOR; ++ goto yy29; ++yy29: ++YYCURSOR; ++ goto yy30; + yy30: +-#line 437 +- { ++#line 487 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" ++{ + + INIT_PZVAL(*rval); + + return object_common2(UNSERIALIZE_PASSTHRU, + object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); + } ++#line 298 "" + yy31: yych = *++YYCURSOR; + if(yych == '+') goto yy32; + if(yych <= '/') goto yy2; +@@ -573,22 +637,35 @@ + yy32: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy33; + yy33: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy34; + yy34: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy33; + if(yych >= ';') goto yy2; ++ goto yy35; + yy35: yych = *++YYCURSOR; + if(yych != '{') goto yy2; +-yy36: yych = *++YYCURSOR; ++ goto yy36; ++yy36: ++YYCURSOR; ++ goto yy37; + yy37: +-#line 419 +- { +- int elements = parse_iv(start + 2); +- ++#line 461 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" ++{ ++ long elements = parse_iv(start + 2); ++ /* use iv() not uiv() in order to check data range */ + *p = YYCURSOR; + ++ if (elements < 0) { ++ return 0; ++ } ++ ++ if (elements < 0) { ++ return 0; ++ } ++ + INIT_PZVAL(*rval); + Z_TYPE_PP(rval) = IS_ARRAY; + ALLOC_HASHTABLE(Z_ARRVAL_PP(rval)); +@@ -601,6 +678,7 @@ + + return finish_nested_data(UNSERIALIZE_PASSTHRU); + } ++#line 349 "" + yy38: yych = *++YYCURSOR; + if(yych == '+') goto yy39; + if(yych <= '/') goto yy2; +@@ -609,18 +687,23 @@ + yy39: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy40; + yy40: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy41; + yy41: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy40; + if(yych >= ';') goto yy2; ++ goto yy42; + yy42: yych = *++YYCURSOR; + if(yych != '"') goto yy2; +-yy43: yych = *++YYCURSOR; ++ goto yy43; ++yy43: ++YYCURSOR; ++ goto yy44; + yy44: +-#line 391 +- { ++#line 433 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" ++{ + size_t len, maxlen; + char *str; + +@@ -647,6 +730,7 @@ + ZVAL_STRINGL(*rval, str, len, 1); + return 1; + } ++#line 402 "" + yy45: yych = *++YYCURSOR; + if(yych <= '/'){ + if(yych <= ','){ +@@ -664,6 +748,7 @@ + goto yy48; + } else { + if(yych != 'N') goto yy2; ++ goto yy46; + } + } + yy46: yych = *++YYCURSOR; +@@ -676,6 +761,7 @@ + } else { + if(yych <= '9') goto yy50; + if(yych != 'I') goto yy2; ++ goto yy48; + } + yy48: yych = *++YYCURSOR; + if(yych == 'N') goto yy64; +@@ -684,9 +770,11 @@ + if(yych == '.') goto yy52; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy50; + yy50: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy51; + yy51: if(yych <= ':'){ + if(yych <= '.'){ + if(yych <= '-') goto yy2; +@@ -709,13 +797,16 @@ + yy52: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy53; + yy53: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy54; + yy54: if(yych <= ';'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy53; + if(yych <= ':') goto yy2; ++ goto yy55; + } else { + if(yych <= 'E'){ + if(yych <= 'D') goto yy2; +@@ -725,18 +816,21 @@ + goto yy2; + } + } +-yy55: yych = *++YYCURSOR; ++yy55: ++YYCURSOR; ++ goto yy56; + yy56: +-#line 384 +- { ++#line 426 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" ++{ + *p = YYCURSOR; + INIT_PZVAL(*rval); +- ZVAL_DOUBLE(*rval, atof(start + 2)); ++ ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); + return 1; + } ++#line 500 "" + yy57: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy2; ++ goto yy58; + } else { + if(yych <= '-') goto yy58; + if(yych <= '/') goto yy2; +@@ -751,10 +845,12 @@ + if(yych <= '-') goto yy61; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy59; + } + yy59: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy60; + yy60: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy59; + if(yych == ';') goto yy55; +@@ -766,6 +862,7 @@ + yy62: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 4) YYFILL(4); + yych = *YYCURSOR; ++ goto yy63; + yy63: if(yych <= ';'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy62; +@@ -782,17 +879,18 @@ + } + yy64: yych = *++YYCURSOR; + if(yych != 'F') goto yy2; ++ goto yy65; + yy65: yych = *++YYCURSOR; + if(yych != ';') goto yy2; +-yy66: yych = *++YYCURSOR; ++ goto yy66; ++yy66: ++YYCURSOR; ++ goto yy67; + yy67: +-#line 367 +- { ++#line 411 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" ++{ + *p = YYCURSOR; + INIT_PZVAL(*rval); +-#if defined(HAVE_ATOF_ACCEPTS_NAN) && defined(HAVE_ATOF_ACCEPTS_INF) +- ZVAL_DOUBLE(*rval, atof(start + 2)); +-#else ++ + if (!strncmp(start + 2, "NAN", 3)) { + ZVAL_DOUBLE(*rval, php_get_nan()); + } else if (!strncmp(start + 2, "INF", 3)) { +@@ -800,15 +898,17 @@ + } else if (!strncmp(start + 2, "-INF", 4)) { + ZVAL_DOUBLE(*rval, -php_get_inf()); + } +-#endif ++ + return 1; + } ++#line 577 "" + yy68: yych = *++YYCURSOR; + if(yych == 'N') goto yy65; + goto yy2; + yy69: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy2; ++ goto yy70; + } else { + if(yych <= '-') goto yy70; + if(yych <= '/') goto yy2; +@@ -818,47 +918,59 @@ + yy70: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy71; + yy71: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy72; + yy72: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy71; + if(yych != ';') goto yy2; +-yy73: yych = *++YYCURSOR; ++ goto yy73; ++yy73: ++YYCURSOR; ++ goto yy74; + yy74: +-#line 360 +- { ++#line 404 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" ++{ + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_LONG(*rval, parse_iv(start + 2)); + return 1; + } ++#line 614 "" + yy75: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= '2') goto yy2; ++ goto yy76; + yy76: yych = *++YYCURSOR; + if(yych != ';') goto yy2; +-yy77: yych = *++YYCURSOR; ++ goto yy77; ++yy77: ++YYCURSOR; ++ goto yy78; + yy78: +-#line 353 +- { ++#line 397 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" ++{ + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_BOOL(*rval, parse_iv(start + 2)); + return 1; + } +-yy79: yych = *++YYCURSOR; ++#line 632 "" ++yy79: ++YYCURSOR; ++ goto yy80; + yy80: +-#line 346 +- { ++#line 390 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" ++{ + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_NULL(*rval); + return 1; + } ++#line 643 "" + yy81: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy2; ++ goto yy82; + } else { + if(yych <= '-') goto yy82; + if(yych <= '/') goto yy2; +@@ -868,17 +980,21 @@ + yy82: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy83; + yy83: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy84; + yy84: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy83; + if(yych != ';') goto yy2; +-yy85: yych = *++YYCURSOR; ++ goto yy85; ++yy85: ++YYCURSOR; ++ goto yy86; + yy86: +-#line 325 +- { +- int id; ++#line 367 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" ++{ ++ long id; + + *p = YYCURSOR; + if (!var_hash) return 0; +@@ -887,7 +1003,7 @@ + if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) { + return 0; + } +- ++ + if (*rval == *rval_ref) return 0; + + if (*rval != NULL) { +@@ -899,9 +1015,11 @@ + + return 1; + } ++#line 693 "" + yy87: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy2; ++ goto yy88; + } else { + if(yych <= '-') goto yy88; + if(yych <= '/') goto yy2; +@@ -911,17 +1029,21 @@ + yy88: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; ++ goto yy89; + yy89: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; ++ goto yy90; + yy90: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy89; + if(yych != ';') goto yy2; +-yy91: yych = *++YYCURSOR; ++ goto yy91; ++yy91: ++YYCURSOR; ++ goto yy92; + yy92: +-#line 304 +- { +- int id; ++#line 346 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" ++{ ++ long id; + + *p = YYCURSOR; + if (!var_hash) return 0; +@@ -940,8 +1062,9 @@ + + return 1; + } ++#line 741 "" + } +-#line 534 ++#line 592 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" + + + return 0; +diff -Nur php-4.3.10/ext/standard/var_unserializer.re hardened-php-4.3.10-0.2.7/ext/standard/var_unserializer.re +--- php-4.3.10/ext/standard/var_unserializer.re 2004-12-03 17:09:19.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/standard/var_unserializer.re 2005-04-07 01:51:16.000000000 +0200 +@@ -16,7 +16,7 @@ + +----------------------------------------------------------------------+ + */ + +-/* $Id: var_unserializer.re,v 1.11.4.8 2004/12/03 16:09:19 sesser Exp $ */ ++/* $Id: var_unserializer.re,v 1.11.4.16 2005/03/10 02:00:17 helly Exp $ */ + + #include "php.h" + #include "ext/standard/php_var.h" +@@ -27,7 +27,7 @@ + + typedef struct { + zval *data[VAR_ENTRIES_MAX]; +- int used_slots; ++ long used_slots; + void *next; + } var_entries; + +@@ -54,9 +54,33 @@ + var_hash->data[var_hash->used_slots++] = *rval; + } + ++static inline void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval) ++{ ++ var_entries *var_hash = var_hashx->first_dtor, *prev = NULL; ++ ++ while (var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) { ++ prev = var_hash; ++ var_hash = var_hash->next; ++ } ++ ++ if (!var_hash) { ++ var_hash = emalloc(sizeof(var_entries)); ++ var_hash->used_slots = 0; ++ var_hash->next = 0; ++ ++ if (!var_hashx->first_dtor) ++ var_hashx->first_dtor = var_hash; ++ else ++ prev->next = var_hash; ++ } ++ ++ (*rval)->refcount++; ++ var_hash->data[var_hash->used_slots++] = *rval; ++} ++ + PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **nzval) + { +- int i; ++ long i; + var_entries *var_hash = var_hashx->first; + + while (var_hash) { +@@ -70,7 +94,7 @@ + } + } + +-static int var_access(php_unserialize_data_t *var_hashx, int id, zval ***store) ++static int var_access(php_unserialize_data_t *var_hashx, long id, zval ***store) + { + var_entries *var_hash = var_hashx->first; + +@@ -91,6 +115,7 @@ + PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) + { + void *next; ++ long i; + var_entries *var_hash = var_hashx->first; + + while (var_hash) { +@@ -98,6 +123,17 @@ + efree(var_hash); + var_hash = next; + } ++ ++ var_hash = var_hashx->first_dtor; ++ ++ while (var_hash) { ++ for (i = 0; i < var_hash->used_slots; i++) { ++ zval_ptr_dtor(&var_hash->data[i]); ++ } ++ next = var_hash->next; ++ efree(var_hash); ++ var_hash = next; ++ } + } + + /* }}} */ +@@ -119,10 +155,10 @@ + + + +-static inline int parse_iv2(const unsigned char *p, const unsigned char **q) ++static inline long parse_iv2(const unsigned char *p, const unsigned char **q) + { + char cursor; +- int result = 0; ++ long result = 0; + int neg = 0; + + switch (*p) { +@@ -147,7 +183,7 @@ + return result; + } + +-static inline int parse_iv(const unsigned char *p) ++static inline long parse_iv(const unsigned char *p) + { + return parse_iv2(p, NULL); + } +@@ -177,10 +213,10 @@ + #define UNSERIALIZE_PARAMETER zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC + #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC + +-static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, int elements) ++static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long elements) + { + while (elements-- > 0) { +- zval *key, *data, *old_data; ++ zval *key, *data, **old_data; + + ALLOC_INIT_ZVAL(key); + +@@ -208,14 +244,14 @@ + + switch (Z_TYPE_P(key)) { + case IS_LONG: +- if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)) { +- var_replace(var_hash, old_data, rval); ++ if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)==SUCCESS) { ++ var_push_dtor(var_hash, old_data); + } + zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL); + break; + case IS_STRING: +- if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)) { +- var_replace(var_hash, old_data, rval); ++ if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) { ++ var_push_dtor(var_hash, old_data); + } + zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL); + break; +@@ -246,7 +282,7 @@ + + static inline int object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) + { +- int elements; ++ long elements; + + elements = parse_iv2((*p) + 2, p); + +@@ -256,7 +292,7 @@ + return elements; + } + +-static inline int object_common2(UNSERIALIZE_PARAMETER, int elements) ++static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) + { + zval *retval_ptr = NULL; + zval fname; +@@ -308,7 +344,7 @@ + /*!re2c + + "R:" iv ";" { +- int id; ++ long id; + + *p = YYCURSOR; + if (!var_hash) return 0; +@@ -329,7 +365,7 @@ + } + + "r:" iv ";" { +- int id; ++ long id; + + *p = YYCURSOR; + if (!var_hash) return 0; +@@ -375,9 +411,7 @@ + "d:" ("NAN" | "-"? "INF") ";" { + *p = YYCURSOR; + INIT_PZVAL(*rval); +-#if defined(HAVE_ATOF_ACCEPTS_NAN) && defined(HAVE_ATOF_ACCEPTS_INF) +- ZVAL_DOUBLE(*rval, atof(start + 2)); +-#else ++ + if (!strncmp(start + 2, "NAN", 3)) { + ZVAL_DOUBLE(*rval, php_get_nan()); + } else if (!strncmp(start + 2, "INF", 3)) { +@@ -385,14 +419,14 @@ + } else if (!strncmp(start + 2, "-INF", 4)) { + ZVAL_DOUBLE(*rval, -php_get_inf()); + } +-#endif ++ + return 1; + } + + "d:" (iv | nv | nvexp) ";" { + *p = YYCURSOR; + INIT_PZVAL(*rval); +- ZVAL_DOUBLE(*rval, atof(start + 2)); ++ ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); + return 1; + } + +@@ -425,10 +459,18 @@ + } + + "a:" uiv ":" "{" { +- int elements = parse_iv(start + 2); +- ++ long elements = parse_iv(start + 2); ++ /* use iv() not uiv() in order to check data range */ + *p = YYCURSOR; + ++ if (elements < 0) { ++ return 0; ++ } ++ ++ if (elements < 0) { ++ return 0; ++ } ++ + INIT_PZVAL(*rval); + Z_TYPE_PP(rval) = IS_ARRAY; + ALLOC_HASHTABLE(Z_ARRVAL_PP(rval)); +@@ -451,8 +493,8 @@ + } + + "O:" uiv ":" ["] { +- size_t len, len2, maxlen; +- int elements; ++ size_t len, len2, len3, maxlen; ++ long elements; + char *class_name; + zend_class_entry *ce; + int incomplete_class = 0; +@@ -486,6 +528,14 @@ + class_name = str_tolower_copy((char *)emalloc(len+1), class_name, len); + class_name[len] = '\0'; + ++ len3 = strspn(class_name, "0123456789_abcdefghijklmnopqrstuvwxyz"); ++ if (len3 != len) ++ { ++ *p = YYCURSOR + len3 - len; ++ efree(class_name); ++ return 0; ++ } ++ + if (zend_hash_find(CG(class_table), class_name, len + 1, (void **) &ce) != SUCCESS) { + if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) { + incomplete_class = 1; +diff -Nur php-4.3.10/ext/swf/swf.c hardened-php-4.3.10-0.2.7/ext/swf/swf.c +--- php-4.3.10/ext/swf/swf.c 2003-09-12 06:53:39.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/ext/swf/swf.c 2005-04-07 01:51:16.000000000 +0200 +@@ -16,7 +16,7 @@ + +----------------------------------------------------------------------+ + */ + +-/* $Id: swf.c,v 1.46.2.2 2003/09/12 04:53:39 iliaa Exp $ */ ++/* $Id: swf.c,v 1.46.2.4 2004/12/23 18:29:36 iliaa Exp $ */ + + + #ifdef HAVE_CONFIG_H +@@ -239,12 +239,17 @@ + } + na = tmpna; + #endif ++ if (php_check_open_basedir(na TSRMLS_CC) || (PG(safe_mode) && !php_checkuid(na, "wb+", CHECKUID_CHECK_MODE_PARAM))) { ++ goto err; ++ } ++ + if (!SWFG(use_file)) + SWFG(tmpfile_name) = na; + + swf_openfile(na,(float)Z_DVAL_PP(sizeX), (float)Z_DVAL_PP(sizeY), + (float)Z_DVAL_PP(frameRate), (float)Z_DVAL_PP(r), + (float)Z_DVAL_PP(g), (float)Z_DVAL_PP(b)); ++err: + #ifdef VIRTUAL_DIR + free(na); + #endif +@@ -606,8 +611,13 @@ + convert_to_double_ex(width); + + if (Z_TYPE_PP(coordinates) != IS_ARRAY) { +- return; + php_error(E_WARNING, "Wrong datatype of second argument to swf_definepoly"); ++ RETURN_FALSE; ++ } ++ ++ if (Z_LVAL_PP(NumPoints) > 256) { ++ php_error(E_WARNING, "The npoints value cannot be larger then 256."); ++ RETURN_FALSE; + } + + npoints = Z_LVAL_PP(NumPoints); +diff -Nur php-4.3.10/ext/varfilter/CREDITS hardened-php-4.3.10-0.2.7/ext/varfilter/CREDITS +--- php-4.3.10/ext/varfilter/CREDITS 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/varfilter/CREDITS 2005-04-07 01:51:16.000000000 +0200 +@@ -0,0 +1,2 @@ ++varfilter ++Stefan Esser +\ No newline at end of file +diff -Nur php-4.3.10/ext/varfilter/config.m4 hardened-php-4.3.10-0.2.7/ext/varfilter/config.m4 +--- php-4.3.10/ext/varfilter/config.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/varfilter/config.m4 2005-04-07 01:51:16.000000000 +0200 +@@ -0,0 +1,11 @@ ++dnl ++dnl $Id: config.m4,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++dnl ++ ++PHP_ARG_ENABLE(varfilter, whether to enable Hardened-PHP's variable filter, ++[ --disable-varfilter Disable Hardened-PHP's variable filter], yes) ++ ++if test "$PHP_VARFILTER" != "no"; then ++ AC_DEFINE(HAVE_VARFILTER, 1, [ ]) ++ PHP_NEW_EXTENSION(varfilter, varfilter.c, $ext_shared) ++fi +diff -Nur php-4.3.10/ext/varfilter/php_varfilter.h hardened-php-4.3.10-0.2.7/ext/varfilter/php_varfilter.h +--- php-4.3.10/ext/varfilter/php_varfilter.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/varfilter/php_varfilter.h 2005-04-07 01:51:16.000000000 +0200 +@@ -0,0 +1,72 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 4 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2003 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: php_varfilter.h,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifndef PHP_VARFILTER_H ++#define PHP_VARFILTER_H ++ ++extern zend_module_entry varfilter_module_entry; ++#define phpext_varfilter_ptr &varfilter_module_entry ++ ++#ifdef PHP_WIN32 ++#define PHP_VARFILTER_API __declspec(dllexport) ++#else ++#define PHP_VARFILTER_API ++#endif ++ ++#ifdef ZTS ++#include "TSRM.h" ++#endif ++ ++#include "SAPI.h" ++ ++PHP_MINIT_FUNCTION(varfilter); ++PHP_MSHUTDOWN_FUNCTION(varfilter); ++PHP_RINIT_FUNCTION(varfilter); ++PHP_RSHUTDOWN_FUNCTION(varfilter); ++PHP_MINFO_FUNCTION(varfilter); ++ ++ ++ZEND_BEGIN_MODULE_GLOBALS(varfilter) ++ long max_request_variables; ++ long cur_request_variables; ++ long max_varname_length; ++ long max_value_length; ++ long max_array_depth; ++ZEND_END_MODULE_GLOBALS(varfilter) ++ ++ ++#ifdef ZTS ++#define VARFILTER_G(v) TSRMG(varfilter_globals_id, zend_varfilter_globals *, v) ++#else ++#define VARFILTER_G(v) (varfilter_globals.v) ++#endif ++ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter); ++ ++#endif /* PHP_VARFILTER_H */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * indent-tabs-mode: t ++ * End: ++ */ +diff -Nur php-4.3.10/ext/varfilter/varfilter.c hardened-php-4.3.10-0.2.7/ext/varfilter/varfilter.c +--- php-4.3.10/ext/varfilter/varfilter.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/ext/varfilter/varfilter.c 2005-04-07 01:51:16.000000000 +0200 +@@ -0,0 +1,196 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 4 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2003 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: | ++ +----------------------------------------------------------------------+ ++ ++ $Id: varfilter.c,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "php.h" ++#include "php_ini.h" ++#include "ext/standard/info.h" ++#include "php_varfilter.h" ++#include "hardened_php.h" ++ ++ZEND_DECLARE_MODULE_GLOBALS(varfilter) ++ ++/* True global resources - no need for thread safety here */ ++static int le_varfilter; ++ ++/* {{{ varfilter_module_entry ++ */ ++zend_module_entry varfilter_module_entry = { ++#if ZEND_MODULE_API_NO >= 20010901 ++ STANDARD_MODULE_HEADER, ++#endif ++ "varfilter", ++ NULL, ++ PHP_MINIT(varfilter), ++ PHP_MSHUTDOWN(varfilter), ++ PHP_RINIT(varfilter), /* Replace with NULL if there's nothing to do at request start */ ++ PHP_RSHUTDOWN(varfilter), /* Replace with NULL if there's nothing to do at request end */ ++ PHP_MINFO(varfilter), ++#if ZEND_MODULE_API_NO >= 20010901 ++ "0.2.0", /* Replace with version number for your extension */ ++#endif ++ STANDARD_MODULE_PROPERTIES ++}; ++/* }}} */ ++ ++#ifdef COMPILE_DL_VARFILTER ++ZEND_GET_MODULE(varfilter) ++#endif ++ ++/* {{{ PHP_INI ++ */ ++PHP_INI_BEGIN() ++ STD_PHP_INI_ENTRY("varfilter.max_request_variables", "200", PHP_INI_SYSTEM, OnUpdateInt, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_varname_length", "64", PHP_INI_SYSTEM, OnUpdateInt, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_value_length", "10000", PHP_INI_SYSTEM, OnUpdateInt, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_depth", "100", PHP_INI_SYSTEM, OnUpdateInt, max_array_depth, zend_varfilter_globals, varfilter_globals) ++PHP_INI_END() ++/* }}} */ ++ ++/* {{{ php_varfilter_init_globals ++ */ ++static void php_varfilter_init_globals(zend_varfilter_globals *varfilter_globals) ++{ ++ varfilter_globals->max_request_variables = 200; ++ varfilter_globals->cur_request_variables = 0; ++ varfilter_globals->max_varname_length = 64; ++ varfilter_globals->max_value_length = 10000; ++ varfilter_globals->max_array_depth = 100; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINIT_FUNCTION ++ */ ++PHP_MINIT_FUNCTION(varfilter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(varfilter, php_varfilter_init_globals, NULL); ++ REGISTER_INI_ENTRIES(); ++ ++ sapi_register_input_filter(varfilter_input_filter); ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MSHUTDOWN_FUNCTION ++ */ ++PHP_MSHUTDOWN_FUNCTION(varfilter) ++{ ++ UNREGISTER_INI_ENTRIES(); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request start */ ++/* {{{ PHP_RINIT_FUNCTION ++ */ ++PHP_RINIT_FUNCTION(varfilter) ++{ ++ VARFILTER_G(cur_request_variables) = 0; ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request end */ ++/* {{{ PHP_RSHUTDOWN_FUNCTION ++ */ ++PHP_RSHUTDOWN_FUNCTION(varfilter) ++{ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINFO_FUNCTION ++ */ ++PHP_MINFO_FUNCTION(varfilter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_header(2, "Hardened-PHP's variable filter support", "enabled"); ++ php_info_print_table_end(); ++ ++ DISPLAY_INI_ENTRIES(); ++} ++/* }}} */ ++ ++/* {{{ SAPI_INPUT_FILTER_FUNC ++ */ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter) ++{ ++ char *index; ++ unsigned int var_len, depth = 0; ++ ++ /* Drop this variable if the limit is reached */ ++ if (VARFILTER_G(max_request_variables) == VARFILTER_G(cur_request_variables)) { ++ php_security_log("tried to register too many variables"); ++ return 0; ++ } ++ ++ /* Drop this variable if it exceeds the value length limit */ ++ if (VARFILTER_G(max_value_length) < val_len) { ++ php_security_log("tried to register a variable with a too long value"); ++ return 0; ++ } ++ ++ /* Find length of variable name */ ++ index = strchr(var, '['); ++ var_len = index ? index-var : strlen(var); ++ ++ /* Drop this variable if it exceeds the varname length limit */ ++ if (VARFILTER_G(max_varname_length) < var_len) { ++ php_security_log("tried to register a variable with a too long variable name"); ++ return 0; ++ } ++ ++ /* Find out array depth */ ++ while (index) { ++ depth++; ++ index = strchr(index+1, '['); ++ } ++ ++ /* Drop this variable if it exceeds the array depth limit */ ++ if (VARFILTER_G(max_array_depth) < depth) { ++ php_security_log("tried to register a too deep array variable"); ++ return 0; ++ } ++ ++ /* Okay let PHP register this variable */ ++ VARFILTER_G(cur_request_variables)++; ++ ++ if (new_val_len) { ++ *new_val_len = val_len; ++ } ++ ++ return 1; ++} ++/* }}} */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: noet sw=4 ts=4 fdm=marker ++ * vim<600: noet sw=4 ts=4 ++ */ +diff -Nur php-4.3.10/main/SAPI.c hardened-php-4.3.10-0.2.7/main/SAPI.c +--- php-4.3.10/main/SAPI.c 2004-08-19 22:35:36.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/main/SAPI.c 2005-04-07 01:51:16.000000000 +0200 +@@ -823,6 +823,12 @@ + return SUCCESS; + } + ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) ++{ ++ sapi_module.input_filter = input_filter; ++ return SUCCESS; ++} ++ + + SAPI_API int sapi_flush(TSRMLS_D) + { +diff -Nur php-4.3.10/main/SAPI.h hardened-php-4.3.10-0.2.7/main/SAPI.h +--- php-4.3.10/main/SAPI.h 2003-04-09 22:27:55.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/main/SAPI.h 2005-04-07 01:51:16.000000000 +0200 +@@ -101,9 +101,14 @@ + char *current_user; + int current_user_length; + +- /* this is necessary for CLI module */ +- int argc; +- char **argv; ++ /* this is necessary for CLI module */ ++ int argc; ++ char **argv; ++ ++#if HARDENED_PHP ++ /* this is necessary for IP logging */ ++ char ip_address[64]; ++#endif + } sapi_request_info; + + +@@ -177,6 +182,7 @@ + SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry); + SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D)); + SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC)); ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)); + + SAPI_API int sapi_flush(TSRMLS_D); + SAPI_API struct stat *sapi_get_stat(TSRMLS_D); +@@ -238,8 +244,11 @@ + int (*get_target_uid)(uid_t * TSRMLS_DC); + int (*get_target_gid)(gid_t * TSRMLS_DC); + ++ unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); ++ + void (*ini_defaults)(HashTable *configuration_hash); + int phpinfo_as_text; ++ + }; + + +@@ -262,16 +271,23 @@ + + #define SAPI_DEFAULT_MIMETYPE "text/html" + #define SAPI_DEFAULT_CHARSET "" ++ ++#if HARDENED_PHP ++#define SAPI_PHP_VERSION_HEADER "X-Powered-By: Hardened-PHP/" PHP_VERSION ++#else + #define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION ++#endif + + #define SAPI_POST_READER_FUNC(post_reader) void post_reader(TSRMLS_D) + #define SAPI_POST_HANDLER_FUNC(post_handler) void post_handler(char *content_type_dup, void *arg TSRMLS_DC) + + #define SAPI_TREAT_DATA_FUNC(treat_data) void treat_data(int arg, char *str, zval* destArray TSRMLS_DC) ++#define SAPI_INPUT_FILTER_FUNC(input_filter) unsigned int input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) + + SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data); + SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader); + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data); ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter); + + #define STANDARD_SAPI_MODULE_PROPERTIES + +diff -Nur php-4.3.10/main/fopen_wrappers.c hardened-php-4.3.10-0.2.7/main/fopen_wrappers.c +--- php-4.3.10/main/fopen_wrappers.c 2004-03-16 01:32:09.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/main/fopen_wrappers.c 2005-04-07 01:51:16.000000000 +0200 +@@ -16,7 +16,7 @@ + | Jim Winstead | + +----------------------------------------------------------------------+ + */ +-/* $Id: fopen_wrappers.c,v 1.153.2.9 2004/03/16 00:32:09 iliaa Exp $ */ ++/* $Id: fopen_wrappers.c,v 1.153.2.10 2005/02/02 23:44:07 iliaa Exp $ */ + + /* {{{ includes + */ +@@ -106,24 +106,11 @@ + char resolved_name[MAXPATHLEN]; + char resolved_basedir[MAXPATHLEN]; + char local_open_basedir[MAXPATHLEN]; +- int local_open_basedir_pos; + int resolved_basedir_len; + int resolved_name_len; + + /* Special case basedir==".": Use script-directory */ +- if ((strcmp(basedir, ".") == 0) && +- SG(request_info).path_translated && +- *SG(request_info).path_translated +- ) { +- strlcpy(local_open_basedir, SG(request_info).path_translated, sizeof(local_open_basedir)); +- local_open_basedir_pos = strlen(local_open_basedir) - 1; +- +- /* Strip filename */ +- while (!IS_SLASH(local_open_basedir[local_open_basedir_pos]) +- && (local_open_basedir_pos >= 0)) { +- local_open_basedir[local_open_basedir_pos--] = 0; +- } +- } else { ++ if (strcmp(basedir, ".") || !VCWD_GETCWD(local_open_basedir, MAXPATHLEN)) { + /* Else use the unmodified path */ + strlcpy(local_open_basedir, basedir, sizeof(local_open_basedir)); + } +@@ -179,6 +166,21 @@ + char *pathbuf; + char *ptr; + char *end; ++ char path_copy[MAXPATHLEN]; ++ int path_len; ++ ++ /* Special case path ends with a trailing slash */ ++ path_len = strlen(path); ++ if (path_len >= MAXPATHLEN) { ++ errno = EPERM; /* we deny permission to open it */ ++ return -1; ++ } ++ if (path_len > 0 && path[path_len-1] == PHP_DIR_SEPARATOR) { ++ memcpy(path_copy, path, path_len+1); ++ while (path_len > 0 && path_copy[path_len-1] == PHP_DIR_SEPARATOR) path_len--; ++ path_copy[path_len] = '\0'; ++ path = (const char *)&path_copy; ++ } + + pathbuf = estrdup(PG(open_basedir)); + +diff -Nur php-4.3.10/main/hardened_globals.h hardened-php-4.3.10-0.2.7/main/hardened_globals.h +--- php-4.3.10/main/hardened_globals.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/main/hardened_globals.h 2005-04-07 01:51:16.000000000 +0200 +@@ -0,0 +1,54 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_GLOBALS_H ++#define HARDENED_GLOBALS_H ++ ++typedef struct _hardened_globals hardened_globals_struct; ++ ++#ifdef ZTS ++# define HG(v) TSRMG(hardened_globals_id, hardened_globals_struct *, v) ++extern int hardened_globals_id; ++#else ++# define HG(v) (hardened_globals.v) ++extern struct _hardened_globals hardened_globals; ++#endif ++ ++ ++struct _hardened_globals { ++#if HARDENED_PHP_MM_PROTECT ++ unsigned int canary_1; ++ unsigned int canary_2; ++#endif ++#if HARDENED_PHP_LL_PROTECT ++ unsigned int canary_3; ++ unsigned int canary_4; ++ unsigned int ll_canary_inited; ++#endif ++ unsigned int dummy; ++}; ++ ++ ++#endif /* HARDENED_GLOBALS_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nur php-4.3.10/main/hardened_php.c hardened-php-4.3.10-0.2.7/main/hardened_php.c +--- php-4.3.10/main/hardened_php.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/main/hardened_php.c 2005-04-07 01:51:16.000000000 +0200 +@@ -0,0 +1,205 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: hardened_php.c,v 1.2 2004/11/21 09:38:52 ionic Exp $ */ ++ ++#include "php.h" ++ ++#include ++#include ++ ++#if HAVE_UNISTD_H ++#include ++#endif ++#include "SAPI.h" ++#include "php_globals.h" ++ ++#if HARDENED_PHP ++ ++#ifdef HAVE_SYS_SOCKET_H ++#include ++#endif ++ ++#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE) ++#undef AF_UNIX ++#endif ++ ++#if defined(AF_UNIX) ++#include ++#endif ++ ++#define SYSLOG_PATH "/dev/log" ++ ++#include "snprintf.h" ++ ++#ifdef ZTS ++#include "hardened_globals.h" ++int hardened_globals_id; ++#else ++struct _hardened_globals hardened_globals; ++#endif ++ ++static void hardened_globals_ctor(hardened_globals_struct *hardened_globals TSRMLS_DC) ++{ ++ memset(hardened_globals, 0, sizeof(*hardened_globals)); ++} ++ ++PHPAPI void hardened_startup() ++{ ++#ifdef ZTS ++ ts_allocate_id(&hardened_globals_id, sizeof(hardened_globals_struct), (ts_allocate_ctor) hardened_globals_ctor, NULL); ++#else ++ hardened_globals_ctor(&hardened_globals TSRMLS_CC); ++#endif ++} ++ ++PHPAPI void php_security_log(char *str) ++{ ++#if defined(AF_UNIX) ++ int s, r; ++ struct sockaddr_un saun; ++ char buf[1024]; ++ char *ip_address; ++ char *fname; ++ TSRMLS_FETCH(); ++ ++ ip_address = sapi_getenv("REMOTE_ADDR", 11 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "REMOTE_ADDR not set"; ++ } ++ ++ fname = sapi_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC); ++ ++ ap_php_snprintf(buf, 1024, "php security-alert: %s (attacker '%s', file '%s')\n", str, ip_address, fname); ++ ++ s = socket(AF_UNIX, SOCK_DGRAM, 0); ++ if (s == -1) { ++ return; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ s = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (s == -1) { ++ return; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ return; ++ } ++ } ++ send(s, buf, strlen(buf), 0); ++ ++ close(s); ++#endif ++} ++#endif ++ ++#if HARDENED_PHP_MM_PROTECT || HARDENED_PHP_LL_PROTECT || HARDENED_PHP_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++PHPAPI unsigned int php_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++#if HARDENED_PHP_INC_PROTECT ++ ++PHPAPI int php_is_valid_include(zval *z) ++{ ++ char *filename; ++ int len; ++ TSRMLS_FETCH(); ++ ++ /* must be of type string */ ++ if (z->type != IS_STRING || z->value.str.val == NULL) { ++ return (0); ++ } ++ ++ /* short cut */ ++ filename = z->value.str.val; ++ len = z->value.str.len; ++ ++ /* 1. must be shorter than MAXPATHLEN */ ++ if (len > MAXPATHLEN) { ++ php_security_log("Include filename longer than MAXPATHLEN chars"); ++ return (0); ++ } ++ ++ /* 2. must not be cutted */ ++ if (len != strlen(filename)) { ++ php_security_log("Include filename has a \\0 cut"); ++ return (0); ++ } ++ ++ /* 3. must not be a URL */ ++ if (strstr(filename, "://")) { ++ php_security_log("Include filename is an URL"); ++ return (0); ++ } ++ ++ /* 4. must not be an uploaded file */ ++ if (SG(rfc1867_uploaded_files)) { ++ if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, len+1)) { ++ php_security_log("Include filename is an uploaded file"); ++ return (0); ++ } ++ } ++ ++ /* passed all tests */ ++ return (1); ++} ++ ++#endif ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nur php-4.3.10/main/hardened_php.h hardened-php-4.3.10-0.2.7/main/hardened_php.h +--- php-4.3.10/main/hardened_php.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/main/hardened_php.h 2005-04-07 01:51:16.000000000 +0200 +@@ -0,0 +1,45 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_PHP_H ++#define HARDENED_PHP_H ++ ++#include "zend.h" ++ ++#if HARDENED_PHP ++PHPAPI void php_security_log(char *str); ++PHPAPI void hardened_startup(); ++#define HARDENED_PHP_VERSION "0.2.7" ++#endif ++ ++#if HARDENED_PHP_MM_PROTECT || HARDENED_PHP_LL_PROTECT || HARDENED_PHP_HASH_PROTECT ++PHPAPI unsigned int php_canary(); ++#endif ++ ++#if HARDENED_PHP_INC_PROTECT ++PHPAPI int php_is_valid_include(zval *z); ++#endif ++ ++#endif /* HARDENED_PHP_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nur php-4.3.10/main/hardened_php.m4 hardened-php-4.3.10-0.2.7/main/hardened_php.m4 +--- php-4.3.10/main/hardened_php.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/main/hardened_php.m4 2005-04-07 01:51:16.000000000 +0200 +@@ -0,0 +1,95 @@ ++dnl ++dnl $Id: hardened_php.m4,v 1.1 2004/11/14 13:24:24 ionic Exp $ ++dnl ++dnl This file contains Hardened-PHP specific autoconf functions. ++dnl ++ ++AC_ARG_ENABLE(hardened-php-mm-protect, ++[ --disable-hardened-php-mm-protect Disable the Memory Manager protection.],[ ++ DO_HARDENED_PHP_MM_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_MM_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardened-php-ll-protect, ++[ --disable-hardened-php-ll-protect Disable the Linked List protection.],[ ++ DO_HARDENED_PHP_LL_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_LL_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardened-php-inc-protect, ++[ --disable-hardened-php-inc-protect Disable include/require protection.],[ ++ DO_HARDENED_PHP_INC_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_INC_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardened-php-fmt-protect, ++[ --disable-hardened-php-fmt-protect Disable format string protection.],[ ++ DO_HARDENED_PHP_FMT_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_FMT_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardened-php-hash-protect, ++[ --disable-hardened-php-hash-protect Disable HashTable destructor protection.],[ ++ DO_HARDENED_PHP_HASH_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_HASH_PROTECT=yes ++]) ++ ++AC_MSG_CHECKING(whether to protect the Zend Memory Manager) ++AC_MSG_RESULT($DO_HARDENED_PHP_MM_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the Zend Linked Lists) ++AC_MSG_RESULT($DO_HARDENED_PHP_LL_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect include/require statements) ++AC_MSG_RESULT($DO_HARDENED_PHP_INC_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect PHP Format String functions) ++AC_MSG_RESULT($DO_HARDENED_PHP_FMT_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the destructor of Zend HashTables) ++AC_MSG_RESULT($DO_HARDENED_PHP_HASH_PROTECT) ++ ++ ++AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ ++ ++if test "$DO_HARDENED_PHP_MM_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_MM_PROTECT, 1, [Memory Manager Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_MM_PROTECT, 0, [Memory Manager Protection]) ++fi ++ ++if test "$DO_HARDENED_PHP_LL_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_LL_PROTECT, 1, [Linked List Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_LL_PROTECT, 0, [Linked List Protection]) ++fi ++ ++if test "$DO_HARDENED_PHP_INC_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_INC_PROTECT, 1, [Include/Require Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_INC_PROTECT, 0, [Include/Require Protection]) ++fi ++ ++if test "$DO_HARDENED_PHP_FMT_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_FMT_PROTECT, 1, [Fmt String Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_FMT_PROTECT, 0, [Fmt String Protection]) ++fi ++ ++if test "$DO_HARDENED_PHP_HASH_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_HASH_PROTECT, 1, [HashTable DTOR Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_HASH_PROTECT, 0, [HashTable DTOR Protection]) ++fi ++ +diff -Nur php-4.3.10/main/main.c hardened-php-4.3.10-0.2.7/main/main.c +--- php-4.3.10/main/main.c 2004-10-01 16:27:13.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/main/main.c 2005-04-07 01:51:16.000000000 +0200 +@@ -100,6 +100,10 @@ + PHPAPI int core_globals_id; + #endif + ++#if HARDENED_PHP ++#include "hardened_globals.h" ++#endif ++ + #define ERROR_BUF_LEN 1024 + + typedef struct { +@@ -150,10 +154,33 @@ + */ + static PHP_INI_MH(OnChangeMemoryLimit) + { ++#if HARDENED_PHP ++ long orig_memory_limit; ++ ++ if (entry->modified) { ++ orig_memory_limit = zend_atoi(entry->orig_value, entry->orig_value_length); ++ } else { ++ orig_memory_limit = 1<<30; ++ } ++ if (orig_memory_limit < 0 || orig_memory_limit > (1<<30)) { ++ orig_memory_limit = 1<<30; ++ } ++#endif + if (new_value) { + PG(memory_limit) = zend_atoi(new_value, new_value_length); ++#if HARDENED_PHP ++ if (PG(memory_limit) > orig_memory_limit) { ++ PG(memory_limit) = orig_memory_limit; ++ php_security_log("script tried to increase memory_limit above allowed value"); ++ return FAILURE; ++ } ++#endif + } else { ++#if HARDENED_PHP ++ PG(memory_limit) = orig_memory_limit; ++#else + PG(memory_limit) = 1<<30; /* effectively, no limit */ ++#endif + } + return zend_set_memory_limit(PG(memory_limit)); + } +@@ -1091,6 +1118,10 @@ + tsrm_ls = ts_resource(0); + #endif + ++#if HARDENED_PHP ++ hardened_startup(); ++#endif ++ + sapi_initialize_empty_request(TSRMLS_C); + sapi_activate(TSRMLS_C); + +@@ -1103,6 +1134,12 @@ + php_output_startup(); + php_output_activate(TSRMLS_C); + ++#if HARDENED_PHP_INC_PROTECT ++ zuf.is_valid_include = php_is_valid_include; ++#endif ++#if HARDENED_PHP ++ zuf.security_log_function = php_security_log; ++#endif + zuf.error_function = php_error_cb; + zuf.printf_function = php_printf; + zuf.write_function = php_body_write_wrapper; +@@ -1204,6 +1241,10 @@ + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, sizeof(PHP_CONFIG_FILE_PATH)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS); ++#if HARDENED_PHP ++ REGISTER_MAIN_LONG_CONSTANT("HARDENED_PHP", 1, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_STRINGL_CONSTANT("HARDENED_PHP_VERSION", HARDENED_PHP_VERSION, sizeof(HARDENED_PHP_VERSION)-1, CONST_PERSISTENT | CONST_CS); ++#endif + REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS); + php_output_register_constants(TSRMLS_C); + php_rfc1867_register_constants(TSRMLS_C); +@@ -1339,6 +1380,7 @@ + ulong num_key; + HashPosition pos; + int key_type; ++ int globals_check = (PG(register_globals) && (dest == (&EG(symbol_table)))); + + zend_hash_internal_pointer_reset_ex(src, &pos); + while (zend_hash_get_current_data_ex(src, (void **)&src_entry, &pos) == SUCCESS) { +@@ -1349,7 +1391,12 @@ + || Z_TYPE_PP(dest_entry) != IS_ARRAY) { + (*src_entry)->refcount++; + if (key_type == HASH_KEY_IS_STRING) { +- zend_hash_update(dest, string_key, strlen(string_key)+1, src_entry, sizeof(zval *), NULL); ++ /* if register_globals is on and working with main symbol table, prevent overwriting of GLOBALS */ ++ if (!globals_check || string_key_len != sizeof("GLOBALS") || memcmp(string_key, "GLOBALS", sizeof("GLOBALS") - 1)) { ++ zend_hash_update(dest, string_key, string_key_len, src_entry, sizeof(zval *), NULL); ++ } else { ++ (*src_entry)->refcount--; ++ } + } else { + zend_hash_index_update(dest, num_key, src_entry, sizeof(zval *), NULL); + } +diff -Nur php-4.3.10/main/php.h hardened-php-4.3.10-0.2.7/main/php.h +--- php-4.3.10/main/php.h 2004-11-28 13:44:56.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/main/php.h 2005-04-07 01:51:16.000000000 +0200 +@@ -35,11 +35,19 @@ + #include "zend_qsort.h" + #include "php_compat.h" + ++ + #include "zend_API.h" + + #undef sprintf + #define sprintf php_sprintf + ++#if HARDENED_PHP ++#if HAVE_REALPATH ++#undef realpath ++#define realpath php_realpath ++#endif ++#endif ++ + /* PHP's DEBUG value must match Zend's ZEND_DEBUG value */ + #undef PHP_DEBUG + #define PHP_DEBUG ZEND_DEBUG +@@ -436,6 +444,10 @@ + #endif + #endif /* !XtOffsetOf */ + ++#if HARDENED_PHP ++#include "hardened_php.h" ++#endif ++ + #endif + + /* +diff -Nur php-4.3.10/main/php_config.h.in hardened-php-4.3.10-0.2.7/main/php_config.h.in +--- php-4.3.10/main/php_config.h.in 2004-12-14 18:55:22.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/main/php_config.h.in 2005-04-07 01:51:16.000000000 +0200 +@@ -834,6 +834,39 @@ + /* Enabling BIND8 compatibility for Panther */ + #undef BIND_8_COMPAT + ++/* Hardened-PHP */ ++#undef HARDENED_PHP ++ ++/* Memory Manager Protection */ ++#undef HARDENED_PHP_MM_PROTECT ++ ++/* Memory Manager Protection */ ++#undef HARDENED_PHP_MM_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENED_PHP_LL_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENED_PHP_LL_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENED_PHP_INC_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENED_PHP_INC_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENED_PHP_FMT_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENED_PHP_FMT_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENED_PHP_HASH_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENED_PHP_HASH_PROTECT ++ + /* Whether you have AOLserver */ + #undef HAVE_AOLSERVER + +@@ -1117,6 +1150,12 @@ + /* Define if you have the getaddrinfo function */ + #undef HAVE_GETADDRINFO + ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ + /* Whether system headers declare timezone */ + #undef HAVE_DECLARED_TIMEZONE + +diff -Nur php-4.3.10/main/php_content_types.c hardened-php-4.3.10-0.2.7/main/php_content_types.c +--- php-4.3.10/main/php_content_types.c 2002-12-31 17:26:14.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/main/php_content_types.c 2005-04-07 01:51:16.000000000 +0200 +@@ -77,6 +77,7 @@ + sapi_register_post_entries(php_post_entries); + sapi_register_default_post_reader(php_default_post_reader); + sapi_register_treat_data(php_default_treat_data); ++ sapi_register_input_filter(php_default_input_filter); + return SUCCESS; + } + /* }}} */ +diff -Nur php-4.3.10/main/php_variables.c hardened-php-4.3.10-0.2.7/main/php_variables.c +--- php-4.3.10/main/php_variables.c 2004-10-18 17:08:46.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/main/php_variables.c 2005-04-07 01:51:16.000000000 +0200 +@@ -211,17 +211,28 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(PARSE_POST, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, "&", &strtok_buf); + } + } + ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter) ++{ ++ /* TODO: check .ini setting here and apply user-defined input filter */ ++ *new_val_len = val_len; ++ return 1; ++} ++ + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) + { + char *res = NULL, *var, *val, *separator=NULL; +@@ -299,15 +310,26 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } else { ++ unsigned int val_len, new_val_len; ++ + php_url_decode(var, strlen(var)); +- php_register_variable_safe(var, "", 0, array_ptr TSRMLS_CC); ++ val_len = 0; ++ val = estrndup("", 0); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, separator, &strtok_buf); + } +diff -Nur php-4.3.10/main/rfc1867.c hardened-php-4.3.10-0.2.7/main/rfc1867.c +--- php-4.3.10/main/rfc1867.c 2004-11-20 21:16:44.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/main/rfc1867.c 2005-04-07 01:51:16.000000000 +0200 +@@ -891,21 +891,24 @@ + if (!filename && param) { + + char *value = multipart_buffer_read_body(mbuff TSRMLS_CC); ++ unsigned int new_val_len; /* Dummy variable */ + + if (!value) { + value = estrdup(""); + } + ++ if (sapi_module.input_filter(PARSE_POST, param, &value, strlen(value), &new_val_len TSRMLS_CC)) { + #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) +- if (php_mb_encoding_translation(TSRMLS_C)) { +- php_mb_gpc_stack_variable(param, value, &val_list, &len_list, +- &num_vars, &num_vars_max TSRMLS_CC); +- } else { +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); +- } ++ if (php_mb_encoding_translation(TSRMLS_C)) { ++ php_mb_gpc_stack_variable(param, value, &val_list, &len_list, ++ &num_vars, &num_vars_max TSRMLS_CC); ++ } else { ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ } + #else +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); + #endif ++ } + if (!strcasecmp(param, "MAX_FILE_SIZE")) { + max_file_size = atol(value); + } +diff -Nur php-4.3.10/main/snprintf.c hardened-php-4.3.10-0.2.7/main/snprintf.c +--- php-4.3.10/main/snprintf.c 2004-11-16 00:27:26.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/main/snprintf.c 2005-04-07 01:51:16.000000000 +0200 +@@ -850,7 +850,11 @@ + + + case 'n': ++#if HARDENED_PHP_FMT_PROTECT ++ php_security_log("'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Nur php-4.3.10/main/spprintf.c hardened-php-4.3.10-0.2.7/main/spprintf.c +--- php-4.3.10/main/spprintf.c 2003-09-29 03:09:36.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/main/spprintf.c 2005-04-07 01:51:16.000000000 +0200 +@@ -531,7 +531,11 @@ + + + case 'n': ++#if HARDENED_PHP_FMT_PROTECT ++ php_security_log("'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Nur php-4.3.10/php.ini-dist hardened-php-4.3.10-0.2.7/php.ini-dist +--- php-4.3.10/php.ini-dist 2004-08-18 07:05:23.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/php.ini-dist 2005-04-07 01:51:16.000000000 +0200 +@@ -1113,6 +1113,23 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[varfilter] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardened-PHP's variable filter ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Maximum number of input variables per request ++varfilter.max_request_variables = 200 ++ ++; Maximum characters in input variable names ++varfilter.max_varname_length = 64 ++ ++; Maximum length of input variable values ++varfilter.max_value_length = 10000 ++ ++; Maximum depth of input variable arrays ++varfilter.max_array_depth = 100 ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nur php-4.3.10/php.ini-recommended hardened-php-4.3.10-0.2.7/php.ini-recommended +--- php-4.3.10/php.ini-recommended 2004-08-18 07:05:23.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/php.ini-recommended 2005-04-07 01:51:16.000000000 +0200 +@@ -1111,6 +1111,23 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[varfilter] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardened-PHP's variable filter ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Maximum number of input variables per request ++varfilter.max_request_variables = 200 ++ ++; Maximum characters in input variable names ++varfilter.max_varname_length = 64 ++ ++; Maximum length of input variable values ++varfilter.max_value_length = 10000 ++ ++; Maximum depth of input variable arrays ++varfilter.max_array_depth = 100 ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nur php-4.3.10/sapi/apache/mod_php4.c hardened-php-4.3.10-0.2.7/sapi/apache/mod_php4.c +--- php-4.3.10/sapi/apache/mod_php4.c 2004-07-21 18:25:28.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/sapi/apache/mod_php4.c 2005-04-07 01:51:16.000000000 +0200 +@@ -446,7 +446,7 @@ + sapi_apache_get_fd, + sapi_apache_force_http_10, + sapi_apache_get_target_uid, +- sapi_apache_get_target_gid ++ sapi_apache_get_target_gid, + }; + /* }}} */ + +@@ -892,7 +892,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENED_PHP ++ ap_add_version_component("Hardened-PHP/" PHP_VERSION); ++#else + ap_add_version_component("PHP/" PHP_VERSION); ++#endif + } + } + #endif +diff -Nur php-4.3.10/sapi/apache2filter/sapi_apache2.c hardened-php-4.3.10-0.2.7/sapi/apache2filter/sapi_apache2.c +--- php-4.3.10/sapi/apache2filter/sapi_apache2.c 2004-06-18 02:37:02.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/sapi/apache2filter/sapi_apache2.c 2005-04-07 01:51:16.000000000 +0200 +@@ -560,7 +560,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENED_PHP ++ ap_add_version_component(p, "Hardened-PHP/" PHP_VERSION); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nur php-4.3.10/sapi/apache2handler/sapi_apache2.c hardened-php-4.3.10-0.2.7/sapi/apache2handler/sapi_apache2.c +--- php-4.3.10/sapi/apache2handler/sapi_apache2.c 2004-12-06 19:55:16.000000000 +0100 ++++ hardened-php-4.3.10-0.2.7/sapi/apache2handler/sapi_apache2.c 2005-04-07 01:51:16.000000000 +0200 +@@ -337,7 +337,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENED_PHP ++ ap_add_version_component(p, "Hardened-PHP/" PHP_VERSION); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nur php-4.3.10/sapi/cgi/cgi_main.c hardened-php-4.3.10-0.2.7/sapi/cgi/cgi_main.c +--- php-4.3.10/sapi/cgi/cgi_main.c 2004-07-15 00:38:18.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/sapi/cgi/cgi_main.c 2005-04-07 01:51:16.000000000 +0200 +@@ -1426,11 +1426,19 @@ + SG(headers_sent) = 1; + SG(request_info).no_headers = 1; + } ++#if HARDENED_PHP ++#if ZEND_DEBUG ++ php_printf("Hardened-PHP %s/%s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENED_PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("Hardened-PHP %s/%s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENED_PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit(1); + break; +diff -Nur php-4.3.10/sapi/cli/php_cli.c hardened-php-4.3.10-0.2.7/sapi/cli/php_cli.c +--- php-4.3.10/sapi/cli/php_cli.c 2004-07-15 00:38:18.000000000 +0200 ++++ hardened-php-4.3.10-0.2.7/sapi/cli/php_cli.c 2005-04-07 01:51:16.000000000 +0200 +@@ -646,11 +646,19 @@ + if (php_request_startup(TSRMLS_C)==FAILURE) { + goto err; + } ++#if HARDENED_PHP ++#if ZEND_DEBUG ++ php_printf("Hardened-PHP %s/%s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENED_PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("Hardened-PHP %s/%s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENED_PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit_status=1; + goto out; diff --git a/0.2.7/hardened-php-4.3.11-0.2.7.patch b/0.2.7/hardened-php-4.3.11-0.2.7.patch new file mode 100644 index 0000000..d91abe4 --- /dev/null +++ b/0.2.7/hardened-php-4.3.11-0.2.7.patch @@ -0,0 +1,3417 @@ +diff -Nur php-4.3.11/README.input_filter hardened-php-4.3.11-0.2.7/README.input_filter +--- php-4.3.11/README.input_filter 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/README.input_filter 2005-04-07 02:08:26.000000000 +0200 +@@ -0,0 +1,193 @@ ++Input Filter Support ported from PHP 5 ++-------------------------------------- ++ ++XSS (Cross Site Scripting) hacks are becoming more and more prevalent, ++and can be quite difficult to prevent. Whenever you accept user data ++and somehow display this data back to users, you are likely vulnerable ++to XSS hacks. ++ ++The Input Filter support in PHP 5 is aimed at providing the framework ++through which a company-wide or site-wide security policy can be ++enforced. It is implemented as a SAPI hook and is called from the ++treat_data and post handler functions. To implement your own security ++policy you will need to write a standard PHP extension. ++ ++A simple implementation might look like the following. This stores the ++original raw user data and adds a my_get_raw() function while the normal ++$_POST, $_GET and $_COOKIE arrays are only populated with stripped ++data. In this simple example all I am doing is calling strip_tags() on ++the data. If register_globals is turned on, the default globals that ++are created will be stripped ($foo) while a $RAW_foo is created with the ++original user input. ++ ++ZEND_BEGIN_MODULE_GLOBALS(my_input_filter) ++ zval *post_array; ++ zval *get_array; ++ zval *cookie_array; ++ZEND_END_MODULE_GLOBALS(my_input_filter) ++ ++#ifdef ZTS ++#define IF_G(v) TSRMG(my_input_filter_globals_id, zend_my_input_filter_globals *, v) ++#else ++#define IF_G(v) (my_input_filter_globals.v) ++#endif ++ ++ZEND_DECLARE_MODULE_GLOBALS(my_input_filter) ++ ++function_entry my_input_filter_functions[] = { ++ PHP_FE(my_get_raw, NULL) ++ {NULL, NULL, NULL} ++}; ++ ++zend_module_entry my_input_filter_module_entry = { ++ STANDARD_MODULE_HEADER, ++ "my_input_filter", ++ my_input_filter_functions, ++ PHP_MINIT(my_input_filter), ++ PHP_MSHUTDOWN(my_input_filter), ++ NULL, ++ PHP_RSHUTDOWN(my_input_filter), ++ PHP_MINFO(my_input_filter), ++ "0.1", ++ STANDARD_MODULE_PROPERTIES ++}; ++ ++PHP_MINIT_FUNCTION(my_input_filter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(my_input_filter, php_my_input_filter_init_globals, NULL); ++ ++ REGISTER_LONG_CONSTANT("POST", PARSE_POST, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("GET", PARSE_GET, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("COOKIE", PARSE_COOKIE, CONST_CS | CONST_PERSISTENT); ++ ++ sapi_register_input_filter(my_sapi_input_filter); ++ return SUCCESS; ++} ++ ++PHP_RSHUTDOWN_FUNCTION(my_input_filter) ++{ ++ if(IF_G(get_array)) { ++ zval_ptr_dtor(&IF_G(get_array)); ++ IF_G(get_array) = NULL; ++ } ++ if(IF_G(post_array)) { ++ zval_ptr_dtor(&IF_G(post_array)); ++ IF_G(post_array) = NULL; ++ } ++ if(IF_G(cookie_array)) { ++ zval_ptr_dtor(&IF_G(cookie_array)); ++ IF_G(cookie_array) = NULL; ++ } ++ return SUCCESS; ++} ++ ++PHP_MINFO_FUNCTION(my_input_filter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_row( 2, "My Input Filter Support", "enabled" ); ++ php_info_print_table_row( 2, "Revision", "$Revision: 1.1 $"); ++ php_info_print_table_end(); ++} ++ ++/* The filter handler. If you return 1 from it, then PHP also registers the ++ * (modified) variable. Returning 0 prevents PHP from registering the variable; ++ * you can use this if your filter already registers the variable under a ++ * different name, or if you just don't want the variable registered at all. */ ++SAPI_INPUT_FILTER_FUNC(my_sapi_input_filter) ++{ ++ zval new_var; ++ zval *array_ptr = NULL; ++ char *raw_var; ++ int var_len; ++ ++ assert(*val != NULL); ++ ++ switch(arg) { ++ case PARSE_GET: ++ if(!IF_G(get_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(get_array) = array_ptr; ++ break; ++ case PARSE_POST: ++ if(!IF_G(post_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(post_array) = array_ptr; ++ break; ++ case PARSE_COOKIE: ++ if(!IF_G(cookie_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(cookie_array) = array_ptr; ++ break; ++ } ++ Z_STRLEN(new_var) = val_len; ++ Z_STRVAL(new_var) = estrndup(*val, val_len); ++ Z_TYPE(new_var) = IS_STRING; ++ ++ var_len = strlen(var); ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ ++ php_register_variable_ex(raw_var, &new_var, array_ptr TSRMLS_DC); ++ ++ php_strip_tags(*val, val_len, NULL, NULL, 0); ++ ++ *new_val_len = strlen(*val); ++ return 1; ++} ++ ++PHP_FUNCTION(my_get_raw) ++{ ++ long arg; ++ char *var; ++ int var_len; ++ zval **tmp; ++ zval *array_ptr = NULL; ++ HashTable *hash_ptr; ++ char *raw_var; ++ ++ if(zend_parse_parameters(2 TSRMLS_CC, "ls", &arg, &var, &var_len) == FAILURE) { ++ return; ++ } ++ ++ switch(arg) { ++ case PARSE_GET: ++ array_ptr = IF_G(get_array); ++ break; ++ case PARSE_POST: ++ array_ptr = IF_G(post_array); ++ break; ++ case PARSE_COOKIE: ++ array_ptr = IF_G(post_array); ++ break; ++ } ++ ++ if(!array_ptr) RETURN_FALSE; ++ ++ /* ++ * I'm changing the variable name here because when running with register_globals on, ++ * the variable will end up in the global symbol table ++ */ ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ hash_ptr = HASH_OF(array_ptr); ++ ++ if(zend_hash_find(hash_ptr, raw_var, var_len+5, (void **)&tmp) == SUCCESS) { ++ *return_value = **tmp; ++ zval_copy_ctor(return_value); ++ } else { ++ RETVAL_FALSE; ++ } ++ efree(raw_var); ++} ++ +diff -Nur php-4.3.11/TSRM/TSRM.h hardened-php-4.3.11-0.2.7/TSRM/TSRM.h +--- php-4.3.11/TSRM/TSRM.h 2005-02-11 04:34:04.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/TSRM/TSRM.h 2005-04-07 02:08:26.000000000 +0200 +@@ -33,6 +33,13 @@ + # define TSRM_API + #endif + ++#if HARDENED_PHP ++# if HAVE_REALPATH ++# undef realpath ++# define realpath php_realpath ++# endif ++#endif ++ + /* Only compile multi-threading functions if we're in ZTS mode */ + #ifdef ZTS + +@@ -90,6 +97,7 @@ + + #define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts + ++ + #ifdef __cplusplus + extern "C" { + #endif +diff -Nur php-4.3.11/TSRM/tsrm_virtual_cwd.c hardened-php-4.3.11-0.2.7/TSRM/tsrm_virtual_cwd.c +--- php-4.3.11/TSRM/tsrm_virtual_cwd.c 2005-02-11 04:34:04.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/TSRM/tsrm_virtual_cwd.c 2005-04-07 02:08:26.000000000 +0200 +@@ -192,6 +192,165 @@ + return p; + } + ++#if HARDENED_PHP ++CWD_API char *php_realpath(const char *path, char *resolved) ++{ ++ struct stat sb; ++ char *p, *q, *s; ++ size_t left_len, resolved_len; ++ unsigned symlinks; ++ int serrno, slen; ++ int is_dir = 1; ++ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; ++ ++ serrno = errno; ++ symlinks = 0; ++ if (path[0] == '/') { ++ resolved[0] = '/'; ++ resolved[1] = '\0'; ++ if (path[1] == '\0') ++ return (resolved); ++ resolved_len = 1; ++ left_len = strlcpy(left, path + 1, sizeof(left)); ++ } else { ++ if (getcwd(resolved, PATH_MAX) == NULL) { ++ strlcpy(resolved, ".", PATH_MAX); ++ return (NULL); ++ } ++ resolved_len = strlen(resolved); ++ left_len = strlcpy(left, path, sizeof(left)); ++ } ++ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ ++ /* ++ * Iterate over path components in `left'. ++ */ ++ while (left_len != 0) { ++ /* ++ * Extract the next path component and adjust `left' ++ * and its length. ++ */ ++ p = strchr(left, '/'); ++ s = p ? p : left + left_len; ++ if (s - left >= sizeof(next_token)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ memcpy(next_token, left, s - left); ++ next_token[s - left] = '\0'; ++ left_len -= s - left; ++ if (p != NULL) ++ memmove(left, s + 1, left_len + 1); ++ if (resolved[resolved_len - 1] != '/') { ++ if (resolved_len + 1 >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ resolved[resolved_len++] = '/'; ++ resolved[resolved_len] = '\0'; ++ } ++ if (next_token[0] == '\0') ++ continue; ++ else if (strcmp(next_token, ".") == 0) ++ continue; ++ else if (strcmp(next_token, "..") == 0) { ++ /* ++ * Strip the last path component except when we have ++ * single "/" ++ */ ++ if (!is_dir) { ++ errno = ENOENT; ++ return (NULL); ++ } ++ if (resolved_len > 1) { ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ continue; ++ } ++ ++ /* ++ * Append the next path component and lstat() it. If ++ * lstat() fails we still can return successfully if ++ * there are no more path components left. ++ */ ++ resolved_len = strlcat(resolved, next_token, PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ if (lstat(resolved, &sb) != 0) { ++ if (errno == ENOENT && p == NULL) { ++ errno = serrno; ++ return (resolved); ++ } ++ return (NULL); ++ } ++ if (S_ISLNK(sb.st_mode)) { ++ if (symlinks++ > MAXSYMLINKS) { ++ errno = ELOOP; ++ return (NULL); ++ } ++ slen = readlink(resolved, symlink, sizeof(symlink) - 1); ++ if (slen < 0) ++ return (NULL); ++ symlink[slen] = '\0'; ++ if (symlink[0] == '/') { ++ resolved[1] = 0; ++ resolved_len = 1; ++ } else if (resolved_len > 1) { ++ /* Strip the last path component. */ ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ ++ /* ++ * If there are any path components left, then ++ * append them to symlink. The result is placed ++ * in `left'. ++ */ ++ if (p != NULL) { ++ if (symlink[slen - 1] != '/') { ++ if (slen + 1 >= sizeof(symlink)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ symlink[slen] = '/'; ++ symlink[slen + 1] = 0; ++ } ++ left_len = strlcat(symlink, left, sizeof(left)); ++ if (left_len >= sizeof(left)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ } ++ left_len = strlcpy(left, symlink, sizeof(left)); ++ } else { ++ if (S_ISDIR(sb.st_mode)) { ++ is_dir = 1; ++ } else { ++ is_dir = 0; ++ } ++ } ++ } ++ ++ /* ++ * Remove trailing slash except when the resolved pathname ++ * is a single "/". ++ */ ++ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') ++ resolved[resolved_len - 1] = '\0'; ++ return (resolved); ++} ++#endif ++ + CWD_API void virtual_cwd_startup(void) + { + char cwd[MAXPATHLEN]; +@@ -314,8 +473,7 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now +- return 1; */ ++ return 1; + } + } + } else { /* Concat current directory with relative path and then run realpath() on it */ +@@ -341,9 +499,8 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now + free(tmp); +- return 1; */ ++ return 1; + } + } + free(tmp); +diff -Nur php-4.3.11/TSRM/tsrm_virtual_cwd.h hardened-php-4.3.11-0.2.7/TSRM/tsrm_virtual_cwd.h +--- php-4.3.11/TSRM/tsrm_virtual_cwd.h 2005-02-11 04:34:04.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/TSRM/tsrm_virtual_cwd.h 2005-04-07 02:08:26.000000000 +0200 +@@ -128,6 +128,22 @@ + + typedef int (*verify_path_func)(const cwd_state *); + ++#ifndef HAVE_STRLCPY ++CWD_API size_t php_strlcpy(char *dst, const char *src, size_t siz); ++#undef strlcpy ++#define strlcpy php_strlcpy ++#endif ++ ++#ifndef HAVE_STRLCAT ++CWD_API size_t php_strlcat(char *dst, const char *src, size_t siz); ++#undef strlcat ++#define strlcat php_strlcat ++#endif ++ ++ ++#if HARDENED_PHP ++CWD_API char *php_realpath(const char *path, char *resolved); ++#endif + CWD_API void virtual_cwd_startup(void); + CWD_API void virtual_cwd_shutdown(void); + CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC); +diff -Nur php-4.3.11/Zend/zend.c hardened-php-4.3.11-0.2.7/Zend/zend.c +--- php-4.3.11/Zend/zend.c 2005-01-22 21:36:34.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/Zend/zend.c 2005-04-07 02:08:26.000000000 +0200 +@@ -53,6 +53,12 @@ + ZEND_API void (*zend_unblock_interruptions)(void); + ZEND_API void (*zend_ticks_function)(int ticks); + ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); ++#if HARDENED_PHP ++ZEND_API void (*zend_security_log)(char *str); ++#endif ++#if HARDENED_PHP_INC_PROTECT ++ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + + void (*zend_on_timeout)(int seconds TSRMLS_DC); + +@@ -420,6 +426,14 @@ + extern zend_scanner_globals language_scanner_globals; + #endif + ++ /* Set up Hardened-PHP utility functions first */ ++#if HARDENED_PHP ++ zend_security_log = utility_functions->security_log_function; ++#endif ++#if HARDENED_PHP_INC_PROTECT ++ zend_is_valid_include = utility_functions->is_valid_include; ++#endif ++ + #ifdef ZTS + ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); + #else +diff -Nur php-4.3.11/Zend/zend.h hardened-php-4.3.11-0.2.7/Zend/zend.h +--- php-4.3.11/Zend/zend.h 2005-01-25 14:08:41.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/Zend/zend.h 2005-04-07 02:08:26.000000000 +0200 +@@ -275,9 +275,9 @@ + struct _zval_struct { + /* Variable information */ + zvalue_value value; /* value */ ++ zend_uint refcount; + zend_uchar type; /* active type */ + zend_uchar is_ref; +- zend_ushort refcount; + }; + + +@@ -338,6 +338,12 @@ + void (*ticks_function)(int ticks); + void (*on_timeout)(int seconds TSRMLS_DC); + zend_bool (*open_function)(const char *filename, struct _zend_file_handle *); ++#if HARDENED_PHP ++ void (*security_log_function)(char *str); ++#endif ++#if HARDENED_PHP_INC_PROTECT ++ int (*is_valid_include)(zval *z); ++#endif + } zend_utility_functions; + + +@@ -469,7 +475,16 @@ + extern ZEND_API void (*zend_ticks_function)(int ticks); + extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); + extern void (*zend_on_timeout)(int seconds TSRMLS_DC); ++#if HARDENED_PHP ++extern ZEND_API void (*zend_security_log)(char *str); ++#endif ++#if HARDENED_PHP_INC_PROTECT ++extern ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + ++#if HARDENED_PHP_MM_PROTECT || HARDENED_PHP_LL_PROTECT || HARDENED_PHP_HASH_PROTECT ++ZEND_API unsigned int zend_canary(void); ++#endif + + ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 2, 3); + +@@ -576,6 +591,10 @@ + + #define ZEND_MAX_RESERVED_RESOURCES 4 + ++#if HARDENED_PHP ++#include "hardened_globals.h" ++#endif ++ + #endif /* ZEND_H */ + + /* +diff -Nur php-4.3.11/Zend/zend_alloc.c hardened-php-4.3.11-0.2.7/Zend/zend_alloc.c +--- php-4.3.11/Zend/zend_alloc.c 2004-08-27 18:51:25.000000000 +0200 ++++ hardened-php-4.3.11-0.2.7/Zend/zend_alloc.c 2005-04-07 02:11:04.000000000 +0200 +@@ -56,6 +56,11 @@ + # define END_MAGIC_SIZE 0 + #endif + ++#if HARDENED_PHP_MM_PROTECT ++# define CANARY_SIZE sizeof(unsigned int) ++#else ++# define CANARY_SIZE 0 ++#endif + + # if MEMORY_LIMIT + # if ZEND_DEBUG +@@ -95,9 +100,17 @@ + if (p==AG(head)) { \ + AG(head) = p->pNext; \ + } else { \ ++ if (p != p->pLast->pNext) { \ ++ zend_security_log("linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pLast->pNext = p->pNext; \ + } \ + if (p->pNext) { \ ++ if (p != p->pNext->pLast) { \ ++ zend_security_log("linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pNext->pLast = p->pLast; \ + } + +@@ -129,6 +142,12 @@ + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENED_PHP_MM_PROTECT ++ if (size > LONG_MAX - sizeof(zend_mem_header) - MEM_HEADER_PADDING - END_MAGIC_SIZE - CANARY_SIZE) { ++ zend_security_log("emalloc() - requested size would result in integer overflow"); ++ exit(1); ++ } ++#endif + CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size); + + if (!ZEND_DISABLE_MEMORY_CACHE && (CACHE_INDEX < MAX_CACHED_MEMORY) && (AG(cache_count)[CACHE_INDEX] > 0)) { +@@ -146,6 +165,10 @@ + AG(cache_stats)[CACHE_INDEX][1]++; + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif ++#if HARDENED_PHP_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->cached = 0; + p->size = size; + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); +@@ -161,7 +184,7 @@ + AG(allocated_memory_peak) = AG(allocated_memory); + } + #endif +- p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE + CANARY_SIZE); + } + + HANDLE_BLOCK_INTERRUPTIONS(); +@@ -191,7 +214,10 @@ + # endif + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif +- ++#if HARDENED_PHP_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); + } +@@ -218,17 +244,33 @@ + return emalloc_rel(lval + offset); + } + } +- ++ ++#if HARDENED_PHP ++ zend_security_log("Possible integer overflow catched by safe_emalloc()"); ++#endif + zend_error(E_ERROR, "Possible integer overflow in memory allocation (%ld * %ld + %ld)", nmemb, size, offset); + return 0; + } + + ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENED_PHP_MM_PROTECT ++ unsigned int *canary_2; ++#endif + zend_mem_header *p = (zend_mem_header *) ((char *)ptr - sizeof(zend_mem_header) - MEM_HEADER_PADDING); + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENED_PHP_MM_PROTECT ++ canary_2 = (unsigned int *)(((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE); ++ if (p->canary != HG(canary_1) || *canary_2 != HG(canary_2)) { ++ zend_security_log("canary mismatch on efree() - heap overflow or double efree detected"); ++ exit(1); ++ } ++ /* to catch double efree()s */ ++ *canary_2 = p->canary = 0; ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + tsrm_error(TSRM_ERROR_LEVEL_ERROR, "Memory block allocated at %s:(%d) on thread %x freed at %s:(%d) on thread %x, ignoring", +@@ -273,6 +315,9 @@ + size_t _size = nmemb * size; + + if (nmemb && (_size/nmemb!=size)) { ++#if HARDENED_PHP ++ zend_security_log("Possible integer overflow catched by ecalloc()"); ++#endif + fprintf(stderr,"FATAL: ecalloc(): Unable to allocate %ld * %ld bytes\n", (long) nmemb, (long) size); + #if ZEND_DEBUG && HAVE_KILL && HAVE_GETPID + kill(getpid(), SIGSEGV); +@@ -292,6 +337,9 @@ + + ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENED_PHP_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p; + zend_mem_header *orig; + DECLARE_CACHE_VARS(); +@@ -303,6 +351,14 @@ + + p = orig = (zend_mem_header *) ((char *)ptr-sizeof(zend_mem_header)-MEM_HEADER_PADDING); + ++#if HARDENED_PHP_MM_PROTECT ++ canary_2 = *(unsigned int *)(((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE); ++ if (p->canary != HG(canary_1) || canary_2 != HG(canary_2)) { ++ zend_security_log("canary mismatch on erealloc() - heap overflow detected"); ++ exit(1); ++ } ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + void *new_p; +@@ -326,7 +382,7 @@ + } + #endif + REMOVE_POINTER_FROM_LIST(p); +- p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE+CANARY_SIZE); + if (!p) { + if (!allow_failure) { + fprintf(stderr,"FATAL: erealloc(): Unable to allocate %ld bytes\n", (long) size); +@@ -348,6 +404,9 @@ + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif + ++#if HARDENED_PHP_MM_PROTECT ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->size = size; + + HANDLE_UNBLOCK_INTERRUPTIONS(); +@@ -423,6 +482,10 @@ + { + AG(head) = NULL; + ++#if HARDENED_PHP_MM_PROTECT ++ HG(canary_1) = zend_canary(); ++ HG(canary_2) = zend_canary(); ++#endif + #if MEMORY_LIMIT + AG(memory_limit) = 1<<30; /* ridiculous limit, effectively no limit */ + AG(allocated_memory) = 0; +diff -Nur php-4.3.11/Zend/zend_alloc.h hardened-php-4.3.11-0.2.7/Zend/zend_alloc.h +--- php-4.3.11/Zend/zend_alloc.h 2004-08-11 08:10:46.000000000 +0200 ++++ hardened-php-4.3.11-0.2.7/Zend/zend_alloc.h 2005-04-07 02:08:26.000000000 +0200 +@@ -32,6 +32,9 @@ + #define MEM_BLOCK_CACHED_MAGIC 0xFB8277DCL + + typedef struct _zend_mem_header { ++#if HARDENED_PHP_MM_PROTECT ++ unsigned int canary; ++#endif + #if ZEND_DEBUG + long magic; + char *filename; +diff -Nur php-4.3.11/Zend/zend_builtin_functions.c hardened-php-4.3.11-0.2.7/Zend/zend_builtin_functions.c +--- php-4.3.11/Zend/zend_builtin_functions.c 2004-12-27 20:28:35.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/Zend/zend_builtin_functions.c 2005-04-07 02:08:26.000000000 +0200 +@@ -49,6 +49,9 @@ + static ZEND_FUNCTION(crash); + #endif + #endif ++#if HARDENED_PHP_MM_PROTECT_DEBUG ++static ZEND_FUNCTION(heap_overflow); ++#endif + static ZEND_FUNCTION(get_included_files); + static ZEND_FUNCTION(is_subclass_of); + static ZEND_FUNCTION(is_a); +@@ -101,6 +104,9 @@ + ZEND_FE(crash, NULL) + #endif + #endif ++#if HARDENED_PHP_MM_PROTECT_DEBUG ++ ZEND_FE(heap_overflow, NULL) ++#endif + ZEND_FE(get_included_files, NULL) + ZEND_FALIAS(get_required_files, get_included_files, NULL) + ZEND_FE(is_subclass_of, NULL) +@@ -805,6 +811,19 @@ + + #endif /* ZEND_DEBUG */ + ++ ++#if HARDENED_PHP_MM_PROTECT_DEBUG ++ZEND_FUNCTION(heap_overflow) ++{ ++ char *nowhere = emalloc(10); ++ ++ memcpy(nowhere, "something1234567890", sizeof("something1234567890")); ++ ++ efree(nowhere); ++} ++#endif ++ ++ + /* {{{ proto array get_included_files(void) + Returns an array with the file names that were include_once()'d */ + ZEND_FUNCTION(get_included_files) +diff -Nur php-4.3.11/Zend/zend_canary.c hardened-php-4.3.11-0.2.7/Zend/zend_canary.c +--- php-4.3.11/Zend/zend_canary.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/Zend/zend_canary.c 2005-04-07 02:08:26.000000000 +0200 +@@ -0,0 +1,58 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: zend_canary.c,v 1.1 2004/11/26 12:45:41 ionic Exp $ */ ++ ++#include "zend.h" ++ ++#include ++#include ++ ++ ++#if HARDENED_PHP_MM_PROTECT || HARDENED_PHP_LL_PROTECT ++ ++/* will be replaced later with more compatible method */ ++ZEND_API unsigned int zend_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nur php-4.3.11/Zend/zend_execute.c hardened-php-4.3.11-0.2.7/Zend/zend_execute.c +--- php-4.3.11/Zend/zend_execute.c 2005-02-21 13:38:54.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/Zend/zend_execute.c 2005-04-07 02:08:26.000000000 +0200 +@@ -2161,7 +2161,12 @@ + int dummy = 1; + zend_file_handle file_handle = {0}; + ++#if HARDENED_PHP_INC_PROTECT ++ if (zend_is_valid_include(inc_filename) ++ && zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#else + if (zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#endif + && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) { + + file_handle.filename = inc_filename->value.str.val; +@@ -2190,6 +2195,11 @@ + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: ++#if HARDENED_PHP_INC_PROTECT ++ if (!zend_is_valid_include(inc_filename)) { ++ break; ++ } ++#endif + new_op_array = compile_filename(EX(opline)->op2.u.constant.value.lval, inc_filename TSRMLS_CC); + break; + case ZEND_EVAL: { +diff -Nur php-4.3.11/Zend/zend_extensions.h hardened-php-4.3.11-0.2.7/Zend/zend_extensions.h +--- php-4.3.11/Zend/zend_extensions.h 2002-12-31 17:23:02.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/Zend/zend_extensions.h 2005-04-07 02:08:26.000000000 +0200 +@@ -23,7 +23,9 @@ + + #include "zend_compile.h" + +-#define ZEND_EXTENSION_API_NO 20021010 ++/* Create own API version number for Hardened-PHP */ ++ ++#define ZEND_EXTENSION_API_NO 1020041222 + + typedef struct _zend_extension_version_info { + int zend_extension_api_no; +diff -Nur php-4.3.11/Zend/zend_hash.c hardened-php-4.3.11-0.2.7/Zend/zend_hash.c +--- php-4.3.11/Zend/zend_hash.c 2004-07-12 23:26:46.000000000 +0200 ++++ hardened-php-4.3.11-0.2.7/Zend/zend_hash.c 2005-04-07 02:09:31.000000000 +0200 +@@ -26,6 +26,17 @@ + # include + #endif + ++#if HARDENED_PHP_HASH_PROTECT ++ unsigned int zend_hash_canary = 0x1234567; ++ zend_bool zend_hash_canary_inited = 0; ++#endif ++ ++#define CHECK_HASH_CANARY(hash) \ ++ if (zend_hash_canary != (hash)->canary) { \ ++ zend_security_log("Zend HashTable canary was overwritten"); \ ++ exit(1); \ ++ } ++ + #define HANDLE_NUMERIC(key, length, func) { \ + register char *tmp=key; \ + \ +@@ -175,6 +186,9 @@ + { + uint i = 3; + Bucket **tmp; ++#if HARDENED_PHP_HASH_PROTECT ++ TSRMLS_FETCH(); ++#endif + + SET_INCONSISTENT(HT_OK); + +@@ -184,6 +198,13 @@ + + ht->nTableSize = 1 << i; + ht->nTableMask = ht->nTableSize - 1; ++#if HARDENED_PHP_HASH_PROTECT ++ if (zend_hash_canary_inited==0) { ++ zend_hash_canary = zend_canary(); ++ zend_hash_canary_inited = 1; ++ } ++ ht->canary = zend_hash_canary; ++#endif + ht->pDestructor = pDestructor; + ht->pListHead = NULL; + ht->pListTail = NULL; +@@ -259,6 +280,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -327,6 +351,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -402,6 +429,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -450,7 +480,7 @@ + IS_CONSISTENT(ht); + + if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */ +- t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); ++ t = (Bucket **) perealloc(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); + if (t) { + HANDLE_BLOCK_INTERRUPTIONS(); + ht->arBuckets = t; +@@ -460,6 +490,7 @@ + HANDLE_UNBLOCK_INTERRUPTIONS(); + return SUCCESS; + } ++ zend_error(E_ERROR, "zend_hash_do_resize - out of memory"); + return FAILURE; + } + return SUCCESS; +@@ -524,6 +555,9 @@ + ht->pInternalPointer = p->pListNext; + } + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +@@ -553,6 +587,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -579,6 +616,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -608,6 +648,9 @@ + HANDLE_BLOCK_INTERRUPTIONS(); + + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +diff -Nur php-4.3.11/Zend/zend_hash.h hardened-php-4.3.11-0.2.7/Zend/zend_hash.h +--- php-4.3.11/Zend/zend_hash.h 2002-12-31 17:23:03.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/Zend/zend_hash.h 2005-04-07 02:08:26.000000000 +0200 +@@ -54,6 +54,9 @@ + } Bucket; + + typedef struct _hashtable { ++#if HARDENED_PHP_HASH_PROTECT ++ unsigned int canary; ++#endif + uint nTableSize; + uint nTableMask; + uint nNumOfElements; +diff -Nur php-4.3.11/Zend/zend_llist.c hardened-php-4.3.11-0.2.7/Zend/zend_llist.c +--- php-4.3.11/Zend/zend_llist.c 2002-12-31 17:23:04.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/Zend/zend_llist.c 2005-04-07 02:08:26.000000000 +0200 +@@ -21,9 +21,34 @@ + #include "zend.h" + #include "zend_llist.h" + #include "zend_qsort.h" ++#include "zend_globals.h" ++ ++#define CHECK_LIST_CANARY(list) \ ++ if (HG(canary_3) != (list)->canary_h || HG(canary_4) != (list)->canary_t) { \ ++ zend_security_log("linked list canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++#define CHECK_LISTELEMENT_CANARY(elem) \ ++ if (HG(canary_3) != (elem)->canary) { \ ++ zend_security_log("linked list element canary was overwritten"); \ ++ exit(1); \ ++ } ++ + + ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent) + { ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ ++ if (!HG(ll_canary_inited)) { ++ HG(canary_3) = zend_canary(); ++ HG(canary_4) = zend_canary(); ++ HG(ll_canary_inited) = 1; ++ } ++ l->canary_h = HG(canary_3); ++ l->canary_t = HG(canary_4); ++#endif + l->head = NULL; + l->tail = NULL; + l->count = 0; +@@ -37,6 +62,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->prev = l->tail; + tmp->next = NULL; + if (l->tail) { +@@ -55,6 +85,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->next = l->head; + tmp->prev = NULL; + if (l->head) { +@@ -91,10 +126,20 @@ + zend_llist_element *current=l->head; + zend_llist_element *next; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (compare(current->data, element)) { + DEL_LLIST_ELEMENT(current, l); ++#if HARDENED_PHP_LL_PROTECT ++ current->canary = 0; ++#endif + break; + } + current = next; +@@ -106,7 +151,14 @@ + { + zend_llist_element *current=l->head, *next; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (l->dtor) { + l->dtor(current->data); +@@ -131,7 +183,14 @@ + zend_llist_element *old_tail; + void *data; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if ((old_tail = l->tail)) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(old_tail) ++#endif + if (l->tail->prev) { + l->tail->prev->next = NULL; + } +@@ -157,9 +216,16 @@ + { + zend_llist_element *ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(src) ++#endif + zend_llist_init(dst, src->size, src->dtor, src->persistent); + ptr = src->head; + while (ptr) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(ptr) ++#endif + zend_llist_add_element(dst, ptr->data); + ptr = ptr->next; + } +@@ -170,11 +236,21 @@ + { + zend_llist_element *element, *next; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + element=l->head; + while (element) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + next = element->next; + if (func(element->data)) { + DEL_LLIST_ELEMENT(element, l); ++#if HARDENED_PHP_LL_PROTECT ++ element->canary = 0; ++#endif + } + element = next; + } +@@ -185,7 +261,13 @@ + { + zend_llist_element *element; + ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data TSRMLS_CC); + } + } +@@ -197,6 +279,9 @@ + zend_llist_element **elements; + zend_llist_element *element, **ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + if (l->count <= 0) { + return; + } +@@ -206,6 +291,9 @@ + ptr = &elements[0]; + + for (element=l->head; element; element=element->next) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + *ptr++ = element; + } + +@@ -228,7 +316,13 @@ + { + zend_llist_element *element; + ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, arg TSRMLS_CC); + } + } +@@ -239,8 +333,14 @@ + zend_llist_element *element; + va_list args; + ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + va_start(args, num_args); + for (element=l->head; element; element=element->next) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, num_args, args TSRMLS_CC); + } + va_end(args); +@@ -249,6 +349,10 @@ + + ZEND_API int zend_llist_count(zend_llist *l) + { ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + return l->count; + } + +@@ -256,8 +360,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->head; + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -269,8 +380,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->tail; + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -282,9 +400,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->next; + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +@@ -296,9 +424,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->prev; + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +diff -Nur php-4.3.11/Zend/zend_llist.h hardened-php-4.3.11-0.2.7/Zend/zend_llist.h +--- php-4.3.11/Zend/zend_llist.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/Zend/zend_llist.h 2005-04-07 02:08:26.000000000 +0200 +@@ -24,6 +24,9 @@ + #include + + typedef struct _zend_llist_element { ++#if HARDENED_PHP_LL_PROTECT ++ unsigned int canary; ++#endif + struct _zend_llist_element *next; + struct _zend_llist_element *prev; + char data[1]; /* Needs to always be last in the struct */ +@@ -36,6 +39,9 @@ + typedef void (*llist_apply_func_t)(void * TSRMLS_DC); + + typedef struct _zend_llist { ++#if HARDENED_PHP_LL_PROTECT ++ unsigned int canary_h; /* head */ ++#endif + zend_llist_element *head; + zend_llist_element *tail; + size_t size; +@@ -43,6 +49,9 @@ + llist_dtor_func_t dtor; + unsigned char persistent; + zend_llist_element *traverse_ptr; ++#if HARDENED_PHP_LL_PROTECT ++ unsigned int canary_t; /* tail */ ++#endif + } zend_llist; + + typedef zend_llist_element* zend_llist_position; +diff -Nur php-4.3.11/Zend/zend_modules.h hardened-php-4.3.11-0.2.7/Zend/zend_modules.h +--- php-4.3.11/Zend/zend_modules.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/Zend/zend_modules.h 2005-04-07 02:08:26.000000000 +0200 +@@ -34,7 +34,7 @@ + ZEND_API extern unsigned char second_arg_force_ref[]; + ZEND_API extern unsigned char third_arg_force_ref[]; + +-#define ZEND_MODULE_API_NO 20020429 ++#define ZEND_MODULE_API_NO 1020041222 + #ifdef ZTS + #define USING_ZTS 1 + #else +diff -Nur php-4.3.11/acinclude.m4 hardened-php-4.3.11-0.2.7/acinclude.m4 +--- php-4.3.11/acinclude.m4 2005-01-25 14:03:06.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/acinclude.m4 2005-04-07 02:08:26.000000000 +0200 +@@ -1173,6 +1173,36 @@ + fi + ]) + ++dnl ++dnl Check for broken realpath() ++dnl ++dnl realpath("/etc/hosts/../passwd",XXX) should not return ++dnl "/etc/passwd" ++dnl ++AC_DEFUN([PHP_AC_BROKEN_REALPATH],[ ++ AC_CACHE_CHECK(whether realpath is broken, ac_cv_broken_realpath,[ ++ AC_TRY_RUN([ ++main() { ++ char buf[4096+1]; ++ buf[0] = 0; ++ realpath("/etc/hosts/../passwd", buf); ++ exit(strcmp(buf, "/etc/passwd")==0); ++} ++ ],[ ++ ac_cv_broken_realpath=no ++ ],[ ++ ac_cv_broken_realpath=yes ++ ],[ ++ ac_cv_broken_realpath=no ++ ]) ++ ]) ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ AC_DEFINE(PHP_BROKEN_REALPATH, 1, [Whether realpath is broken]) ++ else ++ AC_DEFINE(PHP_BROKEN_REALPATH, 0, [Whether realpath is broken]) ++ fi ++]) ++ + dnl PHP_SHARED_MODULE(module-name, object-var, build-dir, cxx) + dnl + dnl Basically sets up the link-stage for building module-name +diff -Nur php-4.3.11/configure hardened-php-4.3.11-0.2.7/configure +--- php-4.3.11/configure 2005-03-30 16:35:34.000000000 +0200 ++++ hardened-php-4.3.11-0.2.7/configure 2005-04-07 02:08:26.000000000 +0200 +@@ -394,6 +394,16 @@ + ac_default_prefix=/usr/local + # Any additions from configure.in: + ac_help="$ac_help ++ --disable-hardened-php-mm-protect Disable the Memory Manager protection." ++ac_help="$ac_help ++ --disable-hardened-php-ll-protect Disable the Linked List protection." ++ac_help="$ac_help ++ --disable-hardened-php-inc-protect Disable include/require protection." ++ac_help="$ac_help ++ --disable-hardened-php-fmt-protect Disable format string protection." ++ac_help="$ac_help ++ --disable-hardened-php-hash-protect Disable Zend HashTable DTOR protection." ++ac_help="$ac_help + + SAPI modules: + " +@@ -846,6 +856,8 @@ + ac_help="$ac_help + --disable-tokenizer Disable tokenizer support" + ac_help="$ac_help ++ --disable-varfilter Disable Hardened-PHP's variable filter" ++ac_help="$ac_help + --enable-wddx Enable WDDX support." + ac_help="$ac_help + --disable-xml Disable XML support using bundled expat lib" +@@ -2669,6 +2681,157 @@ + + + ++# Check whether --enable-hardened-php-mm-protect or --disable-hardened-php-mm-protect was given. ++if test "${enable_hardened_php_mm_protect+set}" = set; then ++ enableval="$enable_hardened_php_mm_protect" ++ ++ DO_HARDENED_PHP_MM_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_MM_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardened-php-ll-protect or --disable-hardened-php-ll-protect was given. ++if test "${enable_hardened_php_ll_protect+set}" = set; then ++ enableval="$enable_hardened_php_ll_protect" ++ ++ DO_HARDENED_PHP_LL_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_LL_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardened-php-inc-protect or --disable-hardened-php-inc-protect was given. ++if test "${enable_hardened_php_inc_protect+set}" = set; then ++ enableval="$enable_hardened_php_inc_protect" ++ ++ DO_HARDENED_PHP_INC_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_INC_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardened-php-fmt-protect or --disable-hardened-php-fmt-protect was given. ++if test "${enable_hardened_php_fmt_protect+set}" = set; then ++ enableval="$enable_hardened_php_fmt_protect" ++ ++ DO_HARDENED_PHP_FMT_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_FMT_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardened-php-hash-protect or --disable-hardened-php-hash-protect was given. ++if test "${enable_hardened_php_hash_protect+set}" = set; then ++ enableval="$enable_hardened_php_hash_protect" ++ ++ DO_HARDENED_PHP_HASH_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_HASH_PROTECT=yes ++ ++fi ++ ++ ++echo $ac_n "checking whether to protect the Zend Memory Manager""... $ac_c" 1>&6 ++echo "configure:2725: checking whether to protect the Zend Memory Manager" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_MM_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend Linked Lists""... $ac_c" 1>&6 ++echo "configure:2729: checking whether to protect the Zend Linked Lists" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_LL_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect include/require statements""... $ac_c" 1>&6 ++echo "configure:2733: checking whether to protect include/require statements" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_INC_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect PHP Format String functions""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect PHP Format String functions" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_FMT_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend HashTable Destructors""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect the Zend HashTable Destructors" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_HASH_PROTECT" 1>&6 ++ ++ ++cat >> confdefs.h <<\EOF ++#define HARDENED_PHP 1 ++EOF ++ ++ ++ ++if test "$DO_HARDENED_PHP_MM_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_MM_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_MM_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENED_PHP_LL_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_LL_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_LL_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENED_PHP_INC_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_INC_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_INC_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENED_PHP_FMT_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_FMT_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_FMT_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENED_PHP_HASH_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_HASH_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_HASH_PROTECT 0 ++EOF ++ ++fi + + + +@@ -15486,6 +15649,62 @@ + fi + + ++ echo $ac_n "checking whether realpath is broken""... $ac_c" 1>&6 ++echo "configure:14928: checking whether realpath is broken" >&5 ++if eval "test \"`echo '$''{'ac_cv_broken_realpath'+set}'`\" = set"; then ++ echo $ac_n "(cached) $ac_c" 1>&6 ++else ++ ++ if test "$cross_compiling" = yes; then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null ++then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ echo "configure: failed program was:" >&5 ++ cat conftest.$ac_ext >&5 ++ rm -fr conftest* ++ ++ ac_cv_broken_realpath=yes ++ ++fi ++rm -fr conftest* ++fi ++ ++ ++fi ++ ++echo "$ac_t""$ac_cv_broken_realpath" 1>&6 ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 1 ++EOF ++ ++ else ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 0 ++EOF ++ ++ fi ++ ++ + echo $ac_n "checking for declared timezone""... $ac_c" 1>&6 + echo "configure:15491: checking for declared timezone" >&5 + if eval "test \"`echo '$''{'ac_cv_declared_timezone'+set}'`\" = set"; then +@@ -85975,6 +86194,265 @@ + fi + + ++echo $ac_n "checking whether to enable Hardened-PHP's variable filter""... $ac_c" 1>&6 ++echo "configure:82041: checking whether to enable Hardened-PHP's variable filter" >&5 ++# Check whether --enable-varfilter or --disable-varfilter was given. ++if test "${enable_varfilter+set}" = set; then ++ enableval="$enable_varfilter" ++ PHP_VARFILTER=$enableval ++else ++ ++ PHP_VARFILTER=yes ++ ++ if test "$PHP_ENABLE_ALL" && test "yes" = "yes"; then ++ PHP_VARFILTER=$PHP_ENABLE_ALL ++ fi ++ ++fi ++ ++ ++ ++ext_output="yes, shared" ++ext_shared=yes ++case $PHP_VARFILTER in ++shared,*) ++ PHP_VARFILTER=`echo "$PHP_VARFILTER"|sed 's/^shared,//'` ++ ;; ++shared) ++ PHP_VARFILTER=yes ++ ;; ++no) ++ ext_output=no ++ ext_shared=no ++ ;; ++*) ++ ext_output=yes ++ ext_shared=no ++ ;; ++esac ++ ++ ++ ++echo "$ac_t""$ext_output" 1>&6 ++ ++ ++ ++ ++if test "$PHP_VARFILTER" != "no"; then ++ cat >> confdefs.h <<\EOF ++#define HAVE_VARFILTER 1 ++EOF ++ ++ ++ ext_builddir=ext/varfilter ++ ext_srcdir=$abs_srcdir/ext/varfilter ++ ++ ac_extra= ++ ++ if test "$ext_shared" != "shared" && test "$ext_shared" != "yes" && test "" != "cli"; then ++ ++ ++ ++ case ext/varfilter in ++ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;; ++ /*) ac_srcdir=`echo "ext/varfilter"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;; ++ *) ac_srcdir="$abs_srcdir/ext/varfilter/"; ac_bdir="ext/varfilter/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;; ++ esac ++ ++ ++ ++ b_c_pre=$php_c_pre ++ b_cxx_pre=$php_cxx_pre ++ b_c_meta=$php_c_meta ++ b_cxx_meta=$php_cxx_meta ++ b_c_post=$php_c_post ++ b_cxx_post=$php_cxx_post ++ b_lo=$php_lo ++ ++ ++ old_IFS=$IFS ++ for ac_src in varfilter.c; do ++ ++ IFS=. ++ set $ac_src ++ ac_obj=$1 ++ IFS=$old_IFS ++ ++ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo" ++ ++ case $ac_src in ++ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;; ++ *.cpp) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;; ++ esac ++ ++ cat >>Makefile.objects<>Makefile.objects<>Makefile.objects<> confdefs.h <>Makefile.objects<>Makefile.objects<&6 +@@ -98629,7 +99107,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c; do ++ output.c memory_streams.c user_streams.c hardened_php.c; do + + IFS=. + set $ac_src +@@ -98802,7 +99280,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c; do ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c; do + + IFS=. + set $ac_src +diff -Nur php-4.3.11/configure.in hardened-php-4.3.11-0.2.7/configure.in +--- php-4.3.11/configure.in 2005-03-30 16:18:36.000000000 +0200 ++++ hardened-php-4.3.11-0.2.7/configure.in 2005-04-07 02:08:26.000000000 +0200 +@@ -227,7 +227,7 @@ + sinclude(Zend/acinclude.m4) + sinclude(Zend/Zend.m4) + sinclude(TSRM/tsrm.m4) +- ++sinclude(main/hardened_php.m4) + + + divert(2) +@@ -595,6 +595,7 @@ + AC_FUNC_ALLOCA + dnl PHP_AC_BROKEN_SPRINTF + dnl PHP_AC_BROKEN_SNPRINTF ++PHP_AC_BROKEN_REALPATH + PHP_DECLARED_TIMEZONE + PHP_TIME_R_TYPE + PHP_READDIR_R_TYPE +@@ -1224,7 +1225,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c) ++ output.c memory_streams.c user_streams.c hardened_php.c) + PHP_ADD_SOURCES(/main, internal_functions.c,, sapi) + PHP_ADD_SOURCES(/main, internal_functions_cli.c,, cli) + +@@ -1237,7 +1238,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c) ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c ) + + if test -r "$abs_srcdir/Zend/zend_objects.c"; then + PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_mm.c) +diff -Nur php-4.3.11/ext/mbstring/mbstring.c hardened-php-4.3.11-0.2.7/ext/mbstring/mbstring.c +--- php-4.3.11/ext/mbstring/mbstring.c 2005-02-21 09:03:47.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/ext/mbstring/mbstring.c 2005-04-07 02:08:26.000000000 +0200 +@@ -1487,6 +1487,7 @@ + char *strtok_buf = NULL, **val_list; + zval *array_ptr = (zval *) arg; + int n, num, val_len, *len_list; ++ unsigned int new_val_len; + enum mbfl_no_encoding from_encoding; + mbfl_string string, resvar, resval; + mbfl_encoding_detector *identd = NULL; +@@ -1609,8 +1610,14 @@ + val_len = len_list[n]; + } + n++; +- /* add variable to symbol table */ +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ /* we need val to be emalloc()ed */ ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(info->data_type, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ /* add variable to symbol table */ ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); ++ + if (convd != NULL){ + mbfl_string_clear(&resvar); + mbfl_string_clear(&resval); +diff -Nur php-4.3.11/ext/standard/array.c hardened-php-4.3.11-0.2.7/ext/standard/array.c +--- php-4.3.11/ext/standard/array.c 2004-12-23 17:40:03.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/ext/standard/array.c 2005-04-07 02:08:26.000000000 +0200 +@@ -1153,6 +1153,31 @@ + } + } + } ++ ++ if (var_name[0] == 'H') { ++ if ((strcmp(var_name, "HTTP_GET_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_FILES")==0)|| ++ (strcmp(var_name, "HTTP_ENV_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(var_name, "HTTP_COOKIE_VARS")==0)) { ++ return 0; ++ } ++ } else if (var_name[0] == '_') { ++ if ((strcmp(var_name, "_COOKIE")==0)|| ++ (strcmp(var_name, "_ENV")==0)|| ++ (strcmp(var_name, "_FILES")==0)|| ++ (strcmp(var_name, "_GET")==0)|| ++ (strcmp(var_name, "_POST")==0)|| ++ (strcmp(var_name, "_REQUEST")==0)|| ++ (strcmp(var_name, "_SESSION")==0)|| ++ (strcmp(var_name, "_SERVER")==0)) { ++ return 0; ++ } ++ } else if (strcmp(var_name, "GLOBALS")==0) { ++ return 0; ++ } + + return 1; + } +diff -Nur php-4.3.11/ext/standard/basic_functions.c hardened-php-4.3.11-0.2.7/ext/standard/basic_functions.c +--- php-4.3.11/ext/standard/basic_functions.c 2005-01-18 12:01:20.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/ext/standard/basic_functions.c 2005-04-07 02:08:26.000000000 +0200 +@@ -687,7 +687,7 @@ + PHP_FALIAS(socket_get_status, stream_get_meta_data, NULL) + + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +- PHP_FE(realpath, NULL) ++ PHP_STATIC_FE("realpath", zif_real_path, NULL) + #endif + + #ifdef HAVE_FNMATCH +@@ -3020,6 +3020,34 @@ + memcpy(new_key, prefix, prefix_len); + memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + ++ if (new_key[0] == 'H') { ++ if ((strcmp(new_key, "HTTP_GET_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_FILES")==0)|| ++ (strcmp(new_key, "HTTP_ENV_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(new_key, "HTTP_COOKIE_VARS")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (new_key[0] == '_') { ++ if ((strcmp(new_key, "_COOKIE")==0)|| ++ (strcmp(new_key, "_ENV")==0)|| ++ (strcmp(new_key, "_FILES")==0)|| ++ (strcmp(new_key, "_GET")==0)|| ++ (strcmp(new_key, "_POST")==0)|| ++ (strcmp(new_key, "_REQUEST")==0)|| ++ (strcmp(new_key, "_SESSION")==0)|| ++ (strcmp(new_key, "_SERVER")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (strcmp(new_key, "GLOBALS")==0) { ++ efree(new_key); ++ return 0; ++ } ++ + zend_hash_del(&EG(symbol_table), new_key, new_key_len); + ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, (*var)->refcount+1, 0); + +diff -Nur php-4.3.11/ext/standard/file.c hardened-php-4.3.11-0.2.7/ext/standard/file.c +--- php-4.3.11/ext/standard/file.c 2005-03-27 17:53:59.000000000 +0200 ++++ hardened-php-4.3.11-0.2.7/ext/standard/file.c 2005-04-07 02:08:26.000000000 +0200 +@@ -2469,7 +2469,7 @@ + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) + /* {{{ proto string realpath(string path) + Return the resolved path */ +-PHP_FUNCTION(realpath) ++PHP_FUNCTION(real_path) + { + zval **path; + char resolved_path_buff[MAXPATHLEN]; +diff -Nur php-4.3.11/ext/standard/file.h hardened-php-4.3.11-0.2.7/ext/standard/file.h +--- php-4.3.11/ext/standard/file.h 2004-06-21 21:33:47.000000000 +0200 ++++ hardened-php-4.3.11-0.2.7/ext/standard/file.h 2005-04-07 02:08:26.000000000 +0200 +@@ -64,7 +64,7 @@ + PHP_FUNCTION(fd_set); + PHP_FUNCTION(fd_isset); + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +-PHP_FUNCTION(realpath); ++PHP_FUNCTION(real_path); + #endif + #ifdef HAVE_FNMATCH + PHP_FUNCTION(fnmatch); +diff -Nur php-4.3.11/ext/standard/info.c hardened-php-4.3.11-0.2.7/ext/standard/info.c +--- php-4.3.11/ext/standard/info.c 2004-06-09 17:10:19.000000000 +0200 ++++ hardened-php-4.3.11-0.2.7/ext/standard/info.c 2005-04-07 02:08:26.000000000 +0200 +@@ -397,7 +397,7 @@ + + if (flag & PHP_INFO_GENERAL) { + char *zend_version = get_zend_version(); +- char temp_api[9]; ++ char temp_api[11]; + + php_uname = php_get_uname('a'); + +@@ -417,11 +417,22 @@ + } + } + ++#if HARDENED_PHP ++ if (!sapi_module.phpinfo_as_text) { ++ php_printf("

Hardened-PHP Version %s/%s

\n", PHP_VERSION, HARDENED_PHP_VERSION); ++ } else { ++ char temp_ver[40]; ++ ++ snprintf(temp_ver, sizeof(temp_ver), "%s/%s", PHP_VERSION, HARDENED_PHP_VERSION); ++ php_info_print_table_row(2, "Hardened-PHP Version", temp_ver); ++ } ++#else + if (!sapi_module.phpinfo_as_text) { + php_printf("

PHP Version %s

\n", PHP_VERSION); + } else { + php_info_print_table_row(2, "PHP Version", PHP_VERSION); + } ++#endif + php_info_print_box_end(); + php_info_print_table_start(); + php_info_print_table_row(2, "System", php_uname ); +diff -Nur php-4.3.11/ext/varfilter/CREDITS hardened-php-4.3.11-0.2.7/ext/varfilter/CREDITS +--- php-4.3.11/ext/varfilter/CREDITS 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/ext/varfilter/CREDITS 2005-04-07 02:08:26.000000000 +0200 +@@ -0,0 +1,2 @@ ++varfilter ++Stefan Esser +\ No newline at end of file +diff -Nur php-4.3.11/ext/varfilter/config.m4 hardened-php-4.3.11-0.2.7/ext/varfilter/config.m4 +--- php-4.3.11/ext/varfilter/config.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/ext/varfilter/config.m4 2005-04-07 02:08:26.000000000 +0200 +@@ -0,0 +1,11 @@ ++dnl ++dnl $Id: config.m4,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++dnl ++ ++PHP_ARG_ENABLE(varfilter, whether to enable Hardened-PHP's variable filter, ++[ --disable-varfilter Disable Hardened-PHP's variable filter], yes) ++ ++if test "$PHP_VARFILTER" != "no"; then ++ AC_DEFINE(HAVE_VARFILTER, 1, [ ]) ++ PHP_NEW_EXTENSION(varfilter, varfilter.c, $ext_shared) ++fi +diff -Nur php-4.3.11/ext/varfilter/php_varfilter.h hardened-php-4.3.11-0.2.7/ext/varfilter/php_varfilter.h +--- php-4.3.11/ext/varfilter/php_varfilter.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/ext/varfilter/php_varfilter.h 2005-04-07 02:08:26.000000000 +0200 +@@ -0,0 +1,72 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 4 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2003 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: php_varfilter.h,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifndef PHP_VARFILTER_H ++#define PHP_VARFILTER_H ++ ++extern zend_module_entry varfilter_module_entry; ++#define phpext_varfilter_ptr &varfilter_module_entry ++ ++#ifdef PHP_WIN32 ++#define PHP_VARFILTER_API __declspec(dllexport) ++#else ++#define PHP_VARFILTER_API ++#endif ++ ++#ifdef ZTS ++#include "TSRM.h" ++#endif ++ ++#include "SAPI.h" ++ ++PHP_MINIT_FUNCTION(varfilter); ++PHP_MSHUTDOWN_FUNCTION(varfilter); ++PHP_RINIT_FUNCTION(varfilter); ++PHP_RSHUTDOWN_FUNCTION(varfilter); ++PHP_MINFO_FUNCTION(varfilter); ++ ++ ++ZEND_BEGIN_MODULE_GLOBALS(varfilter) ++ long max_request_variables; ++ long cur_request_variables; ++ long max_varname_length; ++ long max_value_length; ++ long max_array_depth; ++ZEND_END_MODULE_GLOBALS(varfilter) ++ ++ ++#ifdef ZTS ++#define VARFILTER_G(v) TSRMG(varfilter_globals_id, zend_varfilter_globals *, v) ++#else ++#define VARFILTER_G(v) (varfilter_globals.v) ++#endif ++ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter); ++ ++#endif /* PHP_VARFILTER_H */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * indent-tabs-mode: t ++ * End: ++ */ +diff -Nur php-4.3.11/ext/varfilter/varfilter.c hardened-php-4.3.11-0.2.7/ext/varfilter/varfilter.c +--- php-4.3.11/ext/varfilter/varfilter.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/ext/varfilter/varfilter.c 2005-04-07 02:08:26.000000000 +0200 +@@ -0,0 +1,196 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 4 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2003 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: | ++ +----------------------------------------------------------------------+ ++ ++ $Id: varfilter.c,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "php.h" ++#include "php_ini.h" ++#include "ext/standard/info.h" ++#include "php_varfilter.h" ++#include "hardened_php.h" ++ ++ZEND_DECLARE_MODULE_GLOBALS(varfilter) ++ ++/* True global resources - no need for thread safety here */ ++static int le_varfilter; ++ ++/* {{{ varfilter_module_entry ++ */ ++zend_module_entry varfilter_module_entry = { ++#if ZEND_MODULE_API_NO >= 20010901 ++ STANDARD_MODULE_HEADER, ++#endif ++ "varfilter", ++ NULL, ++ PHP_MINIT(varfilter), ++ PHP_MSHUTDOWN(varfilter), ++ PHP_RINIT(varfilter), /* Replace with NULL if there's nothing to do at request start */ ++ PHP_RSHUTDOWN(varfilter), /* Replace with NULL if there's nothing to do at request end */ ++ PHP_MINFO(varfilter), ++#if ZEND_MODULE_API_NO >= 20010901 ++ "0.2.0", /* Replace with version number for your extension */ ++#endif ++ STANDARD_MODULE_PROPERTIES ++}; ++/* }}} */ ++ ++#ifdef COMPILE_DL_VARFILTER ++ZEND_GET_MODULE(varfilter) ++#endif ++ ++/* {{{ PHP_INI ++ */ ++PHP_INI_BEGIN() ++ STD_PHP_INI_ENTRY("varfilter.max_request_variables", "200", PHP_INI_SYSTEM, OnUpdateInt, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_varname_length", "64", PHP_INI_SYSTEM, OnUpdateInt, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_value_length", "10000", PHP_INI_SYSTEM, OnUpdateInt, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_depth", "100", PHP_INI_SYSTEM, OnUpdateInt, max_array_depth, zend_varfilter_globals, varfilter_globals) ++PHP_INI_END() ++/* }}} */ ++ ++/* {{{ php_varfilter_init_globals ++ */ ++static void php_varfilter_init_globals(zend_varfilter_globals *varfilter_globals) ++{ ++ varfilter_globals->max_request_variables = 200; ++ varfilter_globals->cur_request_variables = 0; ++ varfilter_globals->max_varname_length = 64; ++ varfilter_globals->max_value_length = 10000; ++ varfilter_globals->max_array_depth = 100; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINIT_FUNCTION ++ */ ++PHP_MINIT_FUNCTION(varfilter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(varfilter, php_varfilter_init_globals, NULL); ++ REGISTER_INI_ENTRIES(); ++ ++ sapi_register_input_filter(varfilter_input_filter); ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MSHUTDOWN_FUNCTION ++ */ ++PHP_MSHUTDOWN_FUNCTION(varfilter) ++{ ++ UNREGISTER_INI_ENTRIES(); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request start */ ++/* {{{ PHP_RINIT_FUNCTION ++ */ ++PHP_RINIT_FUNCTION(varfilter) ++{ ++ VARFILTER_G(cur_request_variables) = 0; ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request end */ ++/* {{{ PHP_RSHUTDOWN_FUNCTION ++ */ ++PHP_RSHUTDOWN_FUNCTION(varfilter) ++{ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINFO_FUNCTION ++ */ ++PHP_MINFO_FUNCTION(varfilter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_header(2, "Hardened-PHP's variable filter support", "enabled"); ++ php_info_print_table_end(); ++ ++ DISPLAY_INI_ENTRIES(); ++} ++/* }}} */ ++ ++/* {{{ SAPI_INPUT_FILTER_FUNC ++ */ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter) ++{ ++ char *index; ++ unsigned int var_len, depth = 0; ++ ++ /* Drop this variable if the limit is reached */ ++ if (VARFILTER_G(max_request_variables) == VARFILTER_G(cur_request_variables)) { ++ php_security_log("tried to register too many variables"); ++ return 0; ++ } ++ ++ /* Drop this variable if it exceeds the value length limit */ ++ if (VARFILTER_G(max_value_length) < val_len) { ++ php_security_log("tried to register a variable with a too long value"); ++ return 0; ++ } ++ ++ /* Find length of variable name */ ++ index = strchr(var, '['); ++ var_len = index ? index-var : strlen(var); ++ ++ /* Drop this variable if it exceeds the varname length limit */ ++ if (VARFILTER_G(max_varname_length) < var_len) { ++ php_security_log("tried to register a variable with a too long variable name"); ++ return 0; ++ } ++ ++ /* Find out array depth */ ++ while (index) { ++ depth++; ++ index = strchr(index+1, '['); ++ } ++ ++ /* Drop this variable if it exceeds the array depth limit */ ++ if (VARFILTER_G(max_array_depth) < depth) { ++ php_security_log("tried to register a too deep array variable"); ++ return 0; ++ } ++ ++ /* Okay let PHP register this variable */ ++ VARFILTER_G(cur_request_variables)++; ++ ++ if (new_val_len) { ++ *new_val_len = val_len; ++ } ++ ++ return 1; ++} ++/* }}} */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: noet sw=4 ts=4 fdm=marker ++ * vim<600: noet sw=4 ts=4 ++ */ +diff -Nur php-4.3.11/main/SAPI.c hardened-php-4.3.11-0.2.7/main/SAPI.c +--- php-4.3.11/main/SAPI.c 2005-02-22 15:46:24.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/main/SAPI.c 2005-04-07 02:08:26.000000000 +0200 +@@ -831,6 +831,12 @@ + return SUCCESS; + } + ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) ++{ ++ sapi_module.input_filter = input_filter; ++ return SUCCESS; ++} ++ + + SAPI_API int sapi_flush(TSRMLS_D) + { +diff -Nur php-4.3.11/main/SAPI.h hardened-php-4.3.11-0.2.7/main/SAPI.h +--- php-4.3.11/main/SAPI.h 2003-04-09 22:27:55.000000000 +0200 ++++ hardened-php-4.3.11-0.2.7/main/SAPI.h 2005-04-07 02:08:26.000000000 +0200 +@@ -101,9 +101,14 @@ + char *current_user; + int current_user_length; + +- /* this is necessary for CLI module */ +- int argc; +- char **argv; ++ /* this is necessary for CLI module */ ++ int argc; ++ char **argv; ++ ++#if HARDENED_PHP ++ /* this is necessary for IP logging */ ++ char ip_address[64]; ++#endif + } sapi_request_info; + + +@@ -177,6 +182,7 @@ + SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry); + SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D)); + SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC)); ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)); + + SAPI_API int sapi_flush(TSRMLS_D); + SAPI_API struct stat *sapi_get_stat(TSRMLS_D); +@@ -238,8 +244,11 @@ + int (*get_target_uid)(uid_t * TSRMLS_DC); + int (*get_target_gid)(gid_t * TSRMLS_DC); + ++ unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); ++ + void (*ini_defaults)(HashTable *configuration_hash); + int phpinfo_as_text; ++ + }; + + +@@ -262,16 +271,23 @@ + + #define SAPI_DEFAULT_MIMETYPE "text/html" + #define SAPI_DEFAULT_CHARSET "" ++ ++#if HARDENED_PHP ++#define SAPI_PHP_VERSION_HEADER "X-Powered-By: Hardened-PHP/" PHP_VERSION ++#else + #define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION ++#endif + + #define SAPI_POST_READER_FUNC(post_reader) void post_reader(TSRMLS_D) + #define SAPI_POST_HANDLER_FUNC(post_handler) void post_handler(char *content_type_dup, void *arg TSRMLS_DC) + + #define SAPI_TREAT_DATA_FUNC(treat_data) void treat_data(int arg, char *str, zval* destArray TSRMLS_DC) ++#define SAPI_INPUT_FILTER_FUNC(input_filter) unsigned int input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) + + SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data); + SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader); + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data); ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter); + + #define STANDARD_SAPI_MODULE_PROPERTIES + +diff -Nur php-4.3.11/main/fopen_wrappers.c hardened-php-4.3.11-0.2.7/main/fopen_wrappers.c +--- php-4.3.11/main/fopen_wrappers.c 2005-02-03 00:44:07.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/main/fopen_wrappers.c 2005-04-07 02:07:07.000000000 +0200 +@@ -166,6 +166,21 @@ + char *pathbuf; + char *ptr; + char *end; ++ char path_copy[MAXPATHLEN]; ++ int path_len; ++ ++ /* Special case path ends with a trailing slash */ ++ path_len = strlen(path); ++ if (path_len >= MAXPATHLEN) { ++ errno = EPERM; /* we deny permission to open it */ ++ return -1; ++ } ++ if (path_len > 0 && path[path_len-1] == PHP_DIR_SEPARATOR) { ++ memcpy(path_copy, path, path_len+1); ++ while (path_len > 0 && path_copy[path_len-1] == PHP_DIR_SEPARATOR) path_len--; ++ path_copy[path_len] = '\0'; ++ path = (const char *)&path_copy; ++ } + + pathbuf = estrdup(PG(open_basedir)); + +diff -Nur php-4.3.11/main/hardened_globals.h hardened-php-4.3.11-0.2.7/main/hardened_globals.h +--- php-4.3.11/main/hardened_globals.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/main/hardened_globals.h 2005-04-07 02:08:26.000000000 +0200 +@@ -0,0 +1,54 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_GLOBALS_H ++#define HARDENED_GLOBALS_H ++ ++typedef struct _hardened_globals hardened_globals_struct; ++ ++#ifdef ZTS ++# define HG(v) TSRMG(hardened_globals_id, hardened_globals_struct *, v) ++extern int hardened_globals_id; ++#else ++# define HG(v) (hardened_globals.v) ++extern struct _hardened_globals hardened_globals; ++#endif ++ ++ ++struct _hardened_globals { ++#if HARDENED_PHP_MM_PROTECT ++ unsigned int canary_1; ++ unsigned int canary_2; ++#endif ++#if HARDENED_PHP_LL_PROTECT ++ unsigned int canary_3; ++ unsigned int canary_4; ++ unsigned int ll_canary_inited; ++#endif ++ unsigned int dummy; ++}; ++ ++ ++#endif /* HARDENED_GLOBALS_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nur php-4.3.11/main/hardened_php.c hardened-php-4.3.11-0.2.7/main/hardened_php.c +--- php-4.3.11/main/hardened_php.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/main/hardened_php.c 2005-04-07 02:08:26.000000000 +0200 +@@ -0,0 +1,205 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: hardened_php.c,v 1.2 2004/11/21 09:38:52 ionic Exp $ */ ++ ++#include "php.h" ++ ++#include ++#include ++ ++#if HAVE_UNISTD_H ++#include ++#endif ++#include "SAPI.h" ++#include "php_globals.h" ++ ++#if HARDENED_PHP ++ ++#ifdef HAVE_SYS_SOCKET_H ++#include ++#endif ++ ++#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE) ++#undef AF_UNIX ++#endif ++ ++#if defined(AF_UNIX) ++#include ++#endif ++ ++#define SYSLOG_PATH "/dev/log" ++ ++#include "snprintf.h" ++ ++#ifdef ZTS ++#include "hardened_globals.h" ++int hardened_globals_id; ++#else ++struct _hardened_globals hardened_globals; ++#endif ++ ++static void hardened_globals_ctor(hardened_globals_struct *hardened_globals TSRMLS_DC) ++{ ++ memset(hardened_globals, 0, sizeof(*hardened_globals)); ++} ++ ++PHPAPI void hardened_startup() ++{ ++#ifdef ZTS ++ ts_allocate_id(&hardened_globals_id, sizeof(hardened_globals_struct), (ts_allocate_ctor) hardened_globals_ctor, NULL); ++#else ++ hardened_globals_ctor(&hardened_globals TSRMLS_CC); ++#endif ++} ++ ++PHPAPI void php_security_log(char *str) ++{ ++#if defined(AF_UNIX) ++ int s, r; ++ struct sockaddr_un saun; ++ char buf[1024]; ++ char *ip_address; ++ char *fname; ++ TSRMLS_FETCH(); ++ ++ ip_address = sapi_getenv("REMOTE_ADDR", 11 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "REMOTE_ADDR not set"; ++ } ++ ++ fname = sapi_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC); ++ ++ ap_php_snprintf(buf, 1024, "php security-alert: %s (attacker '%s', file '%s')\n", str, ip_address, fname); ++ ++ s = socket(AF_UNIX, SOCK_DGRAM, 0); ++ if (s == -1) { ++ return; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ s = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (s == -1) { ++ return; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ return; ++ } ++ } ++ send(s, buf, strlen(buf), 0); ++ ++ close(s); ++#endif ++} ++#endif ++ ++#if HARDENED_PHP_MM_PROTECT || HARDENED_PHP_LL_PROTECT || HARDENED_PHP_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++PHPAPI unsigned int php_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++#if HARDENED_PHP_INC_PROTECT ++ ++PHPAPI int php_is_valid_include(zval *z) ++{ ++ char *filename; ++ int len; ++ TSRMLS_FETCH(); ++ ++ /* must be of type string */ ++ if (z->type != IS_STRING || z->value.str.val == NULL) { ++ return (0); ++ } ++ ++ /* short cut */ ++ filename = z->value.str.val; ++ len = z->value.str.len; ++ ++ /* 1. must be shorter than MAXPATHLEN */ ++ if (len > MAXPATHLEN) { ++ php_security_log("Include filename longer than MAXPATHLEN chars"); ++ return (0); ++ } ++ ++ /* 2. must not be cutted */ ++ if (len != strlen(filename)) { ++ php_security_log("Include filename has a \\0 cut"); ++ return (0); ++ } ++ ++ /* 3. must not be a URL */ ++ if (strstr(filename, "://")) { ++ php_security_log("Include filename is an URL"); ++ return (0); ++ } ++ ++ /* 4. must not be an uploaded file */ ++ if (SG(rfc1867_uploaded_files)) { ++ if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, len+1)) { ++ php_security_log("Include filename is an uploaded file"); ++ return (0); ++ } ++ } ++ ++ /* passed all tests */ ++ return (1); ++} ++ ++#endif ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nur php-4.3.11/main/hardened_php.h hardened-php-4.3.11-0.2.7/main/hardened_php.h +--- php-4.3.11/main/hardened_php.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/main/hardened_php.h 2005-04-07 02:08:45.000000000 +0200 +@@ -0,0 +1,45 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_PHP_H ++#define HARDENED_PHP_H ++ ++#include "zend.h" ++ ++#if HARDENED_PHP ++PHPAPI void php_security_log(char *str); ++PHPAPI void hardened_startup(); ++#define HARDENED_PHP_VERSION "0.2.7" ++#endif ++ ++#if HARDENED_PHP_MM_PROTECT || HARDENED_PHP_LL_PROTECT || HARDENED_PHP_HASH_PROTECT ++PHPAPI unsigned int php_canary(); ++#endif ++ ++#if HARDENED_PHP_INC_PROTECT ++PHPAPI int php_is_valid_include(zval *z); ++#endif ++ ++#endif /* HARDENED_PHP_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nur php-4.3.11/main/hardened_php.m4 hardened-php-4.3.11-0.2.7/main/hardened_php.m4 +--- php-4.3.11/main/hardened_php.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/main/hardened_php.m4 2005-04-07 02:08:26.000000000 +0200 +@@ -0,0 +1,95 @@ ++dnl ++dnl $Id: hardened_php.m4,v 1.1 2004/11/14 13:24:24 ionic Exp $ ++dnl ++dnl This file contains Hardened-PHP specific autoconf functions. ++dnl ++ ++AC_ARG_ENABLE(hardened-php-mm-protect, ++[ --disable-hardened-php-mm-protect Disable the Memory Manager protection.],[ ++ DO_HARDENED_PHP_MM_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_MM_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardened-php-ll-protect, ++[ --disable-hardened-php-ll-protect Disable the Linked List protection.],[ ++ DO_HARDENED_PHP_LL_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_LL_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardened-php-inc-protect, ++[ --disable-hardened-php-inc-protect Disable include/require protection.],[ ++ DO_HARDENED_PHP_INC_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_INC_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardened-php-fmt-protect, ++[ --disable-hardened-php-fmt-protect Disable format string protection.],[ ++ DO_HARDENED_PHP_FMT_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_FMT_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardened-php-hash-protect, ++[ --disable-hardened-php-hash-protect Disable HashTable destructor protection.],[ ++ DO_HARDENED_PHP_HASH_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_HASH_PROTECT=yes ++]) ++ ++AC_MSG_CHECKING(whether to protect the Zend Memory Manager) ++AC_MSG_RESULT($DO_HARDENED_PHP_MM_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the Zend Linked Lists) ++AC_MSG_RESULT($DO_HARDENED_PHP_LL_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect include/require statements) ++AC_MSG_RESULT($DO_HARDENED_PHP_INC_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect PHP Format String functions) ++AC_MSG_RESULT($DO_HARDENED_PHP_FMT_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the destructor of Zend HashTables) ++AC_MSG_RESULT($DO_HARDENED_PHP_HASH_PROTECT) ++ ++ ++AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ ++ ++if test "$DO_HARDENED_PHP_MM_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_MM_PROTECT, 1, [Memory Manager Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_MM_PROTECT, 0, [Memory Manager Protection]) ++fi ++ ++if test "$DO_HARDENED_PHP_LL_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_LL_PROTECT, 1, [Linked List Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_LL_PROTECT, 0, [Linked List Protection]) ++fi ++ ++if test "$DO_HARDENED_PHP_INC_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_INC_PROTECT, 1, [Include/Require Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_INC_PROTECT, 0, [Include/Require Protection]) ++fi ++ ++if test "$DO_HARDENED_PHP_FMT_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_FMT_PROTECT, 1, [Fmt String Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_FMT_PROTECT, 0, [Fmt String Protection]) ++fi ++ ++if test "$DO_HARDENED_PHP_HASH_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_HASH_PROTECT, 1, [HashTable DTOR Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_HASH_PROTECT, 0, [HashTable DTOR Protection]) ++fi ++ +diff -Nur php-4.3.11/main/main.c hardened-php-4.3.11-0.2.7/main/main.c +--- php-4.3.11/main/main.c 2005-03-08 22:45:51.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/main/main.c 2005-04-07 02:08:26.000000000 +0200 +@@ -100,6 +100,10 @@ + PHPAPI int core_globals_id; + #endif + ++#if HARDENED_PHP ++#include "hardened_globals.h" ++#endif ++ + #define ERROR_BUF_LEN 1024 + + typedef struct { +@@ -150,10 +154,33 @@ + */ + static PHP_INI_MH(OnChangeMemoryLimit) + { ++#if HARDENED_PHP ++ long orig_memory_limit; ++ ++ if (entry->modified) { ++ orig_memory_limit = zend_atoi(entry->orig_value, entry->orig_value_length); ++ } else { ++ orig_memory_limit = 1<<30; ++ } ++ if (orig_memory_limit < 0 || orig_memory_limit > (1<<30)) { ++ orig_memory_limit = 1<<30; ++ } ++#endif + if (new_value) { + PG(memory_limit) = zend_atoi(new_value, new_value_length); ++#if HARDENED_PHP ++ if (PG(memory_limit) > orig_memory_limit) { ++ PG(memory_limit) = orig_memory_limit; ++ php_security_log("script tried to increase memory_limit above allowed value"); ++ return FAILURE; ++ } ++#endif + } else { ++#if HARDENED_PHP ++ PG(memory_limit) = orig_memory_limit; ++#else + PG(memory_limit) = 1<<30; /* effectively, no limit */ ++#endif + } + return zend_set_memory_limit(PG(memory_limit)); + } +@@ -1092,6 +1119,10 @@ + tsrm_ls = ts_resource(0); + #endif + ++#if HARDENED_PHP ++ hardened_startup(); ++#endif ++ + sapi_initialize_empty_request(TSRMLS_C); + sapi_activate(TSRMLS_C); + +@@ -1104,6 +1135,12 @@ + php_output_startup(); + php_output_activate(TSRMLS_C); + ++#if HARDENED_PHP_INC_PROTECT ++ zuf.is_valid_include = php_is_valid_include; ++#endif ++#if HARDENED_PHP ++ zuf.security_log_function = php_security_log; ++#endif + zuf.error_function = php_error_cb; + zuf.printf_function = php_printf; + zuf.write_function = php_body_write_wrapper; +@@ -1205,6 +1242,10 @@ + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, sizeof(PHP_CONFIG_FILE_PATH)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS); ++#if HARDENED_PHP ++ REGISTER_MAIN_LONG_CONSTANT("HARDENED_PHP", 1, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_STRINGL_CONSTANT("HARDENED_PHP_VERSION", HARDENED_PHP_VERSION, sizeof(HARDENED_PHP_VERSION)-1, CONST_PERSISTENT | CONST_CS); ++#endif + REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS); + php_output_register_constants(TSRMLS_C); + php_rfc1867_register_constants(TSRMLS_C); +diff -Nur php-4.3.11/main/php.h hardened-php-4.3.11-0.2.7/main/php.h +--- php-4.3.11/main/php.h 2005-03-08 22:45:51.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/main/php.h 2005-04-07 02:08:26.000000000 +0200 +@@ -35,11 +35,19 @@ + #include "zend_qsort.h" + #include "php_compat.h" + ++ + #include "zend_API.h" + + #undef sprintf + #define sprintf php_sprintf + ++#if HARDENED_PHP ++#if HAVE_REALPATH ++#undef realpath ++#define realpath php_realpath ++#endif ++#endif ++ + /* PHP's DEBUG value must match Zend's ZEND_DEBUG value */ + #undef PHP_DEBUG + #define PHP_DEBUG ZEND_DEBUG +@@ -436,6 +444,10 @@ + #endif + #endif /* !XtOffsetOf */ + ++#if HARDENED_PHP ++#include "hardened_php.h" ++#endif ++ + #endif + + /* +diff -Nur php-4.3.11/main/php_config.h.in hardened-php-4.3.11-0.2.7/main/php_config.h.in +--- php-4.3.11/main/php_config.h.in 2005-03-30 16:35:47.000000000 +0200 ++++ hardened-php-4.3.11-0.2.7/main/php_config.h.in 2005-04-07 02:08:26.000000000 +0200 +@@ -839,6 +839,39 @@ + /* Enabling BIND8 compatibility for Panther */ + #undef BIND_8_COMPAT + ++/* Hardened-PHP */ ++#undef HARDENED_PHP ++ ++/* Memory Manager Protection */ ++#undef HARDENED_PHP_MM_PROTECT ++ ++/* Memory Manager Protection */ ++#undef HARDENED_PHP_MM_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENED_PHP_LL_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENED_PHP_LL_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENED_PHP_INC_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENED_PHP_INC_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENED_PHP_FMT_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENED_PHP_FMT_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENED_PHP_HASH_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENED_PHP_HASH_PROTECT ++ + /* Whether you have AOLserver */ + #undef HAVE_AOLSERVER + +@@ -1122,6 +1155,12 @@ + /* Define if you have the getaddrinfo function */ + #undef HAVE_GETADDRINFO + ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ + /* Whether system headers declare timezone */ + #undef HAVE_DECLARED_TIMEZONE + +diff -Nur php-4.3.11/main/php_content_types.c hardened-php-4.3.11-0.2.7/main/php_content_types.c +--- php-4.3.11/main/php_content_types.c 2002-12-31 17:26:14.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/main/php_content_types.c 2005-04-07 02:08:26.000000000 +0200 +@@ -77,6 +77,7 @@ + sapi_register_post_entries(php_post_entries); + sapi_register_default_post_reader(php_default_post_reader); + sapi_register_treat_data(php_default_treat_data); ++ sapi_register_input_filter(php_default_input_filter); + return SUCCESS; + } + /* }}} */ +diff -Nur php-4.3.11/main/php_variables.c hardened-php-4.3.11-0.2.7/main/php_variables.c +--- php-4.3.11/main/php_variables.c 2004-10-18 17:08:46.000000000 +0200 ++++ hardened-php-4.3.11-0.2.7/main/php_variables.c 2005-04-07 02:08:26.000000000 +0200 +@@ -211,17 +211,28 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(PARSE_POST, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, "&", &strtok_buf); + } + } + ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter) ++{ ++ /* TODO: check .ini setting here and apply user-defined input filter */ ++ *new_val_len = val_len; ++ return 1; ++} ++ + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) + { + char *res = NULL, *var, *val, *separator=NULL; +@@ -299,15 +310,26 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } else { ++ unsigned int val_len, new_val_len; ++ + php_url_decode(var, strlen(var)); +- php_register_variable_safe(var, "", 0, array_ptr TSRMLS_CC); ++ val_len = 0; ++ val = estrndup("", 0); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, separator, &strtok_buf); + } +diff -Nur php-4.3.11/main/rfc1867.c hardened-php-4.3.11-0.2.7/main/rfc1867.c +--- php-4.3.11/main/rfc1867.c 2005-02-15 01:28:39.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/main/rfc1867.c 2005-04-07 02:08:26.000000000 +0200 +@@ -891,21 +891,24 @@ + if (!filename && param) { + + char *value = multipart_buffer_read_body(mbuff TSRMLS_CC); ++ unsigned int new_val_len; /* Dummy variable */ + + if (!value) { + value = estrdup(""); + } + ++ if (sapi_module.input_filter(PARSE_POST, param, &value, strlen(value), &new_val_len TSRMLS_CC)) { + #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) +- if (php_mb_encoding_translation(TSRMLS_C)) { +- php_mb_gpc_stack_variable(param, value, &val_list, &len_list, +- &num_vars, &num_vars_max TSRMLS_CC); +- } else { +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); +- } ++ if (php_mb_encoding_translation(TSRMLS_C)) { ++ php_mb_gpc_stack_variable(param, value, &val_list, &len_list, ++ &num_vars, &num_vars_max TSRMLS_CC); ++ } else { ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ } + #else +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); + #endif ++ } + if (!strcasecmp(param, "MAX_FILE_SIZE")) { + max_file_size = atol(value); + } +diff -Nur php-4.3.11/main/snprintf.c hardened-php-4.3.11-0.2.7/main/snprintf.c +--- php-4.3.11/main/snprintf.c 2004-11-16 00:27:26.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/main/snprintf.c 2005-04-07 02:08:26.000000000 +0200 +@@ -850,7 +850,11 @@ + + + case 'n': ++#if HARDENED_PHP_FMT_PROTECT ++ php_security_log("'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Nur php-4.3.11/main/spprintf.c hardened-php-4.3.11-0.2.7/main/spprintf.c +--- php-4.3.11/main/spprintf.c 2003-09-29 03:09:36.000000000 +0200 ++++ hardened-php-4.3.11-0.2.7/main/spprintf.c 2005-04-07 02:08:26.000000000 +0200 +@@ -531,7 +531,11 @@ + + + case 'n': ++#if HARDENED_PHP_FMT_PROTECT ++ php_security_log("'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Nur php-4.3.11/php.ini-dist hardened-php-4.3.11-0.2.7/php.ini-dist +--- php-4.3.11/php.ini-dist 2005-02-14 09:26:10.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/php.ini-dist 2005-04-07 02:08:26.000000000 +0200 +@@ -1109,6 +1109,23 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[varfilter] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardened-PHP's variable filter ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Maximum number of input variables per request ++varfilter.max_request_variables = 200 ++ ++; Maximum characters in input variable names ++varfilter.max_varname_length = 64 ++ ++; Maximum length of input variable values ++varfilter.max_value_length = 10000 ++ ++; Maximum depth of input variable arrays ++varfilter.max_array_depth = 100 ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nur php-4.3.11/php.ini-recommended hardened-php-4.3.11-0.2.7/php.ini-recommended +--- php-4.3.11/php.ini-recommended 2005-02-14 09:26:10.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/php.ini-recommended 2005-04-07 02:08:26.000000000 +0200 +@@ -1107,6 +1107,23 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[varfilter] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardened-PHP's variable filter ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Maximum number of input variables per request ++varfilter.max_request_variables = 200 ++ ++; Maximum characters in input variable names ++varfilter.max_varname_length = 64 ++ ++; Maximum length of input variable values ++varfilter.max_value_length = 10000 ++ ++; Maximum depth of input variable arrays ++varfilter.max_array_depth = 100 ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nur php-4.3.11/sapi/apache/mod_php4.c hardened-php-4.3.11-0.2.7/sapi/apache/mod_php4.c +--- php-4.3.11/sapi/apache/mod_php4.c 2004-07-21 18:25:28.000000000 +0200 ++++ hardened-php-4.3.11-0.2.7/sapi/apache/mod_php4.c 2005-04-07 02:08:26.000000000 +0200 +@@ -446,7 +446,7 @@ + sapi_apache_get_fd, + sapi_apache_force_http_10, + sapi_apache_get_target_uid, +- sapi_apache_get_target_gid ++ sapi_apache_get_target_gid, + }; + /* }}} */ + +@@ -892,7 +892,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENED_PHP ++ ap_add_version_component("Hardened-PHP/" PHP_VERSION); ++#else + ap_add_version_component("PHP/" PHP_VERSION); ++#endif + } + } + #endif +diff -Nur php-4.3.11/sapi/apache2filter/sapi_apache2.c hardened-php-4.3.11-0.2.7/sapi/apache2filter/sapi_apache2.c +--- php-4.3.11/sapi/apache2filter/sapi_apache2.c 2005-01-07 07:28:36.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/sapi/apache2filter/sapi_apache2.c 2005-04-07 02:08:26.000000000 +0200 +@@ -563,7 +563,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENED_PHP ++ ap_add_version_component(p, "Hardened-PHP/" PHP_VERSION); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nur php-4.3.11/sapi/apache2handler/sapi_apache2.c hardened-php-4.3.11-0.2.7/sapi/apache2handler/sapi_apache2.c +--- php-4.3.11/sapi/apache2handler/sapi_apache2.c 2005-03-10 12:39:04.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/sapi/apache2handler/sapi_apache2.c 2005-04-07 02:08:26.000000000 +0200 +@@ -345,7 +345,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENED_PHP ++ ap_add_version_component(p, "Hardened-PHP/" PHP_VERSION); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nur php-4.3.11/sapi/cgi/cgi_main.c hardened-php-4.3.11-0.2.7/sapi/cgi/cgi_main.c +--- php-4.3.11/sapi/cgi/cgi_main.c 2005-02-11 03:12:30.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/sapi/cgi/cgi_main.c 2005-04-07 02:08:26.000000000 +0200 +@@ -1435,11 +1435,19 @@ + SG(headers_sent) = 1; + SG(request_info).no_headers = 1; + } ++#if HARDENED_PHP ++#if ZEND_DEBUG ++ php_printf("Hardened-PHP %s/%s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENED_PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("Hardened-PHP %s/%s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENED_PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit(1); + break; +diff -Nur php-4.3.11/sapi/cli/php_cli.c hardened-php-4.3.11-0.2.7/sapi/cli/php_cli.c +--- php-4.3.11/sapi/cli/php_cli.c 2005-03-22 16:09:36.000000000 +0100 ++++ hardened-php-4.3.11-0.2.7/sapi/cli/php_cli.c 2005-04-07 02:08:26.000000000 +0200 +@@ -652,11 +652,19 @@ + if (php_request_startup(TSRMLS_C)==FAILURE) { + goto err; + } ++#if HARDENED_PHP ++#if ZEND_DEBUG ++ php_printf("Hardened-PHP %s/%s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENED_PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("Hardened-PHP %s/%s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENED_PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit_status=1; + goto out; diff --git a/0.2.7/hardened-php-5.0.4-0.2.7.patch b/0.2.7/hardened-php-5.0.4-0.2.7.patch new file mode 100644 index 0000000..2b1372a --- /dev/null +++ b/0.2.7/hardened-php-5.0.4-0.2.7.patch @@ -0,0 +1,3100 @@ +diff -Nur php-5.0.4/TSRM/TSRM.h hardened-php-5.0.4-0.2.7/TSRM/TSRM.h +--- php-5.0.4/TSRM/TSRM.h 2005-03-11 12:12:07.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/TSRM/TSRM.h 2005-04-07 02:04:38.000000000 +0200 +@@ -33,6 +33,13 @@ + # define TSRM_API + #endif + ++#if HARDENED_PHP ++# if HAVE_REALPATH ++# undef realpath ++# define realpath php_realpath ++# endif ++#endif ++ + /* Only compile multi-threading functions if we're in ZTS mode */ + #ifdef ZTS + +@@ -88,6 +95,7 @@ + + #define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts + ++ + #ifdef __cplusplus + extern "C" { + #endif +diff -Nur php-5.0.4/TSRM/tsrm_virtual_cwd.c hardened-php-5.0.4-0.2.7/TSRM/tsrm_virtual_cwd.c +--- php-5.0.4/TSRM/tsrm_virtual_cwd.c 2005-03-11 12:09:42.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/TSRM/tsrm_virtual_cwd.c 2005-04-07 02:04:38.000000000 +0200 +@@ -197,6 +197,165 @@ + return p; + } + ++#if HARDENED_PHP ++CWD_API char *php_realpath(const char *path, char *resolved) ++{ ++ struct stat sb; ++ char *p, *q, *s; ++ size_t left_len, resolved_len; ++ unsigned symlinks; ++ int serrno, slen; ++ int is_dir = 1; ++ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; ++ ++ serrno = errno; ++ symlinks = 0; ++ if (path[0] == '/') { ++ resolved[0] = '/'; ++ resolved[1] = '\0'; ++ if (path[1] == '\0') ++ return (resolved); ++ resolved_len = 1; ++ left_len = strlcpy(left, path + 1, sizeof(left)); ++ } else { ++ if (getcwd(resolved, PATH_MAX) == NULL) { ++ strlcpy(resolved, ".", PATH_MAX); ++ return (NULL); ++ } ++ resolved_len = strlen(resolved); ++ left_len = strlcpy(left, path, sizeof(left)); ++ } ++ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ ++ /* ++ * Iterate over path components in `left'. ++ */ ++ while (left_len != 0) { ++ /* ++ * Extract the next path component and adjust `left' ++ * and its length. ++ */ ++ p = strchr(left, '/'); ++ s = p ? p : left + left_len; ++ if (s - left >= sizeof(next_token)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ memcpy(next_token, left, s - left); ++ next_token[s - left] = '\0'; ++ left_len -= s - left; ++ if (p != NULL) ++ memmove(left, s + 1, left_len + 1); ++ if (resolved[resolved_len - 1] != '/') { ++ if (resolved_len + 1 >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ resolved[resolved_len++] = '/'; ++ resolved[resolved_len] = '\0'; ++ } ++ if (next_token[0] == '\0') ++ continue; ++ else if (strcmp(next_token, ".") == 0) ++ continue; ++ else if (strcmp(next_token, "..") == 0) { ++ /* ++ * Strip the last path component except when we have ++ * single "/" ++ */ ++ if (!is_dir) { ++ errno = ENOENT; ++ return (NULL); ++ } ++ if (resolved_len > 1) { ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ continue; ++ } ++ ++ /* ++ * Append the next path component and lstat() it. If ++ * lstat() fails we still can return successfully if ++ * there are no more path components left. ++ */ ++ resolved_len = strlcat(resolved, next_token, PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ if (lstat(resolved, &sb) != 0) { ++ if (errno == ENOENT && p == NULL) { ++ errno = serrno; ++ return (resolved); ++ } ++ return (NULL); ++ } ++ if (S_ISLNK(sb.st_mode)) { ++ if (symlinks++ > MAXSYMLINKS) { ++ errno = ELOOP; ++ return (NULL); ++ } ++ slen = readlink(resolved, symlink, sizeof(symlink) - 1); ++ if (slen < 0) ++ return (NULL); ++ symlink[slen] = '\0'; ++ if (symlink[0] == '/') { ++ resolved[1] = 0; ++ resolved_len = 1; ++ } else if (resolved_len > 1) { ++ /* Strip the last path component. */ ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ ++ /* ++ * If there are any path components left, then ++ * append them to symlink. The result is placed ++ * in `left'. ++ */ ++ if (p != NULL) { ++ if (symlink[slen - 1] != '/') { ++ if (slen + 1 >= sizeof(symlink)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ symlink[slen] = '/'; ++ symlink[slen + 1] = 0; ++ } ++ left_len = strlcat(symlink, left, sizeof(left)); ++ if (left_len >= sizeof(left)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ } ++ left_len = strlcpy(left, symlink, sizeof(left)); ++ } else { ++ if (S_ISDIR(sb.st_mode)) { ++ is_dir = 1; ++ } else { ++ is_dir = 0; ++ } ++ } ++ } ++ ++ /* ++ * Remove trailing slash except when the resolved pathname ++ * is a single "/". ++ */ ++ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') ++ resolved[resolved_len - 1] = '\0'; ++ return (resolved); ++} ++#endif ++ + CWD_API void virtual_cwd_startup(void) + { + char cwd[MAXPATHLEN]; +@@ -321,8 +480,7 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now +- return 1; */ ++ return 1; + } + } + } else { /* Concat current directory with relative path and then run realpath() on it */ +@@ -348,9 +506,8 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now + free(tmp); +- return 1; */ ++ return 1; + } + } + free(tmp); +diff -Nur php-5.0.4/TSRM/tsrm_virtual_cwd.h hardened-php-5.0.4-0.2.7/TSRM/tsrm_virtual_cwd.h +--- php-5.0.4/TSRM/tsrm_virtual_cwd.h 2005-03-11 12:07:17.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/TSRM/tsrm_virtual_cwd.h 2005-04-07 02:04:38.000000000 +0200 +@@ -128,6 +128,22 @@ + + typedef int (*verify_path_func)(const cwd_state *); + ++#ifndef HAVE_STRLCPY ++CWD_API size_t php_strlcpy(char *dst, const char *src, size_t siz); ++#undef strlcpy ++#define strlcpy php_strlcpy ++#endif ++ ++#ifndef HAVE_STRLCAT ++CWD_API size_t php_strlcat(char *dst, const char *src, size_t siz); ++#undef strlcat ++#define strlcat php_strlcat ++#endif ++ ++ ++#if HARDENED_PHP ++CWD_API char *php_realpath(const char *path, char *resolved); ++#endif + CWD_API void virtual_cwd_startup(void); + CWD_API void virtual_cwd_shutdown(void); + CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC); +diff -Nur php-5.0.4/Zend/zend.c hardened-php-5.0.4-0.2.7/Zend/zend.c +--- php-5.0.4/Zend/zend.c 2005-03-16 00:47:12.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/Zend/zend.c 2005-04-07 02:04:38.000000000 +0200 +@@ -54,6 +54,12 @@ + ZEND_API void (*zend_unblock_interruptions)(void); + ZEND_API void (*zend_ticks_function)(int ticks); + ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); ++#if HARDENED_PHP ++ZEND_API void (*zend_security_log)(char *str); ++#endif ++#if HARDENED_PHP_INC_PROTECT ++ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); + + void (*zend_on_timeout)(int seconds TSRMLS_DC); +@@ -545,6 +551,14 @@ + extern zend_scanner_globals language_scanner_globals; + #endif + ++ /* Set up Hardened-PHP utility functions first */ ++#if HARDENED_PHP ++ zend_security_log = utility_functions->security_log_function; ++#endif ++#if HARDENED_PHP_INC_PROTECT ++ zend_is_valid_include = utility_functions->is_valid_include; ++#endif ++ + #ifdef ZTS + ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); + #else +diff -Nur php-5.0.4/Zend/zend.h hardened-php-5.0.4-0.2.7/Zend/zend.h +--- php-5.0.4/Zend/zend.h 2005-03-10 12:30:44.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/Zend/zend.h 2005-04-07 02:04:38.000000000 +0200 +@@ -359,6 +359,12 @@ + void (*on_timeout)(int seconds TSRMLS_DC); + int (*stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); + int (*vspprintf_function)(char **pbuf, size_t max_len, const char *format, va_list ap); ++#if HARDENED_PHP ++ void (*security_log_function)(char *str); ++#endif ++#if HARDENED_PHP_INC_PROTECT ++ int (*is_valid_include)(zval *z); ++#endif + } zend_utility_functions; + + +@@ -496,6 +502,16 @@ + extern void (*zend_on_timeout)(int seconds TSRMLS_DC); + extern ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); + extern int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); ++#if HARDENED_PHP ++extern ZEND_API void (*zend_security_log)(char *str); ++#endif ++#if HARDENED_PHP_INC_PROTECT ++extern ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif ++ ++#if HARDENED_PHP_MM_PROTECT || HARDENED_PHP_LL_PROTECT || HARDENED_PHP_HASH_PROTECT ++ZEND_API unsigned int zend_canary(void); ++#endif + + + ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +@@ -620,6 +636,10 @@ + #define ZEND_MAX_RESERVED_RESOURCES 4 + + ++#if HARDENED_PHP ++#include "hardened_globals.h" ++#endif ++ + #endif /* ZEND_H */ + + /* +diff -Nur php-5.0.4/Zend/zend_API.h hardened-php-5.0.4-0.2.7/Zend/zend_API.h +--- php-5.0.4/Zend/zend_API.h 2005-01-22 13:29:13.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/Zend/zend_API.h 2005-04-07 02:04:38.000000000 +0200 +@@ -47,6 +47,7 @@ + #define ZEND_METHOD(classname, name) ZEND_NAMED_FUNCTION(ZEND_FN(classname##_##name)) + + #define ZEND_FENTRY(zend_name, name, arg_info, flags) { #zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeof(struct _zend_arg_info)-1), flags }, ++#define ZEND_STATIC_FE(zend_name, name, arg_info) { zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeof(struct _zend_arg_info)-1), 0 }, + + #define ZEND_NAMED_FE(zend_name, name, arg_info) ZEND_FENTRY(zend_name, name, arg_info, 0) + #define ZEND_FE(name, arg_info) ZEND_FENTRY(name, ZEND_FN(name), arg_info, 0) +diff -Nur php-5.0.4/Zend/zend_alloc.c hardened-php-5.0.4-0.2.7/Zend/zend_alloc.c +--- php-5.0.4/Zend/zend_alloc.c 2004-08-27 18:49:54.000000000 +0200 ++++ hardened-php-5.0.4-0.2.7/Zend/zend_alloc.c 2005-04-07 02:12:14.000000000 +0200 +@@ -64,6 +64,11 @@ + # define END_MAGIC_SIZE 0 + #endif + ++#if HARDENED_PHP_MM_PROTECT ++# define CANARY_SIZE sizeof(unsigned int) ++#else ++# define CANARY_SIZE 0 ++#endif + + # if MEMORY_LIMIT + # if ZEND_DEBUG +@@ -104,9 +109,17 @@ + if (p==AG(head)) { \ + AG(head) = p->pNext; \ + } else { \ ++ if (p != p->pLast->pNext) { \ ++ zend_security_log("linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pLast->pNext = p->pNext; \ + } \ + if (p->pNext) { \ ++ if (p != p->pNext->pLast) { \ ++ zend_security_log("linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pNext->pLast = p->pLast; \ + } + #else +@@ -145,6 +158,12 @@ + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENED_PHP_MM_PROTECT ++ if (size > LONG_MAX - sizeof(zend_mem_header) - MEM_HEADER_PADDING - END_MAGIC_SIZE - CANARY_SIZE) { ++ zend_security_log("emalloc() - requested size would result in integer overflow"); ++ exit(1); ++ } ++#endif + CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size); + + #if !ZEND_DISABLE_MEMORY_CACHE +@@ -163,6 +182,10 @@ + AG(cache_stats)[CACHE_INDEX][1]++; + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif ++#if HARDENED_PHP_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->cached = 0; + p->size = size; + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); +@@ -179,7 +202,7 @@ + AG(allocated_memory_peak) = AG(allocated_memory); + } + #endif +- p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE + CANARY_SIZE); + #if !ZEND_DISABLE_MEMORY_CACHE + } + #endif +@@ -211,7 +234,10 @@ + # endif + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif +- ++#if HARDENED_PHP_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); + } +@@ -239,6 +265,10 @@ + } + } + ++ ++#if HARDENED_PHP ++ zend_security_log("Possible integer overflow catched by safe_emalloc()"); ++#endif + zend_error(E_ERROR, "Possible integer overflow in memory allocation (%zd * %zd + %zd)", nmemb, size, offset); + return 0; + } +@@ -247,9 +277,22 @@ + + ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENED_PHP_MM_PROTECT ++ unsigned int *canary_2; ++#endif + zend_mem_header *p = (zend_mem_header *) ((char *)ptr - sizeof(zend_mem_header) - MEM_HEADER_PADDING); + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); ++ ++#if HARDENED_PHP_MM_PROTECT ++ canary_2 = (unsigned int *)(((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE); ++ if (p->canary != HG(canary_1) || *canary_2 != HG(canary_2)) { ++ zend_security_log("canary mismatch on efree() - heap overflow or double efree detected"); ++ exit(1); ++ } ++ /* to catch double efree()s */ ++ *canary_2 = p->canary = 0; ++#endif + + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { +@@ -291,23 +334,35 @@ + + ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { +- void *p; +- int final_size = size*nmemb; ++ char *p; ++ size_t _size = nmemb * size; ++ ++ if (nmemb && (_size/nmemb!=size)) { ++#if HARDENED_PHP ++ zend_security_log("Possible integer overflow catched by ecalloc()"); ++#endif ++ fprintf(stderr,"FATAL: ecalloc(): Unable to allocate %ld * %ld bytes\n", (long) nmemb, (long) size); ++#if ZEND_DEBUG && HAVE_KILL && HAVE_GETPID ++ kill(getpid(), SIGSEGV); ++#else ++ exit(1); ++#endif ++ } + +- HANDLE_BLOCK_INTERRUPTIONS(); +- p = _emalloc(final_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); +- if (!p) { +- HANDLE_UNBLOCK_INTERRUPTIONS(); +- return (void *) p; ++ p = (char *) _emalloc(_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); ++ if (p) { ++ memset(p, 0, _size); + } +- memset(p, 0, final_size); +- HANDLE_UNBLOCK_INTERRUPTIONS(); +- return p; ++ ++ return ((void *)p); + } + + + ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENED_PHP_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p; + zend_mem_header *orig; + DECLARE_CACHE_VARS(); +@@ -319,6 +374,14 @@ + + p = orig = (zend_mem_header *) ((char *)ptr-sizeof(zend_mem_header)-MEM_HEADER_PADDING); + ++#if HARDENED_PHP_MM_PROTECT ++ canary_2 = *(unsigned int *)(((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE); ++ if (p->canary != HG(canary_1) || canary_2 != HG(canary_2)) { ++ zend_security_log("canary mismatch on erealloc() - heap overflow detected"); ++ exit(1); ++ } ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + void *new_p; +@@ -342,7 +405,7 @@ + } + #endif + REMOVE_POINTER_FROM_LIST(p); +- p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE+CANARY_SIZE); + if (!p) { + if (!allow_failure) { + fprintf(stderr,"FATAL: erealloc(): Unable to allocate %ld bytes\n", (long) size); +@@ -364,6 +427,9 @@ + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif + ++#if HARDENED_PHP_MM_PROTECT ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->size = size; + + HANDLE_UNBLOCK_INTERRUPTIONS(); +@@ -439,6 +505,10 @@ + { + AG(head) = NULL; + ++#if HARDENED_PHP_MM_PROTECT ++ HG(canary_1) = zend_canary(); ++ HG(canary_2) = zend_canary(); ++#endif + #if MEMORY_LIMIT + AG(memory_limit) = 1<<30; /* ridiculous limit, effectively no limit */ + AG(allocated_memory) = 0; +diff -Nur php-5.0.4/Zend/zend_alloc.h hardened-php-5.0.4-0.2.7/Zend/zend_alloc.h +--- php-5.0.4/Zend/zend_alloc.h 2004-08-11 08:13:12.000000000 +0200 ++++ hardened-php-5.0.4-0.2.7/Zend/zend_alloc.h 2005-04-07 02:04:38.000000000 +0200 +@@ -35,6 +35,9 @@ + #define MEM_BLOCK_CACHED_MAGIC 0xFB8277DCL + + typedef struct _zend_mem_header { ++#if HARDENED_PHP_MM_PROTECT ++ unsigned int canary; ++#endif + #if ZEND_DEBUG + long magic; + char *filename; +diff -Nur php-5.0.4/Zend/zend_builtin_functions.c hardened-php-5.0.4-0.2.7/Zend/zend_builtin_functions.c +--- php-5.0.4/Zend/zend_builtin_functions.c 2005-03-14 10:13:14.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/Zend/zend_builtin_functions.c 2005-04-07 02:04:38.000000000 +0200 +@@ -52,6 +52,9 @@ + static ZEND_FUNCTION(crash); + #endif + #endif ++#if HARDENED_PHP_MM_PROTECT_DEBUG ++static ZEND_FUNCTION(heap_overflow); ++#endif + static ZEND_FUNCTION(get_included_files); + static ZEND_FUNCTION(is_subclass_of); + static ZEND_FUNCTION(is_a); +@@ -111,6 +114,9 @@ + ZEND_FE(crash, NULL) + #endif + #endif ++#if HARDENED_PHP_MM_PROTECT_DEBUG ++ ZEND_FE(heap_overflow, NULL) ++#endif + ZEND_FE(get_included_files, NULL) + ZEND_FALIAS(get_required_files, get_included_files, NULL) + ZEND_FE(is_subclass_of, NULL) +@@ -999,6 +1005,19 @@ + + #endif /* ZEND_DEBUG */ + ++ ++#if HARDENED_PHP_MM_PROTECT_DEBUG ++ZEND_FUNCTION(heap_overflow) ++{ ++ char *nowhere = emalloc(10); ++ ++ memcpy(nowhere, "something1234567890", sizeof("something1234567890")); ++ ++ efree(nowhere); ++} ++#endif ++ ++ + /* {{{ proto array get_included_files(void) + Returns an array with the file names that were include_once()'d */ + ZEND_FUNCTION(get_included_files) +diff -Nur php-5.0.4/Zend/zend_canary.c hardened-php-5.0.4-0.2.7/Zend/zend_canary.c +--- php-5.0.4/Zend/zend_canary.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/Zend/zend_canary.c 2005-04-07 02:04:38.000000000 +0200 +@@ -0,0 +1,58 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: zend_canary.c,v 1.1 2004/11/26 12:45:41 ionic Exp $ */ ++ ++#include "zend.h" ++ ++#include ++#include ++ ++ ++#if HARDENED_PHP_MM_PROTECT || HARDENED_PHP_LL_PROTECT || HARDENED_PHP_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++ZEND_API unsigned int zend_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nur php-5.0.4/Zend/zend_execute.c hardened-php-5.0.4-0.2.7/Zend/zend_execute.c +--- php-5.0.4/Zend/zend_execute.c 2005-03-21 17:22:10.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/Zend/zend_execute.c 2005-04-07 02:04:38.000000000 +0200 +@@ -3523,7 +3523,12 @@ + int dummy = 1; + zend_file_handle file_handle; + ++#if HARDENED_PHP_INC_PROTECT ++ if (zend_is_valid_include(inc_filename) ++ && (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC))) { ++#else + if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) { ++#endif + + if (!file_handle.opened_path) { + file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len); +@@ -3548,6 +3553,11 @@ + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: ++#if HARDENED_PHP_INC_PROTECT ++ if (!zend_is_valid_include(inc_filename)) { ++ break; ++ } ++#endif + new_op_array = compile_filename(opline->op2.u.constant.value.lval, inc_filename TSRMLS_CC); + break; + case ZEND_EVAL: { +diff -Nur php-5.0.4/Zend/zend_extensions.h hardened-php-5.0.4-0.2.7/Zend/zend_extensions.h +--- php-5.0.4/Zend/zend_extensions.h 2004-11-25 21:26:48.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/Zend/zend_extensions.h 2005-04-07 02:04:38.000000000 +0200 +@@ -24,10 +24,11 @@ + + #include "zend_compile.h" + +-/* The first number is the engine version and the rest is the date. ++/* The first number is a flag saying that Hardened-PHP is used ++ * the second number is the engine version and the rest is the date. + * This way engine 2 API no. is always greater than engine 1 API no.. + */ +-#define ZEND_EXTENSION_API_NO 220040412 ++#define ZEND_EXTENSION_API_NO 1220040412 + + typedef struct _zend_extension_version_info { + int zend_extension_api_no; +diff -Nur php-5.0.4/Zend/zend_hash.c hardened-php-5.0.4-0.2.7/Zend/zend_hash.c +--- php-5.0.4/Zend/zend_hash.c 2004-07-10 09:45:49.000000000 +0200 ++++ hardened-php-5.0.4-0.2.7/Zend/zend_hash.c 2005-04-07 02:06:13.000000000 +0200 +@@ -21,6 +21,18 @@ + + #include "zend.h" + ++#if HARDENED_PHP_HASH_PROTECT ++ unsigned int zend_hash_canary = 0x1234567; ++ zend_bool zend_hash_canary_inited = 0; ++#endif ++ ++#define CHECK_HASH_CANARY(hash) \ ++ if (zend_hash_canary != (hash)->canary) { \ ++ zend_security_log("Zend HashTable canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++ + #define CONNECT_TO_BUCKET_DLLIST(element, list_head) \ + (element)->pNext = (list_head); \ + (element)->pLast = NULL; \ +@@ -138,6 +150,9 @@ + { + uint i = 3; + Bucket **tmp; ++#if HARDENED_PHP_HASH_PROTECT ++ TSRMLS_FETCH(); ++#endif + + SET_INCONSISTENT(HT_OK); + +@@ -147,6 +162,13 @@ + + ht->nTableSize = 1 << i; + ht->nTableMask = ht->nTableSize - 1; ++#if HARDENED_PHP_HASH_PROTECT ++ if (zend_hash_canary_inited==0) { ++ zend_hash_canary = zend_canary(); ++ zend_hash_canary_inited = 1; ++ } ++ ht->canary = zend_hash_canary; ++#endif + ht->pDestructor = pDestructor; + ht->arBuckets = NULL; + ht->pListHead = NULL; +@@ -226,6 +248,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -291,6 +316,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -366,6 +394,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -414,7 +445,7 @@ + IS_CONSISTENT(ht); + + if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */ +- t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); ++ t = (Bucket **) perealloc(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); + if (t) { + HANDLE_BLOCK_INTERRUPTIONS(); + ht->arBuckets = t; +@@ -424,6 +455,7 @@ + HANDLE_UNBLOCK_INTERRUPTIONS(); + return SUCCESS; + } ++ zend_error(E_ERROR, "zend_hash_do_resize - out of memory"); + return FAILURE; + } + return SUCCESS; +@@ -487,6 +519,9 @@ + ht->pInternalPointer = p->pListNext; + } + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +@@ -516,6 +551,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -542,6 +580,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -571,6 +612,9 @@ + HANDLE_BLOCK_INTERRUPTIONS(); + + if (ht->pDestructor) { ++#if HARDENED_PHP_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +diff -Nur php-5.0.4/Zend/zend_hash.h hardened-php-5.0.4-0.2.7/Zend/zend_hash.h +--- php-5.0.4/Zend/zend_hash.h 2004-01-08 18:31:47.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/Zend/zend_hash.h 2005-04-07 02:04:38.000000000 +0200 +@@ -58,6 +58,9 @@ + } Bucket; + + typedef struct _hashtable { ++#if HARDENED_PHP_HASH_PROTECT ++ unsigned int canary; ++#endif + uint nTableSize; + uint nTableMask; + uint nNumOfElements; +diff -Nur php-5.0.4/Zend/zend_llist.c hardened-php-5.0.4-0.2.7/Zend/zend_llist.c +--- php-5.0.4/Zend/zend_llist.c 2004-01-08 18:31:47.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/Zend/zend_llist.c 2005-04-07 02:04:38.000000000 +0200 +@@ -22,9 +22,34 @@ + #include "zend.h" + #include "zend_llist.h" + #include "zend_qsort.h" ++#include "zend_globals.h" ++ ++#define CHECK_LIST_CANARY(list) \ ++ if (HG(canary_3) != (list)->canary_h || HG(canary_4) != (list)->canary_t) { \ ++ zend_security_log("linked list canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++#define CHECK_LISTELEMENT_CANARY(elem) \ ++ if (HG(canary_3) != (elem)->canary) { \ ++ zend_security_log("linked list element canary was overwritten"); \ ++ exit(1); \ ++ } ++ + + ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent) + { ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ ++ if (!HG(ll_canary_inited)) { ++ HG(canary_3) = zend_canary(); ++ HG(canary_4) = zend_canary(); ++ HG(ll_canary_inited) = 1; ++ } ++ l->canary_h = HG(canary_3); ++ l->canary_t = HG(canary_4); ++#endif + l->head = NULL; + l->tail = NULL; + l->count = 0; +@@ -38,6 +63,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->prev = l->tail; + tmp->next = NULL; + if (l->tail) { +@@ -56,6 +86,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->next = l->head; + tmp->prev = NULL; + if (l->head) { +@@ -93,10 +128,20 @@ + zend_llist_element *current=l->head; + zend_llist_element *next; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (compare(current->data, element)) { + DEL_LLIST_ELEMENT(current, l); ++#if HARDENED_PHP_LL_PROTECT ++ current->canary = 0; ++#endif + break; + } + current = next; +@@ -108,7 +153,14 @@ + { + zend_llist_element *current=l->head, *next; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (l->dtor) { + l->dtor(current->data); +@@ -133,7 +185,14 @@ + zend_llist_element *old_tail; + void *data; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if ((old_tail = l->tail)) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(old_tail) ++#endif + if (l->tail->prev) { + l->tail->prev->next = NULL; + } +@@ -159,9 +218,16 @@ + { + zend_llist_element *ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(src) ++#endif + zend_llist_init(dst, src->size, src->dtor, src->persistent); + ptr = src->head; + while (ptr) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(ptr) ++#endif + zend_llist_add_element(dst, ptr->data); + ptr = ptr->next; + } +@@ -172,11 +238,21 @@ + { + zend_llist_element *element, *next; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + element=l->head; + while (element) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + next = element->next; + if (func(element->data)) { + DEL_LLIST_ELEMENT(element, l); ++#if HARDENED_PHP_LL_PROTECT ++ element->canary = 0; ++#endif + } + element = next; + } +@@ -187,7 +263,13 @@ + { + zend_llist_element *element; + ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data TSRMLS_CC); + } + } +@@ -199,6 +281,9 @@ + zend_llist_element **elements; + zend_llist_element *element, **ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + if (l->count <= 0) { + return; + } +@@ -208,6 +293,9 @@ + ptr = &elements[0]; + + for (element=l->head; element; element=element->next) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + *ptr++ = element; + } + +@@ -230,7 +318,13 @@ + { + zend_llist_element *element; + ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, arg TSRMLS_CC); + } + } +@@ -241,8 +335,14 @@ + zend_llist_element *element; + va_list args; + ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + va_start(args, num_args); + for (element=l->head; element; element=element->next) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, num_args, args TSRMLS_CC); + } + va_end(args); +@@ -251,6 +351,10 @@ + + ZEND_API int zend_llist_count(zend_llist *l) + { ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + return l->count; + } + +@@ -259,8 +363,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->head; + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -272,8 +383,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->tail; + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -285,9 +403,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->next; + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +@@ -299,9 +427,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENED_PHP_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->prev; + if (*current) { ++#if HARDENED_PHP_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +diff -Nur php-5.0.4/Zend/zend_llist.h hardened-php-5.0.4-0.2.7/Zend/zend_llist.h +--- php-5.0.4/Zend/zend_llist.h 2004-01-08 18:31:47.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/Zend/zend_llist.h 2005-04-07 02:04:38.000000000 +0200 +@@ -23,6 +23,9 @@ + #define ZEND_LLIST_H + + typedef struct _zend_llist_element { ++#if HARDENED_PHP_LL_PROTECT ++ unsigned int canary; ++#endif + struct _zend_llist_element *next; + struct _zend_llist_element *prev; + char data[1]; /* Needs to always be last in the struct */ +@@ -35,6 +38,9 @@ + typedef void (*llist_apply_func_t)(void * TSRMLS_DC); + + typedef struct _zend_llist { ++#if HARDENED_PHP_LL_PROTECT ++ unsigned int canary_h; /* head */ ++#endif + zend_llist_element *head; + zend_llist_element *tail; + size_t count; +@@ -42,6 +48,9 @@ + llist_dtor_func_t dtor; + unsigned char persistent; + zend_llist_element *traverse_ptr; ++#if HARDENED_PHP_LL_PROTECT ++ unsigned int canary_t; /* tail */ ++#endif + } zend_llist; + + typedef zend_llist_element* zend_llist_position; +diff -Nur php-5.0.4/Zend/zend_modules.h hardened-php-5.0.4-0.2.7/Zend/zend_modules.h +--- php-5.0.4/Zend/zend_modules.h 2005-03-16 00:47:12.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/Zend/zend_modules.h 2005-04-07 02:04:38.000000000 +0200 +@@ -38,7 +38,7 @@ + extern struct _zend_arg_info fourth_arg_force_ref[5]; + extern struct _zend_arg_info all_args_by_ref[1]; + +-#define ZEND_MODULE_API_NO 20041030 ++#define ZEND_MODULE_API_NO 1020041030 + #ifdef ZTS + #define USING_ZTS 1 + #else +diff -Nur php-5.0.4/acinclude.m4 hardened-php-5.0.4-0.2.7/acinclude.m4 +--- php-5.0.4/acinclude.m4 2005-01-25 14:02:45.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/acinclude.m4 2005-04-07 02:04:39.000000000 +0200 +@@ -1169,6 +1169,36 @@ + fi + ]) + ++dnl ++dnl Check for broken realpath() ++dnl ++dnl realpath("/etc/hosts/../passwd",XXX) should not return ++dnl "/etc/passwd" ++dnl ++AC_DEFUN([PHP_AC_BROKEN_REALPATH],[ ++ AC_CACHE_CHECK(whether realpath is broken, ac_cv_broken_realpath,[ ++ AC_TRY_RUN([ ++main() { ++ char buf[4096+1]; ++ buf[0] = 0; ++ realpath("/etc/hosts/../passwd", buf); ++ exit(strcmp(buf, "/etc/passwd")==0); ++} ++ ],[ ++ ac_cv_broken_realpath=no ++ ],[ ++ ac_cv_broken_realpath=yes ++ ],[ ++ ac_cv_broken_realpath=no ++ ]) ++ ]) ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ AC_DEFINE(PHP_BROKEN_REALPATH, 1, [Whether realpath is broken]) ++ else ++ AC_DEFINE(PHP_BROKEN_REALPATH, 0, [Whether realpath is broken]) ++ fi ++]) ++ + dnl PHP_SHARED_MODULE(module-name, object-var, build-dir, cxx) + dnl + dnl Basically sets up the link-stage for building module-name +diff -Nur php-5.0.4/configure hardened-php-5.0.4-0.2.7/configure +--- php-5.0.4/configure 2005-04-03 11:42:50.000000000 +0200 ++++ hardened-php-5.0.4-0.2.7/configure 2005-04-07 02:04:39.000000000 +0200 +@@ -401,6 +401,16 @@ + ac_default_prefix=/usr/local + # Any additions from configure.in: + ac_help="$ac_help ++ --disable-hardened-php-mm-protect Disable the Memory Manager protection." ++ac_help="$ac_help ++ --disable-hardened-php-ll-protect Disable the Linked List protection." ++ac_help="$ac_help ++ --disable-hardened-php-inc-protect Disable include/require protection." ++ac_help="$ac_help ++ --disable-hardened-php-fmt-protect Disable format string protection." ++ac_help="$ac_help ++ --disable-hardened-php-hash-protect Disable Zend HashTable DTOR protection." ++ac_help="$ac_help + + SAPI modules: + " +@@ -857,6 +867,8 @@ + ac_help="$ac_help + --disable-tokenizer Disable tokenizer support" + ac_help="$ac_help ++ --disable-varfilter Disable Hardened-PHP's variable filter" ++ac_help="$ac_help + --enable-wddx Enable WDDX support." + ac_help="$ac_help + --disable-xml Disable XML support." +@@ -2749,6 +2761,157 @@ + + + ++# Check whether --enable-hardened-php-mm-protect or --disable-hardened-php-mm-protect was given. ++if test "${enable_hardened_php_mm_protect+set}" = set; then ++ enableval="$enable_hardened_php_mm_protect" ++ ++ DO_HARDENED_PHP_MM_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_MM_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardened-php-ll-protect or --disable-hardened-php-ll-protect was given. ++if test "${enable_hardened_php_ll_protect+set}" = set; then ++ enableval="$enable_hardened_php_ll_protect" ++ ++ DO_HARDENED_PHP_LL_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_LL_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardened-php-inc-protect or --disable-hardened-php-inc-protect was given. ++if test "${enable_hardened_php_inc_protect+set}" = set; then ++ enableval="$enable_hardened_php_inc_protect" ++ ++ DO_HARDENED_PHP_INC_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_INC_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardened-php-fmt-protect or --disable-hardened-php-fmt-protect was given. ++if test "${enable_hardened_php_fmt_protect+set}" = set; then ++ enableval="$enable_hardened_php_fmt_protect" ++ ++ DO_HARDENED_PHP_FMT_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_FMT_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardened-php-hash-protect or --disable-hardened-php-hash-protect was given. ++if test "${enable_hardened_php_hash_protect+set}" = set; then ++ enableval="$enable_hardened_php_hash_protect" ++ ++ DO_HARDENED_PHP_HASH_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENED_PHP_HASH_PROTECT=yes ++ ++fi ++ ++ ++echo $ac_n "checking whether to protect the Zend Memory Manager""... $ac_c" 1>&6 ++echo "configure:2725: checking whether to protect the Zend Memory Manager" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_MM_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend Linked Lists""... $ac_c" 1>&6 ++echo "configure:2729: checking whether to protect the Zend Linked Lists" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_LL_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect include/require statements""... $ac_c" 1>&6 ++echo "configure:2733: checking whether to protect include/require statements" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_INC_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect PHP Format String functions""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect PHP Format String functions" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_FMT_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend HashTable Destructors""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect the Zend HashTable Destructors" >&5 ++echo "$ac_t""$DO_HARDENED_PHP_HASH_PROTECT" 1>&6 ++ ++ ++cat >> confdefs.h <<\EOF ++#define HARDENED_PHP 1 ++EOF ++ ++ ++ ++if test "$DO_HARDENED_PHP_MM_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_MM_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_MM_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENED_PHP_LL_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_LL_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_LL_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENED_PHP_INC_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_INC_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_INC_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENED_PHP_FMT_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_FMT_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_FMT_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENED_PHP_HASH_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_HASH_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENED_PHP_HASH_PROTECT 0 ++EOF ++ ++fi + + + +@@ -17390,6 +17553,62 @@ + fi + + ++ echo $ac_n "checking whether realpath is broken""... $ac_c" 1>&6 ++echo "configure:14928: checking whether realpath is broken" >&5 ++if eval "test \"`echo '$''{'ac_cv_broken_realpath'+set}'`\" = set"; then ++ echo $ac_n "(cached) $ac_c" 1>&6 ++else ++ ++ if test "$cross_compiling" = yes; then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null ++then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ echo "configure: failed program was:" >&5 ++ cat conftest.$ac_ext >&5 ++ rm -fr conftest* ++ ++ ac_cv_broken_realpath=yes ++ ++fi ++rm -fr conftest* ++fi ++ ++ ++fi ++ ++echo "$ac_t""$ac_cv_broken_realpath" 1>&6 ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 1 ++EOF ++ ++ else ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 0 ++EOF ++ ++ fi ++ ++ + echo $ac_n "checking for declared timezone""... $ac_c" 1>&6 + echo "configure:17395: checking for declared timezone" >&5 + if eval "test \"`echo '$''{'ac_cv_declared_timezone'+set}'`\" = set"; then +@@ -86878,6 +87097,265 @@ + fi + + ++echo $ac_n "checking whether to enable Hardened-PHP's variable filter""... $ac_c" 1>&6 ++echo "configure:82041: checking whether to enable Hardened-PHP's variable filter" >&5 ++# Check whether --enable-varfilter or --disable-varfilter was given. ++if test "${enable_varfilter+set}" = set; then ++ enableval="$enable_varfilter" ++ PHP_VARFILTER=$enableval ++else ++ ++ PHP_VARFILTER=yes ++ ++ if test "$PHP_ENABLE_ALL" && test "yes" = "yes"; then ++ PHP_VARFILTER=$PHP_ENABLE_ALL ++ fi ++ ++fi ++ ++ ++ ++ext_output="yes, shared" ++ext_shared=yes ++case $PHP_VARFILTER in ++shared,*) ++ PHP_VARFILTER=`echo "$PHP_VARFILTER"|sed 's/^shared,//'` ++ ;; ++shared) ++ PHP_VARFILTER=yes ++ ;; ++no) ++ ext_output=no ++ ext_shared=no ++ ;; ++*) ++ ext_output=yes ++ ext_shared=no ++ ;; ++esac ++ ++ ++ ++echo "$ac_t""$ext_output" 1>&6 ++ ++ ++ ++ ++if test "$PHP_VARFILTER" != "no"; then ++ cat >> confdefs.h <<\EOF ++#define HAVE_VARFILTER 1 ++EOF ++ ++ ++ ext_builddir=ext/varfilter ++ ext_srcdir=$abs_srcdir/ext/varfilter ++ ++ ac_extra= ++ ++ if test "$ext_shared" != "shared" && test "$ext_shared" != "yes" && test "" != "cli"; then ++ ++ ++ ++ case ext/varfilter in ++ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;; ++ /*) ac_srcdir=`echo "ext/varfilter"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;; ++ *) ac_srcdir="$abs_srcdir/ext/varfilter/"; ac_bdir="ext/varfilter/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;; ++ esac ++ ++ ++ ++ b_c_pre=$php_c_pre ++ b_cxx_pre=$php_cxx_pre ++ b_c_meta=$php_c_meta ++ b_cxx_meta=$php_cxx_meta ++ b_c_post=$php_c_post ++ b_cxx_post=$php_cxx_post ++ b_lo=$php_lo ++ ++ ++ old_IFS=$IFS ++ for ac_src in varfilter.c; do ++ ++ IFS=. ++ set $ac_src ++ ac_obj=$1 ++ IFS=$old_IFS ++ ++ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo" ++ ++ case $ac_src in ++ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;; ++ *.cpp) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;; ++ esac ++ ++ cat >>Makefile.objects<>Makefile.objects<>Makefile.objects<> confdefs.h <>Makefile.objects<>Makefile.objects<&6 +@@ -97351,7 +97829,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + network.c php_open_temporary_file.c php_logos.c \ +- output.c ; do ++ output.c hardened_php.c ; do + + IFS=. + set $ac_src +@@ -97579,7 +98057,7 @@ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ + zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ +- zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c; do ++ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_canary.c; do + + IFS=. + set $ac_src +diff -Nur php-5.0.4/configure.in hardened-php-5.0.4-0.2.7/configure.in +--- php-5.0.4/configure.in 2005-03-30 23:43:12.000000000 +0200 ++++ hardened-php-5.0.4-0.2.7/configure.in 2005-04-07 02:04:39.000000000 +0200 +@@ -235,7 +235,7 @@ + sinclude(Zend/acinclude.m4) + sinclude(Zend/Zend.m4) + sinclude(TSRM/tsrm.m4) +- ++sinclude(main/hardened_php.m4) + + + divert(2) +@@ -620,6 +620,7 @@ + AC_FUNC_ALLOCA + dnl PHP_AC_BROKEN_SPRINTF + dnl PHP_AC_BROKEN_SNPRINTF ++PHP_AC_BROKEN_REALPATH + PHP_DECLARED_TIMEZONE + PHP_TIME_R_TYPE + PHP_READDIR_R_TYPE +@@ -1262,7 +1263,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + network.c php_open_temporary_file.c php_logos.c \ +- output.c ) ++ output.c hardened_php.c ) + + PHP_ADD_SOURCES(main/streams, streams.c cast.c memory.c filter.c \ + plain_wrapper.c userspace.c transports.c xp_socket.c mmap.c) +@@ -1280,7 +1281,7 @@ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ + zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ +- zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c) ++ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_canary.c ) + + if test -r "$abs_srcdir/Zend/zend_objects.c"; then + PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_mm.c \ +diff -Nur php-5.0.4/ext/standard/array.c hardened-php-5.0.4-0.2.7/ext/standard/array.c +--- php-5.0.4/ext/standard/array.c 2005-03-12 11:12:49.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/ext/standard/array.c 2005-04-07 02:04:39.000000000 +0200 +@@ -1255,6 +1255,31 @@ + } + } + } ++ ++ if (var_name[0] == 'H') { ++ if ((strcmp(var_name, "HTTP_GET_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_FILES")==0)|| ++ (strcmp(var_name, "HTTP_ENV_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(var_name, "HTTP_COOKIE_VARS")==0)) { ++ return 0; ++ } ++ } else if (var_name[0] == '_') { ++ if ((strcmp(var_name, "_COOKIE")==0)|| ++ (strcmp(var_name, "_ENV")==0)|| ++ (strcmp(var_name, "_FILES")==0)|| ++ (strcmp(var_name, "_GET")==0)|| ++ (strcmp(var_name, "_POST")==0)|| ++ (strcmp(var_name, "_REQUEST")==0)|| ++ (strcmp(var_name, "_SESSION")==0)|| ++ (strcmp(var_name, "_SERVER")==0)) { ++ return 0; ++ } ++ } else if (strcmp(var_name, "GLOBALS")==0) { ++ return 0; ++ } + + return 1; + } +diff -Nur php-5.0.4/ext/standard/basic_functions.c hardened-php-5.0.4-0.2.7/ext/standard/basic_functions.c +--- php-5.0.4/ext/standard/basic_functions.c 2005-03-10 13:10:57.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/ext/standard/basic_functions.c 2005-04-07 02:04:39.000000000 +0200 +@@ -617,7 +617,7 @@ + PHP_FALIAS(socket_get_status, stream_get_meta_data, NULL) + + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +- PHP_FE(realpath, NULL) ++ PHP_STATIC_FE("realpath", zif_real_path, NULL) + #endif + + #ifdef HAVE_FNMATCH +@@ -3124,6 +3124,34 @@ + memcpy(new_key, prefix, prefix_len); + memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + ++ if (new_key[0] == 'H') { ++ if ((strcmp(new_key, "HTTP_GET_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_FILES")==0)|| ++ (strcmp(new_key, "HTTP_ENV_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(new_key, "HTTP_COOKIE_VARS")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (new_key[0] == '_') { ++ if ((strcmp(new_key, "_COOKIE")==0)|| ++ (strcmp(new_key, "_ENV")==0)|| ++ (strcmp(new_key, "_FILES")==0)|| ++ (strcmp(new_key, "_GET")==0)|| ++ (strcmp(new_key, "_POST")==0)|| ++ (strcmp(new_key, "_REQUEST")==0)|| ++ (strcmp(new_key, "_SESSION")==0)|| ++ (strcmp(new_key, "_SERVER")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (strcmp(new_key, "GLOBALS")==0) { ++ efree(new_key); ++ return 0; ++ } ++ + zend_hash_del(&EG(symbol_table), new_key, new_key_len); + ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, (*var)->refcount+1, 0); + +diff -Nur php-5.0.4/ext/standard/file.c hardened-php-5.0.4-0.2.7/ext/standard/file.c +--- php-5.0.4/ext/standard/file.c 2005-03-27 17:53:30.000000000 +0200 ++++ hardened-php-5.0.4-0.2.7/ext/standard/file.c 2005-04-07 02:04:39.000000000 +0200 +@@ -2044,7 +2044,7 @@ + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) + /* {{{ proto string realpath(string path) + Return the resolved path */ +-PHP_FUNCTION(realpath) ++PHP_FUNCTION(real_path) + { + zval **path; + char resolved_path_buff[MAXPATHLEN]; +diff -Nur php-5.0.4/ext/standard/file.h hardened-php-5.0.4-0.2.7/ext/standard/file.h +--- php-5.0.4/ext/standard/file.h 2004-06-21 23:08:05.000000000 +0200 ++++ hardened-php-5.0.4-0.2.7/ext/standard/file.h 2005-04-07 02:04:39.000000000 +0200 +@@ -60,7 +60,7 @@ + PHP_FUNCTION(fd_set); + PHP_FUNCTION(fd_isset); + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +-PHP_FUNCTION(realpath); ++PHP_FUNCTION(real_path); + PHP_FUNCTION(fnmatch); + #endif + PHP_NAMED_FUNCTION(php_if_ftruncate); +diff -Nur php-5.0.4/ext/standard/info.c hardened-php-5.0.4-0.2.7/ext/standard/info.c +--- php-5.0.4/ext/standard/info.c 2004-05-02 15:23:30.000000000 +0200 ++++ hardened-php-5.0.4-0.2.7/ext/standard/info.c 2005-04-07 02:04:39.000000000 +0200 +@@ -394,7 +394,7 @@ + + if (flag & PHP_INFO_GENERAL) { + char *zend_version = get_zend_version(); +- char temp_api[10]; ++ char temp_api[11]; + char *logo_guid; + + php_uname = php_get_uname('a'); +@@ -415,11 +415,22 @@ + PUTS("\" alt=\"PHP Logo\" />"); + } + ++#if HARDENED_PHP ++ if (!sapi_module.phpinfo_as_text) { ++ php_printf("

Hardened-PHP Version %s/%s

\n", PHP_VERSION, HARDENED_PHP_VERSION); ++ } else { ++ char temp_ver[40]; ++ ++ snprintf(temp_ver, sizeof(temp_ver), "%s/%s", PHP_VERSION, HARDENED_PHP_VERSION); ++ php_info_print_table_row(2, "Hardened-PHP Version", temp_ver); ++ } ++#else + if (!sapi_module.phpinfo_as_text) { + php_printf("

PHP Version %s

\n", PHP_VERSION); + } else { + php_info_print_table_row(2, "PHP Version", PHP_VERSION); +- } ++ } ++#endif + php_info_print_box_end(); + php_info_print_table_start(); + php_info_print_table_row(2, "System", php_uname ); +diff -Nur php-5.0.4/ext/varfilter/CREDITS hardened-php-5.0.4-0.2.7/ext/varfilter/CREDITS +--- php-5.0.4/ext/varfilter/CREDITS 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/ext/varfilter/CREDITS 2005-04-07 02:04:39.000000000 +0200 +@@ -0,0 +1,2 @@ ++varfilter ++Stefan Esser +\ No newline at end of file +diff -Nur php-5.0.4/ext/varfilter/config.m4 hardened-php-5.0.4-0.2.7/ext/varfilter/config.m4 +--- php-5.0.4/ext/varfilter/config.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/ext/varfilter/config.m4 2005-04-07 02:04:39.000000000 +0200 +@@ -0,0 +1,11 @@ ++dnl ++dnl $Id: config.m4,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++dnl ++ ++PHP_ARG_ENABLE(varfilter, whether to enable Hardened-PHP's variable filter, ++[ --disable-varfilter Disable Hardened-PHP's variable filter], yes) ++ ++if test "$PHP_VARFILTER" != "no"; then ++ AC_DEFINE(HAVE_VARFILTER, 1, [ ]) ++ PHP_NEW_EXTENSION(varfilter, varfilter.c, $ext_shared) ++fi +diff -Nur php-5.0.4/ext/varfilter/php_varfilter.h hardened-php-5.0.4-0.2.7/ext/varfilter/php_varfilter.h +--- php-5.0.4/ext/varfilter/php_varfilter.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/ext/varfilter/php_varfilter.h 2005-04-07 02:04:39.000000000 +0200 +@@ -0,0 +1,72 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 4 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2003 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: php_varfilter.h,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifndef PHP_VARFILTER_H ++#define PHP_VARFILTER_H ++ ++extern zend_module_entry varfilter_module_entry; ++#define phpext_varfilter_ptr &varfilter_module_entry ++ ++#ifdef PHP_WIN32 ++#define PHP_VARFILTER_API __declspec(dllexport) ++#else ++#define PHP_VARFILTER_API ++#endif ++ ++#ifdef ZTS ++#include "TSRM.h" ++#endif ++ ++#include "SAPI.h" ++ ++PHP_MINIT_FUNCTION(varfilter); ++PHP_MSHUTDOWN_FUNCTION(varfilter); ++PHP_RINIT_FUNCTION(varfilter); ++PHP_RSHUTDOWN_FUNCTION(varfilter); ++PHP_MINFO_FUNCTION(varfilter); ++ ++ ++ZEND_BEGIN_MODULE_GLOBALS(varfilter) ++ long max_request_variables; ++ long cur_request_variables; ++ long max_varname_length; ++ long max_value_length; ++ long max_array_depth; ++ZEND_END_MODULE_GLOBALS(varfilter) ++ ++ ++#ifdef ZTS ++#define VARFILTER_G(v) TSRMG(varfilter_globals_id, zend_varfilter_globals *, v) ++#else ++#define VARFILTER_G(v) (varfilter_globals.v) ++#endif ++ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter); ++ ++#endif /* PHP_VARFILTER_H */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * indent-tabs-mode: t ++ * End: ++ */ +diff -Nur php-5.0.4/ext/varfilter/varfilter.c hardened-php-5.0.4-0.2.7/ext/varfilter/varfilter.c +--- php-5.0.4/ext/varfilter/varfilter.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/ext/varfilter/varfilter.c 2005-04-07 02:04:39.000000000 +0200 +@@ -0,0 +1,196 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 4 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2003 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: | ++ +----------------------------------------------------------------------+ ++ ++ $Id: varfilter.c,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "php.h" ++#include "php_ini.h" ++#include "ext/standard/info.h" ++#include "php_varfilter.h" ++#include "hardened_php.h" ++ ++ZEND_DECLARE_MODULE_GLOBALS(varfilter) ++ ++/* True global resources - no need for thread safety here */ ++static int le_varfilter; ++ ++/* {{{ varfilter_module_entry ++ */ ++zend_module_entry varfilter_module_entry = { ++#if ZEND_MODULE_API_NO >= 20010901 ++ STANDARD_MODULE_HEADER, ++#endif ++ "varfilter", ++ NULL, ++ PHP_MINIT(varfilter), ++ PHP_MSHUTDOWN(varfilter), ++ PHP_RINIT(varfilter), /* Replace with NULL if there's nothing to do at request start */ ++ PHP_RSHUTDOWN(varfilter), /* Replace with NULL if there's nothing to do at request end */ ++ PHP_MINFO(varfilter), ++#if ZEND_MODULE_API_NO >= 20010901 ++ "0.2.0", /* Replace with version number for your extension */ ++#endif ++ STANDARD_MODULE_PROPERTIES ++}; ++/* }}} */ ++ ++#ifdef COMPILE_DL_VARFILTER ++ZEND_GET_MODULE(varfilter) ++#endif ++ ++/* {{{ PHP_INI ++ */ ++PHP_INI_BEGIN() ++ STD_PHP_INI_ENTRY("varfilter.max_request_variables", "200", PHP_INI_SYSTEM, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_varname_length", "64", PHP_INI_SYSTEM, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_value_length", "10000", PHP_INI_SYSTEM, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_depth", "100", PHP_INI_SYSTEM, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++PHP_INI_END() ++/* }}} */ ++ ++/* {{{ php_varfilter_init_globals ++ */ ++static void php_varfilter_init_globals(zend_varfilter_globals *varfilter_globals) ++{ ++ varfilter_globals->max_request_variables = 200; ++ varfilter_globals->cur_request_variables = 0; ++ varfilter_globals->max_varname_length = 64; ++ varfilter_globals->max_value_length = 10000; ++ varfilter_globals->max_array_depth = 100; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINIT_FUNCTION ++ */ ++PHP_MINIT_FUNCTION(varfilter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(varfilter, php_varfilter_init_globals, NULL); ++ REGISTER_INI_ENTRIES(); ++ ++ sapi_register_input_filter(varfilter_input_filter); ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MSHUTDOWN_FUNCTION ++ */ ++PHP_MSHUTDOWN_FUNCTION(varfilter) ++{ ++ UNREGISTER_INI_ENTRIES(); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request start */ ++/* {{{ PHP_RINIT_FUNCTION ++ */ ++PHP_RINIT_FUNCTION(varfilter) ++{ ++ VARFILTER_G(cur_request_variables) = 0; ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request end */ ++/* {{{ PHP_RSHUTDOWN_FUNCTION ++ */ ++PHP_RSHUTDOWN_FUNCTION(varfilter) ++{ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINFO_FUNCTION ++ */ ++PHP_MINFO_FUNCTION(varfilter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_header(2, "Hardened-PHP's variable filter support", "enabled"); ++ php_info_print_table_end(); ++ ++ DISPLAY_INI_ENTRIES(); ++} ++/* }}} */ ++ ++/* {{{ SAPI_INPUT_FILTER_FUNC ++ */ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter) ++{ ++ char *index; ++ unsigned int var_len, depth = 0; ++ ++ /* Drop this variable if the limit is reached */ ++ if (VARFILTER_G(max_request_variables) == VARFILTER_G(cur_request_variables)) { ++ php_security_log("tried to register too many variables"); ++ return 0; ++ } ++ ++ /* Drop this variable if it exceeds the value length limit */ ++ if (VARFILTER_G(max_value_length) < val_len) { ++ php_security_log("tried to register a variable with a too long value"); ++ return 0; ++ } ++ ++ /* Find length of variable name */ ++ index = strchr(var, '['); ++ var_len = index ? index-var : strlen(var); ++ ++ /* Drop this variable if it exceeds the varname length limit */ ++ if (VARFILTER_G(max_varname_length) < var_len) { ++ php_security_log("tried to register a variable with a too long variable name"); ++ return 0; ++ } ++ ++ /* Find out array depth */ ++ while (index) { ++ depth++; ++ index = strchr(index+1, '['); ++ } ++ ++ /* Drop this variable if it exceeds the array depth limit */ ++ if (VARFILTER_G(max_array_depth) < depth) { ++ php_security_log("tried to register a too deep array variable"); ++ return 0; ++ } ++ ++ /* Okay let PHP register this variable */ ++ VARFILTER_G(cur_request_variables)++; ++ ++ if (new_val_len) { ++ *new_val_len = val_len; ++ } ++ ++ return 1; ++} ++/* }}} */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: noet sw=4 ts=4 fdm=marker ++ * vim<600: noet sw=4 ts=4 ++ */ +diff -Nur php-5.0.4/main/SAPI.c hardened-php-5.0.4-0.2.7/main/SAPI.c +--- php-5.0.4/main/SAPI.c 2005-02-22 15:46:15.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/main/SAPI.c 2005-04-07 02:04:39.000000000 +0200 +@@ -821,6 +821,12 @@ + zend_hash_del(&known_post_content_types, post_entry->content_type, post_entry->content_type_len+1); + } + ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) ++{ ++ sapi_module.input_filter = input_filter; ++ return SUCCESS; ++} ++ + + SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D)) + { +@@ -835,11 +841,6 @@ + return SUCCESS; + } + +-SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) +-{ +- sapi_module.input_filter = input_filter; +- return SUCCESS; +-} + + SAPI_API int sapi_flush(TSRMLS_D) + { +diff -Nur php-5.0.4/main/SAPI.h hardened-php-5.0.4-0.2.7/main/SAPI.h +--- php-5.0.4/main/SAPI.h 2004-01-08 18:33:04.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/main/SAPI.h 2005-04-07 02:04:39.000000000 +0200 +@@ -103,9 +103,14 @@ + char *current_user; + int current_user_length; + +- /* this is necessary for CLI module */ +- int argc; +- char **argv; ++ /* this is necessary for CLI module */ ++ int argc; ++ char **argv; ++ ++#if HARDENED_PHP ++ /* this is necessary for IP logging */ ++ char ip_address[64]; ++#endif + } sapi_request_info; + + +@@ -270,7 +275,11 @@ + + #define SAPI_DEFAULT_MIMETYPE "text/html" + #define SAPI_DEFAULT_CHARSET "" ++#if HARDENED_PHP ++#define SAPI_PHP_VERSION_HEADER "X-Powered-By: Hardened-PHP/" PHP_VERSION ++#else + #define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION ++#endif + + #define SAPI_POST_READER_FUNC(post_reader) void post_reader(TSRMLS_D) + #define SAPI_POST_HANDLER_FUNC(post_handler) void post_handler(char *content_type_dup, void *arg TSRMLS_DC) +diff -Nur php-5.0.4/main/fopen_wrappers.c hardened-php-5.0.4-0.2.7/main/fopen_wrappers.c +--- php-5.0.4/main/fopen_wrappers.c 2005-03-11 07:55:22.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/main/fopen_wrappers.c 2005-04-07 02:05:49.000000000 +0200 +@@ -163,6 +163,21 @@ + char *pathbuf; + char *ptr; + char *end; ++ char path_copy[MAXPATHLEN]; ++ int path_len; ++ ++ /* Special case path ends with a trailing slash */ ++ path_len = strlen(path); ++ if (path_len >= MAXPATHLEN) { ++ errno = EPERM; /* we deny permission to open it */ ++ return -1; ++ } ++ if (path_len > 0 && path[path_len-1] == PHP_DIR_SEPARATOR) { ++ memcpy(path_copy, path, path_len+1); ++ while (path_len > 0 && path_copy[path_len-1] == PHP_DIR_SEPARATOR) path_len--; ++ path_copy[path_len] = '\0'; ++ path = (const char *)&path_copy; ++ } + + pathbuf = estrdup(PG(open_basedir)); + +diff -Nur php-5.0.4/main/hardened_globals.h hardened-php-5.0.4-0.2.7/main/hardened_globals.h +--- php-5.0.4/main/hardened_globals.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/main/hardened_globals.h 2005-04-07 02:04:39.000000000 +0200 +@@ -0,0 +1,54 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_GLOBALS_H ++#define HARDENED_GLOBALS_H ++ ++typedef struct _hardened_globals hardened_globals_struct; ++ ++#ifdef ZTS ++# define HG(v) TSRMG(hardened_globals_id, hardened_globals_struct *, v) ++extern int hardened_globals_id; ++#else ++# define HG(v) (hardened_globals.v) ++extern struct _hardened_globals hardened_globals; ++#endif ++ ++ ++struct _hardened_globals { ++#if HARDENED_PHP_MM_PROTECT ++ unsigned int canary_1; ++ unsigned int canary_2; ++#endif ++#if HARDENED_PHP_LL_PROTECT ++ unsigned int canary_3; ++ unsigned int canary_4; ++ unsigned int ll_canary_inited; ++#endif ++ unsigned int dummy; ++}; ++ ++ ++#endif /* HARDENED_GLOBALS_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nur php-5.0.4/main/hardened_php.c hardened-php-5.0.4-0.2.7/main/hardened_php.c +--- php-5.0.4/main/hardened_php.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/main/hardened_php.c 2005-04-07 02:04:39.000000000 +0200 +@@ -0,0 +1,205 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: hardened_php.c,v 1.2 2004/11/21 09:38:52 ionic Exp $ */ ++ ++#include "php.h" ++ ++#include ++#include ++ ++#if HAVE_UNISTD_H ++#include ++#endif ++#include "SAPI.h" ++#include "php_globals.h" ++ ++#if HARDENED_PHP ++ ++#ifdef HAVE_SYS_SOCKET_H ++#include ++#endif ++ ++#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE) ++#undef AF_UNIX ++#endif ++ ++#if defined(AF_UNIX) ++#include ++#endif ++ ++#define SYSLOG_PATH "/dev/log" ++ ++#include "snprintf.h" ++ ++#ifdef ZTS ++#include "hardened_globals.h" ++int hardened_globals_id; ++#else ++struct _hardened_globals hardened_globals; ++#endif ++ ++static void hardened_globals_ctor(hardened_globals_struct *hardened_globals TSRMLS_DC) ++{ ++ memset(hardened_globals, 0, sizeof(*hardened_globals)); ++} ++ ++PHPAPI void hardened_startup() ++{ ++#ifdef ZTS ++ ts_allocate_id(&hardened_globals_id, sizeof(hardened_globals_struct), (ts_allocate_ctor) hardened_globals_ctor, NULL); ++#else ++ hardened_globals_ctor(&hardened_globals TSRMLS_CC); ++#endif ++} ++ ++PHPAPI void php_security_log(char *str) ++{ ++#if defined(AF_UNIX) ++ int s, r; ++ struct sockaddr_un saun; ++ char buf[1024]; ++ char *ip_address; ++ char *fname; ++ TSRMLS_FETCH(); ++ ++ ip_address = sapi_getenv("REMOTE_ADDR", 11 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "REMOTE_ADDR not set"; ++ } ++ ++ fname = sapi_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC); ++ ++ ap_php_snprintf(buf, 1024, "php security-alert: %s (attacker '%s', file '%s')\n", str, ip_address, fname); ++ ++ s = socket(AF_UNIX, SOCK_DGRAM, 0); ++ if (s == -1) { ++ return; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ s = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (s == -1) { ++ return; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ return; ++ } ++ } ++ send(s, buf, strlen(buf), 0); ++ ++ close(s); ++#endif ++} ++#endif ++ ++#if HARDENED_PHP_MM_PROTECT || HARDENED_PHP_LL_PROTECT || HARDENED_PHP_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++PHPAPI unsigned int php_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++#if HARDENED_PHP_INC_PROTECT ++ ++PHPAPI int php_is_valid_include(zval *z) ++{ ++ char *filename; ++ int len; ++ TSRMLS_FETCH(); ++ ++ /* must be of type string */ ++ if (z->type != IS_STRING || z->value.str.val == NULL) { ++ return (0); ++ } ++ ++ /* short cut */ ++ filename = z->value.str.val; ++ len = z->value.str.len; ++ ++ /* 1. must be shorter than MAXPATHLEN */ ++ if (len > MAXPATHLEN) { ++ php_security_log("Include filename longer than MAXPATHLEN chars"); ++ return (0); ++ } ++ ++ /* 2. must not be cutted */ ++ if (len != strlen(filename)) { ++ php_security_log("Include filename has a \\0 cut"); ++ return (0); ++ } ++ ++ /* 3. must not be a URL */ ++ if (strstr(filename, "://")) { ++ php_security_log("Include filename is an URL"); ++ return (0); ++ } ++ ++ /* 4. must not be an uploaded file */ ++ if (SG(rfc1867_uploaded_files)) { ++ if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, len+1)) { ++ php_security_log("Include filename is an uploaded file"); ++ return (0); ++ } ++ } ++ ++ /* passed all tests */ ++ return (1); ++} ++ ++#endif ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nur php-5.0.4/main/hardened_php.h hardened-php-5.0.4-0.2.7/main/hardened_php.h +--- php-5.0.4/main/hardened_php.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/main/hardened_php.h 2005-04-07 02:05:01.000000000 +0200 +@@ -0,0 +1,45 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_PHP_H ++#define HARDENED_PHP_H ++ ++#include "zend.h" ++ ++#if HARDENED_PHP ++PHPAPI void php_security_log(char *str); ++PHPAPI void hardened_startup(); ++#define HARDENED_PHP_VERSION "0.2.7" ++#endif ++ ++#if HARDENED_PHP_MM_PROTECT || HARDENED_PHP_LL_PROTECT || HARDENED_PHP_HASH_PROTECT ++PHPAPI unsigned int php_canary(); ++#endif ++ ++#if HARDENED_PHP_INC_PROTECT ++PHPAPI int php_is_valid_include(zval *z); ++#endif ++ ++#endif /* HARDENED_PHP_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nur php-5.0.4/main/hardened_php.m4 hardened-php-5.0.4-0.2.7/main/hardened_php.m4 +--- php-5.0.4/main/hardened_php.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/main/hardened_php.m4 2005-04-07 02:04:39.000000000 +0200 +@@ -0,0 +1,95 @@ ++dnl ++dnl $Id: hardened_php.m4,v 1.1 2004/11/14 13:24:24 ionic Exp $ ++dnl ++dnl This file contains Hardened-PHP specific autoconf functions. ++dnl ++ ++AC_ARG_ENABLE(hardened-php-mm-protect, ++[ --disable-hardened-php-mm-protect Disable the Memory Manager protection.],[ ++ DO_HARDENED_PHP_MM_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_MM_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardened-php-ll-protect, ++[ --disable-hardened-php-ll-protect Disable the Linked List protection.],[ ++ DO_HARDENED_PHP_LL_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_LL_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardened-php-inc-protect, ++[ --disable-hardened-php-inc-protect Disable include/require protection.],[ ++ DO_HARDENED_PHP_INC_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_INC_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardened-php-fmt-protect, ++[ --disable-hardened-php-fmt-protect Disable format string protection.],[ ++ DO_HARDENED_PHP_FMT_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_FMT_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardened-php-hash-protect, ++[ --disable-hardened-php-hash-protect Disable HashTable destructor protection.],[ ++ DO_HARDENED_PHP_HASH_PROTECT=$enableval ++],[ ++ DO_HARDENED_PHP_HASH_PROTECT=yes ++]) ++ ++AC_MSG_CHECKING(whether to protect the Zend Memory Manager) ++AC_MSG_RESULT($DO_HARDENED_PHP_MM_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the Zend Linked Lists) ++AC_MSG_RESULT($DO_HARDENED_PHP_LL_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect include/require statements) ++AC_MSG_RESULT($DO_HARDENED_PHP_INC_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect PHP Format String functions) ++AC_MSG_RESULT($DO_HARDENED_PHP_FMT_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the destructor of Zend HashTables) ++AC_MSG_RESULT($DO_HARDENED_PHP_HASH_PROTECT) ++ ++ ++AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ ++ ++if test "$DO_HARDENED_PHP_MM_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_MM_PROTECT, 1, [Memory Manager Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_MM_PROTECT, 0, [Memory Manager Protection]) ++fi ++ ++if test "$DO_HARDENED_PHP_LL_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_LL_PROTECT, 1, [Linked List Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_LL_PROTECT, 0, [Linked List Protection]) ++fi ++ ++if test "$DO_HARDENED_PHP_INC_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_INC_PROTECT, 1, [Include/Require Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_INC_PROTECT, 0, [Include/Require Protection]) ++fi ++ ++if test "$DO_HARDENED_PHP_FMT_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_FMT_PROTECT, 1, [Fmt String Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_FMT_PROTECT, 0, [Fmt String Protection]) ++fi ++ ++if test "$DO_HARDENED_PHP_HASH_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENED_PHP, 1, [Hardened-PHP]) ++ AC_DEFINE(HARDENED_PHP_HASH_PROTECT, 1, [HashTable DTOR Protection]) ++else ++ AC_DEFINE(HARDENED_PHP_HASH_PROTECT, 0, [HashTable DTOR Protection]) ++fi ++ +diff -Nur php-5.0.4/main/main.c hardened-php-5.0.4-0.2.7/main/main.c +--- php-5.0.4/main/main.c 2005-03-24 02:11:35.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/main/main.c 2005-04-07 02:04:39.000000000 +0200 +@@ -92,6 +92,10 @@ + + #include "SAPI.h" + #include "rfc1867.h" ++#if HARDENED_PHP ++#include "hardened_globals.h" ++#endif ++ + /* }}} */ + + #ifndef ZTS +@@ -116,10 +120,33 @@ + */ + static PHP_INI_MH(OnChangeMemoryLimit) + { ++#if HARDENED_PHP ++ long orig_memory_limit; ++ ++ if (entry->modified) { ++ orig_memory_limit = zend_atoi(entry->orig_value, entry->orig_value_length); ++ } else { ++ orig_memory_limit = 1<<30; ++ } ++ if (orig_memory_limit < 0 || orig_memory_limit > (1<<30)) { ++ orig_memory_limit = 1<<30; ++ } ++#endif + if (new_value) { + PG(memory_limit) = zend_atoi(new_value, new_value_length); ++#if HARDENED_PHP ++ if (PG(memory_limit) > orig_memory_limit) { ++ PG(memory_limit) = orig_memory_limit; ++ php_security_log("script tried to increase memory_limit above allowed value"); ++ return FAILURE; ++ } ++#endif + } else { ++#if HARDENED_PHP ++ PG(memory_limit) = orig_memory_limit; ++#else + PG(memory_limit) = 1<<30; /* effectively, no limit */ ++#endif + } + return zend_set_memory_limit(PG(memory_limit)); + } +@@ -1313,6 +1340,10 @@ + tsrm_ls = ts_resource(0); + #endif + ++#if HARDENED_PHP ++ hardened_startup(); ++#endif ++ + module_shutdown = 0; + module_startup = 1; + sapi_initialize_empty_request(TSRMLS_C); +@@ -1326,6 +1357,12 @@ + + php_output_startup(); + ++#if HARDENED_PHP_INC_PROTECT ++ zuf.is_valid_include = php_is_valid_include; ++#endif ++#if HARDENED_PHP ++ zuf.security_log_function = php_security_log; ++#endif + zuf.error_function = php_error_cb; + zuf.printf_function = php_printf; + zuf.write_function = php_body_write_wrapper; +@@ -1429,6 +1466,10 @@ + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, sizeof(PHP_CONFIG_FILE_PATH)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS); ++#if HARDENED_PHP ++ REGISTER_MAIN_LONG_CONSTANT("HARDENED_PHP", 1, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_STRINGL_CONSTANT("HARDENED_PHP_VERSION", HARDENED_PHP_VERSION, sizeof(HARDENED_PHP_VERSION)-1, CONST_PERSISTENT | CONST_CS); ++#endif + REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS); + php_output_register_constants(TSRMLS_C); + php_rfc1867_register_constants(TSRMLS_C); +diff -Nur php-5.0.4/main/php.h hardened-php-5.0.4-0.2.7/main/php.h +--- php-5.0.4/main/php.h 2005-03-14 10:41:39.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/main/php.h 2005-04-07 02:04:39.000000000 +0200 +@@ -35,11 +35,19 @@ + #include "zend_qsort.h" + #include "php_compat.h" + ++ + #include "zend_API.h" + + #undef sprintf + #define sprintf php_sprintf + ++#if HARDENED_PHP ++#if HAVE_REALPATH ++#undef realpath ++#define realpath php_realpath ++#endif ++#endif ++ + /* PHP's DEBUG value must match Zend's ZEND_DEBUG value */ + #undef PHP_DEBUG + #define PHP_DEBUG ZEND_DEBUG +@@ -341,6 +349,7 @@ + #define PHP_FUNCTION ZEND_FUNCTION + #define PHP_METHOD ZEND_METHOD + ++#define PHP_STATIC_FE ZEND_STATIC_FE + #define PHP_NAMED_FE ZEND_NAMED_FE + #define PHP_FE ZEND_FE + #define PHP_FALIAS ZEND_FALIAS +@@ -446,6 +455,10 @@ + #endif + #endif /* !XtOffsetOf */ + ++#if HARDENED_PHP ++#include "hardened_php.h" ++#endif ++ + #endif + + /* +diff -Nur php-5.0.4/main/php_config.h.in hardened-php-5.0.4-0.2.7/main/php_config.h.in +--- php-5.0.4/main/php_config.h.in 2005-04-03 11:42:53.000000000 +0200 ++++ hardened-php-5.0.4-0.2.7/main/php_config.h.in 2005-04-07 02:04:39.000000000 +0200 +@@ -746,6 +746,39 @@ + /* hardcode for each of the cross compiler host */ + #undef PHP_UNAME + ++/* Hardened-PHP */ ++#undef HARDENED_PHP ++ ++/* Memory Manager Protection */ ++#undef HARDENED_PHP_MM_PROTECT ++ ++/* Memory Manager Protection */ ++#undef HARDENED_PHP_MM_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENED_PHP_LL_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENED_PHP_LL_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENED_PHP_INC_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENED_PHP_INC_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENED_PHP_FMT_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENED_PHP_FMT_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENED_PHP_HASH_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENED_PHP_HASH_PROTECT ++ + /* Whether you have AOLserver */ + #undef HAVE_AOLSERVER + +@@ -1077,6 +1110,12 @@ + /* Define if you have the getaddrinfo function */ + #undef HAVE_GETADDRINFO + ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ + /* Whether system headers declare timezone */ + #undef HAVE_DECLARED_TIMEZONE + +diff -Nur php-5.0.4/main/snprintf.c hardened-php-5.0.4-0.2.7/main/snprintf.c +--- php-5.0.4/main/snprintf.c 2004-11-16 00:14:40.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/main/snprintf.c 2005-04-07 02:04:39.000000000 +0200 +@@ -1013,7 +1013,11 @@ + + + case 'n': ++#if HARDENED_PHP_FMT_PROTECT ++ php_security_log("'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Nur php-5.0.4/main/spprintf.c hardened-php-5.0.4-0.2.7/main/spprintf.c +--- php-5.0.4/main/spprintf.c 2004-04-16 01:04:49.000000000 +0200 ++++ hardened-php-5.0.4-0.2.7/main/spprintf.c 2005-04-07 02:04:39.000000000 +0200 +@@ -630,7 +630,11 @@ + + + case 'n': ++#if HARDENED_PHP_FMT_PROTECT ++ php_security_log("'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = xbuf->len; ++#endif + break; + + /* +diff -Nur php-5.0.4/php.ini-dist hardened-php-5.0.4-0.2.7/php.ini-dist +--- php-5.0.4/php.ini-dist 2005-03-01 01:25:09.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/php.ini-dist 2005-04-07 02:04:39.000000000 +0200 +@@ -1187,6 +1187,23 @@ + ; instead of original one. + soap.wsdl_cache_ttl=86400 + ++[varfilter] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardened-PHP's variable filter ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Maximum number of input variables per request ++varfilter.max_request_variables = 200 ++ ++; Maximum characters in input variable names ++varfilter.max_varname_length = 64 ++ ++; Maximum length of input variable values ++varfilter.max_value_length = 10000 ++ ++; Maximum depth of input variable arrays ++varfilter.max_array_depth = 100 ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nur php-5.0.4/php.ini-recommended hardened-php-5.0.4-0.2.7/php.ini-recommended +--- php-5.0.4/php.ini-recommended 2005-03-01 01:25:09.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/php.ini-recommended 2005-04-07 02:04:39.000000000 +0200 +@@ -1245,6 +1245,23 @@ + ; instead of original one. + soap.wsdl_cache_ttl=86400 + ++[varfilter] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardened-PHP's variable filter ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Maximum number of input variables per request ++varfilter.max_request_variables = 200 ++ ++; Maximum characters in input variable names ++varfilter.max_varname_length = 64 ++ ++; Maximum length of input variable values ++varfilter.max_value_length = 10000 ++ ++; Maximum depth of input variable arrays ++varfilter.max_array_depth = 100 ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nur php-5.0.4/sapi/apache/mod_php5.c hardened-php-5.0.4-0.2.7/sapi/apache/mod_php5.c +--- php-5.0.4/sapi/apache/mod_php5.c 2004-07-14 11:43:26.000000000 +0200 ++++ hardened-php-5.0.4-0.2.7/sapi/apache/mod_php5.c 2005-04-07 02:04:39.000000000 +0200 +@@ -447,7 +447,7 @@ + sapi_apache_get_fd, + sapi_apache_force_http_10, + sapi_apache_get_target_uid, +- sapi_apache_get_target_gid ++ sapi_apache_get_target_gid, + }; + /* }}} */ + +@@ -899,7 +899,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENED_PHP ++ ap_add_version_component("Hardened-PHP/" PHP_VERSION); ++#else + ap_add_version_component("PHP/" PHP_VERSION); ++#endif + } + } + #endif +diff -Nur php-5.0.4/sapi/apache2filter/sapi_apache2.c hardened-php-5.0.4-0.2.7/sapi/apache2filter/sapi_apache2.c +--- php-5.0.4/sapi/apache2filter/sapi_apache2.c 2005-01-07 07:28:24.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/sapi/apache2filter/sapi_apache2.c 2005-04-07 02:04:39.000000000 +0200 +@@ -572,7 +572,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENED_PHP ++ ap_add_version_component(p, "Hardened-PHP/" PHP_VERSION); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nur php-5.0.4/sapi/apache2handler/sapi_apache2.c hardened-php-5.0.4-0.2.7/sapi/apache2handler/sapi_apache2.c +--- php-5.0.4/sapi/apache2handler/sapi_apache2.c 2005-03-10 12:23:57.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/sapi/apache2handler/sapi_apache2.c 2005-04-07 02:04:39.000000000 +0200 +@@ -340,7 +340,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENED_PHP ++ ap_add_version_component(p, "Hardened-PHP/" PHP_VERSION); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nur php-5.0.4/sapi/cgi/cgi_main.c hardened-php-5.0.4-0.2.7/sapi/cgi/cgi_main.c +--- php-5.0.4/sapi/cgi/cgi_main.c 2005-02-11 03:06:48.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/sapi/cgi/cgi_main.c 2005-04-07 02:04:39.000000000 +0200 +@@ -1414,11 +1414,19 @@ + SG(headers_sent) = 1; + SG(request_info).no_headers = 1; + } ++#if HARDENED_PHP ++#if ZEND_DEBUG ++ php_printf("Hardened-PHP %s/%s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENED_PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("Hardened-PHP %s/%s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENED_PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit(1); + break; +diff -Nur php-5.0.4/sapi/cli/php_cli.c hardened-php-5.0.4-0.2.7/sapi/cli/php_cli.c +--- php-5.0.4/sapi/cli/php_cli.c 2005-03-22 16:09:20.000000000 +0100 ++++ hardened-php-5.0.4-0.2.7/sapi/cli/php_cli.c 2005-04-07 02:04:39.000000000 +0200 +@@ -694,11 +694,19 @@ + if (php_request_startup(TSRMLS_C)==FAILURE) { + goto err; + } ++#if HARDENED_PHP ++#if ZEND_DEBUG ++ php_printf("Hardened-PHP %s/%s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENED_PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("Hardened-PHP %s/%s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENED_PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit_status=1; + goto out; diff --git a/0.3.2/hardening-patch-4.3.11-0.3.2.patch b/0.3.2/hardening-patch-4.3.11-0.3.2.patch new file mode 100644 index 0000000..f3ecb0f --- /dev/null +++ b/0.3.2/hardening-patch-4.3.11-0.3.2.patch @@ -0,0 +1,12205 @@ +diff -Naur php-4.3.11/acinclude.m4 hardening-patch-4.3.11-0.3.2/acinclude.m4 +--- php-4.3.11/acinclude.m4 2005-01-25 14:03:06.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/acinclude.m4 2005-07-09 08:53:02.427369648 +0200 +@@ -1173,6 +1173,36 @@ + fi + ]) + ++dnl ++dnl Check for broken realpath() ++dnl ++dnl realpath("/etc/hosts/../passwd",XXX) should not return ++dnl "/etc/passwd" ++dnl ++AC_DEFUN([PHP_AC_BROKEN_REALPATH],[ ++ AC_CACHE_CHECK(whether realpath is broken, ac_cv_broken_realpath,[ ++ AC_TRY_RUN([ ++main() { ++ char buf[4096+1]; ++ buf[0] = 0; ++ realpath("/etc/hosts/../passwd", buf); ++ exit(strcmp(buf, "/etc/passwd")==0); ++} ++ ],[ ++ ac_cv_broken_realpath=no ++ ],[ ++ ac_cv_broken_realpath=yes ++ ],[ ++ ac_cv_broken_realpath=no ++ ]) ++ ]) ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ AC_DEFINE(PHP_BROKEN_REALPATH, 1, [Whether realpath is broken]) ++ else ++ AC_DEFINE(PHP_BROKEN_REALPATH, 0, [Whether realpath is broken]) ++ fi ++]) ++ + dnl PHP_SHARED_MODULE(module-name, object-var, build-dir, cxx) + dnl + dnl Basically sets up the link-stage for building module-name +diff -Naur php-4.3.11/configure hardening-patch-4.3.11-0.3.2/configure +--- php-4.3.11/configure 2005-03-30 16:35:34.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/configure 2005-07-09 08:53:02.464364024 +0200 +@@ -394,6 +394,16 @@ + ac_default_prefix=/usr/local + # Any additions from configure.in: + ac_help="$ac_help ++ --disable-hardening-patch-mm-protect Disable the Memory Manager protection." ++ac_help="$ac_help ++ --disable-hardening-patch-ll-protect Disable the Linked List protection." ++ac_help="$ac_help ++ --disable-hardening-patch-inc-protect Disable include/require protection." ++ac_help="$ac_help ++ --disable-hardening-patch-fmt-protect Disable format string protection." ++ac_help="$ac_help ++ --disable-hardening-patch-hash-protect Disable Zend HashTable DTOR protection." ++ac_help="$ac_help + + SAPI modules: + " +@@ -846,6 +856,8 @@ + ac_help="$ac_help + --disable-tokenizer Disable tokenizer support" + ac_help="$ac_help ++ --disable-varfilter Disable Hardening-Patch's variable filter" ++ac_help="$ac_help + --enable-wddx Enable WDDX support." + ac_help="$ac_help + --disable-xml Disable XML support using bundled expat lib" +@@ -2669,6 +2681,157 @@ + + + ++# Check whether --enable-hardening-patch-mm-protect or --disable-hardening-patch-mm-protect was given. ++if test "${enable_hardening_patch_mm_protect+set}" = set; then ++ enableval="$enable_hardening_patch_mm_protect" ++ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-ll-protect or --disable-hardening-patch-ll-protect was given. ++if test "${enable_hardening_patch_ll_protect+set}" = set; then ++ enableval="$enable_hardening_patch_ll_protect" ++ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-inc-protect or --disable-hardening-patch-inc-protect was given. ++if test "${enable_hardening_patch_inc_protect+set}" = set; then ++ enableval="$enable_hardening_patch_inc_protect" ++ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-fmt-protect or --disable-hardening-patch-fmt-protect was given. ++if test "${enable_hardening_patch_fmt_protect+set}" = set; then ++ enableval="$enable_hardening_patch_fmt_protect" ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-hash-protect or --disable-hardening-patch-hash-protect was given. ++if test "${enable_hardening_patch_hash_protect+set}" = set; then ++ enableval="$enable_hardening_patch_hash_protect" ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++ ++fi ++ ++ ++echo $ac_n "checking whether to protect the Zend Memory Manager""... $ac_c" 1>&6 ++echo "configure:2725: checking whether to protect the Zend Memory Manager" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_MM_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend Linked Lists""... $ac_c" 1>&6 ++echo "configure:2729: checking whether to protect the Zend Linked Lists" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_LL_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect include/require statements""... $ac_c" 1>&6 ++echo "configure:2733: checking whether to protect include/require statements" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_INC_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect PHP Format String functions""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect PHP Format String functions" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_FMT_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend HashTable Destructors""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect the Zend HashTable Destructors" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_HASH_PROTECT" 1>&6 ++ ++ ++cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH 1 ++EOF ++ ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 0 ++EOF ++ ++fi + + + +@@ -15486,6 +15649,62 @@ + fi + + ++ echo $ac_n "checking whether realpath is broken""... $ac_c" 1>&6 ++echo "configure:14928: checking whether realpath is broken" >&5 ++if eval "test \"`echo '$''{'ac_cv_broken_realpath'+set}'`\" = set"; then ++ echo $ac_n "(cached) $ac_c" 1>&6 ++else ++ ++ if test "$cross_compiling" = yes; then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null ++then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ echo "configure: failed program was:" >&5 ++ cat conftest.$ac_ext >&5 ++ rm -fr conftest* ++ ++ ac_cv_broken_realpath=yes ++ ++fi ++rm -fr conftest* ++fi ++ ++ ++fi ++ ++echo "$ac_t""$ac_cv_broken_realpath" 1>&6 ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 1 ++EOF ++ ++ else ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 0 ++EOF ++ ++ fi ++ ++ + echo $ac_n "checking for declared timezone""... $ac_c" 1>&6 + echo "configure:15491: checking for declared timezone" >&5 + if eval "test \"`echo '$''{'ac_cv_declared_timezone'+set}'`\" = set"; then +@@ -85975,6 +86194,265 @@ + fi + + ++echo $ac_n "checking whether to enable Hardening-Patch's variable filter""... $ac_c" 1>&6 ++echo "configure:82041: checking whether to enable Hardening-Patch's variable filter" >&5 ++# Check whether --enable-varfilter or --disable-varfilter was given. ++if test "${enable_varfilter+set}" = set; then ++ enableval="$enable_varfilter" ++ PHP_VARFILTER=$enableval ++else ++ ++ PHP_VARFILTER=yes ++ ++ if test "$PHP_ENABLE_ALL" && test "yes" = "yes"; then ++ PHP_VARFILTER=$PHP_ENABLE_ALL ++ fi ++ ++fi ++ ++ ++ ++ext_output="yes, shared" ++ext_shared=yes ++case $PHP_VARFILTER in ++shared,*) ++ PHP_VARFILTER=`echo "$PHP_VARFILTER"|sed 's/^shared,//'` ++ ;; ++shared) ++ PHP_VARFILTER=yes ++ ;; ++no) ++ ext_output=no ++ ext_shared=no ++ ;; ++*) ++ ext_output=yes ++ ext_shared=no ++ ;; ++esac ++ ++ ++ ++echo "$ac_t""$ext_output" 1>&6 ++ ++ ++ ++ ++if test "$PHP_VARFILTER" != "no"; then ++ cat >> confdefs.h <<\EOF ++#define HAVE_VARFILTER 1 ++EOF ++ ++ ++ ext_builddir=ext/varfilter ++ ext_srcdir=$abs_srcdir/ext/varfilter ++ ++ ac_extra= ++ ++ if test "$ext_shared" != "shared" && test "$ext_shared" != "yes" && test "" != "cli"; then ++ ++ ++ ++ case ext/varfilter in ++ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;; ++ /*) ac_srcdir=`echo "ext/varfilter"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;; ++ *) ac_srcdir="$abs_srcdir/ext/varfilter/"; ac_bdir="ext/varfilter/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;; ++ esac ++ ++ ++ ++ b_c_pre=$php_c_pre ++ b_cxx_pre=$php_cxx_pre ++ b_c_meta=$php_c_meta ++ b_cxx_meta=$php_cxx_meta ++ b_c_post=$php_c_post ++ b_cxx_post=$php_cxx_post ++ b_lo=$php_lo ++ ++ ++ old_IFS=$IFS ++ for ac_src in varfilter.c; do ++ ++ IFS=. ++ set $ac_src ++ ac_obj=$1 ++ IFS=$old_IFS ++ ++ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo" ++ ++ case $ac_src in ++ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;; ++ *.cpp) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;; ++ esac ++ ++ cat >>Makefile.objects<>Makefile.objects<>Makefile.objects<> confdefs.h <>Makefile.objects<>Makefile.objects<&6 +@@ -98629,7 +99107,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c; do ++ output.c memory_streams.c user_streams.c hardening_patch.c; do + + IFS=. + set $ac_src +@@ -98802,7 +99280,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c; do ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c; do + + IFS=. + set $ac_src +diff -Naur php-4.3.11/configure.in hardening-patch-4.3.11-0.3.2/configure.in +--- php-4.3.11/configure.in 2005-03-30 16:18:36.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/configure.in 2005-07-09 08:53:02.466363720 +0200 +@@ -227,7 +227,7 @@ + sinclude(Zend/acinclude.m4) + sinclude(Zend/Zend.m4) + sinclude(TSRM/tsrm.m4) +- ++sinclude(main/hardening_patch.m4) + + + divert(2) +@@ -595,6 +595,7 @@ + AC_FUNC_ALLOCA + dnl PHP_AC_BROKEN_SPRINTF + dnl PHP_AC_BROKEN_SNPRINTF ++PHP_AC_BROKEN_REALPATH + PHP_DECLARED_TIMEZONE + PHP_TIME_R_TYPE + PHP_READDIR_R_TYPE +@@ -1224,7 +1225,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c) ++ output.c memory_streams.c user_streams.c hardening_patch.c) + PHP_ADD_SOURCES(/main, internal_functions.c,, sapi) + PHP_ADD_SOURCES(/main, internal_functions_cli.c,, cli) + +@@ -1237,7 +1238,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c) ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c ) + + if test -r "$abs_srcdir/Zend/zend_objects.c"; then + PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_mm.c) +diff -Naur php-4.3.11/ext/calendar/calendar.c hardening-patch-4.3.11-0.3.2/ext/calendar/calendar.c +--- php-4.3.11/ext/calendar/calendar.c 2003-08-28 22:01:24.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/ext/calendar/calendar.c 2005-07-09 08:53:02.466363720 +0200 +@@ -300,7 +300,7 @@ + { + pval **julday; + int year, month, day; +- char date[10]; ++ char date[16]; + + if (zend_get_parameters_ex(1, &julday) != SUCCESS) { + WRONG_PARAM_COUNT; +@@ -341,7 +341,7 @@ + { + pval **julday; + int year, month, day; +- char date[10]; ++ char date[16]; + + if (zend_get_parameters_ex(1, &julday) != SUCCESS) { + WRONG_PARAM_COUNT; +@@ -453,7 +453,7 @@ + { + long julday, fl; + int year, month, day; +- char date[10], hebdate[25]; ++ char date[16], hebdate[25]; + char *dayp, *yearp; + + if (ZEND_NUM_ARGS() == 1) { +@@ -521,7 +521,7 @@ + { + pval **julday; + int year, month, day; +- char date[10]; ++ char date[16]; + + if (zend_get_parameters_ex(1, &julday) != SUCCESS) { + WRONG_PARAM_COUNT; +diff -Naur php-4.3.11/ext/fbsql/php_fbsql.c hardening-patch-4.3.11-0.3.2/ext/fbsql/php_fbsql.c +--- php-4.3.11/ext/fbsql/php_fbsql.c 2005-02-09 20:33:32.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/ext/fbsql/php_fbsql.c 2005-07-09 08:53:02.468363416 +0200 +@@ -1797,8 +1797,24 @@ + } + else if (fbcmdErrorsFound(md)) + { ++#if HARDENING_PATCH ++ char* query_copy; ++ int i; ++#endif + FBCErrorMetaData* emd = fbcdcErrorMetaData(c, md); + char* emg = fbcemdAllErrorMessages(emd); ++#if HARDENING_PATCH ++ query_copy=estrdup(query_copy); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "fbsql error: %s - query: %s", emg, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ free(emg); ++ fbcemdRelease(emd); ++ result = 0; ++ zend_bailout(); ++ } ++#endif + if (FB_SQL_G(generateWarnings)) + { + if (emg) +diff -Naur php-4.3.11/ext/mbstring/mbstring.c hardening-patch-4.3.11-0.3.2/ext/mbstring/mbstring.c +--- php-4.3.11/ext/mbstring/mbstring.c 2005-02-21 09:03:47.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/ext/mbstring/mbstring.c 2005-07-09 08:53:02.469363264 +0200 +@@ -1487,6 +1487,7 @@ + char *strtok_buf = NULL, **val_list; + zval *array_ptr = (zval *) arg; + int n, num, val_len, *len_list; ++ unsigned int new_val_len; + enum mbfl_no_encoding from_encoding; + mbfl_string string, resvar, resval; + mbfl_encoding_detector *identd = NULL; +@@ -1609,8 +1610,14 @@ + val_len = len_list[n]; + } + n++; +- /* add variable to symbol table */ +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ /* we need val to be emalloc()ed */ ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(info->data_type, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ /* add variable to symbol table */ ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); ++ + if (convd != NULL){ + mbfl_string_clear(&resvar); + mbfl_string_clear(&resval); +diff -Naur php-4.3.11/ext/mysql/php_mysql.c hardening-patch-4.3.11-0.3.2/ext/mysql/php_mysql.c +--- php-4.3.11/ext/mysql/php_mysql.c 2005-02-22 16:00:49.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/ext/mysql/php_mysql.c 2005-07-09 08:53:02.471362960 +0200 +@@ -1215,6 +1215,8 @@ + { + php_mysql_conn *mysql; + MYSQL_RES *mysql_result; ++ char *copy_query; ++ int i; + + ZEND_FETCH_RESOURCE2(mysql, php_mysql_conn *, mysql_link, link_id, "MySQL-Link", le_link, le_plink); + +@@ -1265,6 +1267,13 @@ + php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #else +@@ -1272,12 +1281,20 @@ + /* check possible error */ + if (MySG(trace_mode)){ + if (mysql_errno(&mysql->conn)){ +- php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, mysql_error(&mysql->conn)); ++ php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #endif ++ + if(use_store == MYSQL_USE_RESULT) { + mysql_result=mysql_use_result(&mysql->conn); + } else { +diff -Naur php-4.3.11/ext/pgsql/pgsql.c hardening-patch-4.3.11-0.3.2/ext/pgsql/pgsql.c +--- php-4.3.11/ext/pgsql/pgsql.c 2004-05-12 18:49:56.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/ext/pgsql/pgsql.c 2005-07-09 08:53:02.473362656 +0200 +@@ -997,10 +997,28 @@ + case PGRES_EMPTY_QUERY: + case PGRES_BAD_RESPONSE: + case PGRES_NONFATAL_ERROR: +- case PGRES_FATAL_ERROR: +- PHP_PQ_ERROR("Query failed: %s", pgsql); +- PQclear(pgsql_result); +- RETURN_FALSE; ++ case PGRES_FATAL_ERROR: ++ { ++#if HARDENING_PATCH ++ int i; ++ char *query_copy; ++#endif ++ char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); ++ PQclear(pgsql_result); ++#if HARDENING_PATCH ++ query_copy = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "PgSQL error: %s - query: %s", msgbuf, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ efree(msgbuf); ++ zend_bailout(); ++ } ++#endif ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Query failed: %s", msgbuf); ++ efree(msgbuf); ++ RETURN_FALSE; ++ } + break; + case PGRES_COMMAND_OK: /* successful command that did not return rows */ + default: +diff -Naur php-4.3.11/ext/standard/array.c hardening-patch-4.3.11-0.3.2/ext/standard/array.c +--- php-4.3.11/ext/standard/array.c 2004-12-23 17:40:03.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/ext/standard/array.c 2005-07-09 08:53:02.474362504 +0200 +@@ -1153,6 +1153,32 @@ + } + } + } ++ ++ if (var_name[0] == 'H') { ++ if ((strcmp(var_name, "HTTP_GET_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_FILES")==0)|| ++ (strcmp(var_name, "HTTP_ENV_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(var_name, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(var_name, "HTTP_RAW_POST_DATA")==0)) { ++ return 0; ++ } ++ } else if (var_name[0] == '_') { ++ if ((strcmp(var_name, "_COOKIE")==0)|| ++ (strcmp(var_name, "_ENV")==0)|| ++ (strcmp(var_name, "_FILES")==0)|| ++ (strcmp(var_name, "_GET")==0)|| ++ (strcmp(var_name, "_POST")==0)|| ++ (strcmp(var_name, "_REQUEST")==0)|| ++ (strcmp(var_name, "_SESSION")==0)|| ++ (strcmp(var_name, "_SERVER")==0)) { ++ return 0; ++ } ++ } else if (strcmp(var_name, "GLOBALS")==0) { ++ return 0; ++ } + + return 1; + } +diff -Naur php-4.3.11/ext/standard/basic_functions.c hardening-patch-4.3.11-0.3.2/ext/standard/basic_functions.c +--- php-4.3.11/ext/standard/basic_functions.c 2005-01-18 12:01:20.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/ext/standard/basic_functions.c 2005-07-09 08:53:02.476362200 +0200 +@@ -687,7 +687,7 @@ + PHP_FALIAS(socket_get_status, stream_get_meta_data, NULL) + + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +- PHP_FE(realpath, NULL) ++ PHP_STATIC_FE("realpath", zif_real_path, NULL) + #endif + + #ifdef HAVE_FNMATCH +@@ -3020,6 +3020,35 @@ + memcpy(new_key, prefix, prefix_len); + memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + ++ if (new_key[0] == 'H') { ++ if ((strcmp(new_key, "HTTP_GET_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_FILES")==0)|| ++ (strcmp(new_key, "HTTP_ENV_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(new_key, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(new_key, "HTTP_RAW_POST_DATA")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (new_key[0] == '_') { ++ if ((strcmp(new_key, "_COOKIE")==0)|| ++ (strcmp(new_key, "_ENV")==0)|| ++ (strcmp(new_key, "_FILES")==0)|| ++ (strcmp(new_key, "_GET")==0)|| ++ (strcmp(new_key, "_POST")==0)|| ++ (strcmp(new_key, "_REQUEST")==0)|| ++ (strcmp(new_key, "_SESSION")==0)|| ++ (strcmp(new_key, "_SERVER")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (strcmp(new_key, "GLOBALS")==0) { ++ efree(new_key); ++ return 0; ++ } ++ + zend_hash_del(&EG(symbol_table), new_key, new_key_len); + ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, (*var)->refcount+1, 0); + +diff -Naur php-4.3.11/ext/standard/file.c hardening-patch-4.3.11-0.3.2/ext/standard/file.c +--- php-4.3.11/ext/standard/file.c 2005-03-27 17:53:59.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/ext/standard/file.c 2005-07-09 08:53:02.478361896 +0200 +@@ -2469,7 +2469,7 @@ + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) + /* {{{ proto string realpath(string path) + Return the resolved path */ +-PHP_FUNCTION(realpath) ++PHP_FUNCTION(real_path) + { + zval **path; + char resolved_path_buff[MAXPATHLEN]; +diff -Naur php-4.3.11/ext/standard/file.h hardening-patch-4.3.11-0.3.2/ext/standard/file.h +--- php-4.3.11/ext/standard/file.h 2004-06-21 21:33:47.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/ext/standard/file.h 2005-07-09 08:53:02.478361896 +0200 +@@ -64,7 +64,7 @@ + PHP_FUNCTION(fd_set); + PHP_FUNCTION(fd_isset); + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +-PHP_FUNCTION(realpath); ++PHP_FUNCTION(real_path); + #endif + #ifdef HAVE_FNMATCH + PHP_FUNCTION(fnmatch); +diff -Naur php-4.3.11/ext/standard/ftp_fopen_wrapper.c hardening-patch-4.3.11-0.3.2/ext/standard/ftp_fopen_wrapper.c +--- php-4.3.11/ext/standard/ftp_fopen_wrapper.c 2003-08-26 00:26:37.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/ext/standard/ftp_fopen_wrapper.c 2005-07-09 08:53:02.479361744 +0200 +@@ -17,7 +17,7 @@ + | Hartmut Holzgraefe | + +----------------------------------------------------------------------+ + */ +-/* $Id: ftp_fopen_wrapper.c,v 1.38.2.6 2003/08/25 22:26:37 pollita Exp $ */ ++/* $Id: ftp_fopen_wrapper.c,v 1.38.2.8.2.1 2005/06/27 08:27:23 sesser Exp $ */ + + #include "php.h" + #include "php_globals.h" +@@ -142,7 +142,7 @@ + unsigned short portno; + char *scratch; + int result; +- int i, use_ssl; ++ int i, use_ssl, tmp_len; + #ifdef HAVE_OPENSSL_EXT + int use_ssl_on_data=0; + php_stream *reuseid=NULL; +@@ -243,10 +243,25 @@ + + #endif + ++#define PHP_FTP_CNTRL_CHK(val, val_len, err_msg) { \ ++ unsigned char *s = val, *e = s + val_len; \ ++ while (s < e) { \ ++ if (iscntrl(*s)) { \ ++ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, err_msg, val); \ ++ goto errexit; \ ++ } \ ++ s++; \ ++ } \ ++} ++ + /* send the user name */ + php_stream_write_string(stream, "USER "); + if (resource->user != NULL) { +- php_raw_url_decode(resource->user, strlen(resource->user)); ++ unsigned char *s, *e; ++ tmp_len = php_raw_url_decode(resource->user, strlen(resource->user)); ++ ++ PHP_FTP_CNTRL_CHK(resource->user, tmp_len, "Invalid login %s") ++ + php_stream_write_string(stream, resource->user); + } else { + php_stream_write_string(stream, "anonymous"); +@@ -262,7 +277,10 @@ + + php_stream_write_string(stream, "PASS "); + if (resource->pass != NULL) { +- php_raw_url_decode(resource->pass, strlen(resource->pass)); ++ tmp_len = php_raw_url_decode(resource->pass, strlen(resource->pass)); ++ ++ PHP_FTP_CNTRL_CHK(resource->pass, tmp_len, "Invalid password %s") ++ + php_stream_write_string(stream, resource->pass); + } else { + /* if the user has configured who they are, +diff -Naur php-4.3.11/ext/standard/head.c hardening-patch-4.3.11-0.3.2/ext/standard/head.c +--- php-4.3.11/ext/standard/head.c 2005-01-07 22:14:23.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/ext/standard/head.c 2005-07-09 08:53:02.479361744 +0200 +@@ -45,10 +45,31 @@ + { + zend_bool rep = 1; + sapi_header_line ctr = {0}; ++#if HARDENING_PATCH ++ int i; ++#endif + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &ctr.line, + &ctr.line_len, &rep, &ctr.response_code) == FAILURE) + return; ++ ++#if HARDENING_PATCH ++ if (!HG(hphp_multiheader)) { ++ for (i=0; i0 && (iPHP Version %s with Hardening-Patch %s\n", PHP_VERSION, HARDENING_PATCH_VERSION); ++ } else { ++ char temp_ver[40]; ++ ++ snprintf(temp_ver, sizeof(temp_ver), "%s/%s", PHP_VERSION, HARDENING_PATCH_VERSION); ++ php_info_print_table_row(2, "PHP/Hardening-Patch Version", temp_ver); ++ } ++#else + if (!sapi_module.phpinfo_as_text) { + php_printf("

PHP Version %s

\n", PHP_VERSION); + } else { + php_info_print_table_row(2, "PHP Version", PHP_VERSION); + } ++#endif + php_info_print_box_end(); + php_info_print_table_start(); + php_info_print_table_row(2, "System", php_uname ); +diff -Naur php-4.3.11/ext/standard/syslog.c hardening-patch-4.3.11-0.3.2/ext/standard/syslog.c +--- php-4.3.11/ext/standard/syslog.c 2004-07-30 16:38:29.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/ext/standard/syslog.c 2005-07-09 08:53:02.480361592 +0200 +@@ -42,6 +42,7 @@ + */ + PHP_MINIT_FUNCTION(syslog) + { ++#if !HARDENING_PATCH + /* error levels */ + REGISTER_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ + REGISTER_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ +@@ -97,7 +98,7 @@ + /* AIX doesn't have LOG_PERROR */ + REGISTER_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ + #endif +- ++#endif + return SUCCESS; + } + /* }}} */ +diff -Naur php-4.3.11/ext/varfilter/config.m4 hardening-patch-4.3.11-0.3.2/ext/varfilter/config.m4 +--- php-4.3.11/ext/varfilter/config.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/ext/varfilter/config.m4 2005-07-09 08:53:02.481361440 +0200 +@@ -0,0 +1,11 @@ ++dnl ++dnl $Id: config.m4,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++dnl ++ ++PHP_ARG_ENABLE(varfilter, whether to enable Hardening-Patch's variable filter, ++[ --disable-varfilter Disable Hardening-Patch's variable filter], yes) ++ ++if test "$PHP_VARFILTER" != "no"; then ++ AC_DEFINE(HAVE_VARFILTER, 1, [ ]) ++ PHP_NEW_EXTENSION(varfilter, varfilter.c, $ext_shared) ++fi +diff -Naur php-4.3.11/ext/varfilter/CREDITS hardening-patch-4.3.11-0.3.2/ext/varfilter/CREDITS +--- php-4.3.11/ext/varfilter/CREDITS 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/ext/varfilter/CREDITS 2005-07-09 08:53:02.481361440 +0200 +@@ -0,0 +1,2 @@ ++varfilter ++Stefan Esser +\ Kein Zeilenumbruch am Dateiende. +diff -Naur php-4.3.11/ext/varfilter/php_varfilter.h hardening-patch-4.3.11-0.3.2/ext/varfilter/php_varfilter.h +--- php-4.3.11/ext/varfilter/php_varfilter.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/ext/varfilter/php_varfilter.h 2005-07-09 08:53:02.481361440 +0200 +@@ -0,0 +1,111 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: php_varfilter.h,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifndef PHP_VARFILTER_H ++#define PHP_VARFILTER_H ++ ++extern zend_module_entry varfilter_module_entry; ++#define phpext_varfilter_ptr &varfilter_module_entry ++ ++#ifdef PHP_WIN32 ++#define PHP_VARFILTER_API __declspec(dllexport) ++#else ++#define PHP_VARFILTER_API ++#endif ++ ++#ifdef ZTS ++#include "TSRM.h" ++#endif ++ ++#include "SAPI.h" ++ ++#include "php_variables.h" ++ ++ ++PHP_MINIT_FUNCTION(varfilter); ++PHP_MSHUTDOWN_FUNCTION(varfilter); ++PHP_RINIT_FUNCTION(varfilter); ++PHP_RSHUTDOWN_FUNCTION(varfilter); ++PHP_MINFO_FUNCTION(varfilter); ++ ++ ++ZEND_BEGIN_MODULE_GLOBALS(varfilter) ++// request variables ++ long max_request_variables; ++ long cur_request_variables; ++ long max_varname_length; ++ long max_totalname_length; ++ long max_value_length; ++ long max_array_depth; ++ long max_array_index_length; ++// cookie variables ++ long max_cookie_vars; ++ long cur_cookie_vars; ++ long max_cookie_name_length; ++ long max_cookie_totalname_length; ++ long max_cookie_value_length; ++ long max_cookie_array_depth; ++ long max_cookie_array_index_length; ++// get variables ++ long max_get_vars; ++ long cur_get_vars; ++ long max_get_name_length; ++ long max_get_totalname_length; ++ long max_get_value_length; ++ long max_get_array_depth; ++ long max_get_array_index_length; ++// post variables ++ long max_post_vars; ++ long cur_post_vars; ++ long max_post_name_length; ++ long max_post_totalname_length; ++ long max_post_value_length; ++ long max_post_array_depth; ++ long max_post_array_index_length; ++// fileupload ++ long max_uploads; ++ long cur_uploads; ++ zend_bool disallow_elf_files; ++ char *verification_script; ++ ++ZEND_END_MODULE_GLOBALS(varfilter) ++ ++ ++#ifdef ZTS ++#define VARFILTER_G(v) TSRMG(varfilter_globals_id, zend_varfilter_globals *, v) ++#else ++#define VARFILTER_G(v) (varfilter_globals.v) ++#endif ++ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter); ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter); ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter); ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter); ++ ++#endif /* PHP_VARFILTER_H */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * indent-tabs-mode: t ++ * End: ++ */ +diff -Naur php-4.3.11/ext/varfilter/varfilter.c hardening-patch-4.3.11-0.3.2/ext/varfilter/varfilter.c +--- php-4.3.11/ext/varfilter/varfilter.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/ext/varfilter/varfilter.c 2005-07-09 08:57:24.526524520 +0200 +@@ -0,0 +1,604 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: varfilter.c,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "php.h" ++#include "php_ini.h" ++#include "ext/standard/info.h" ++#include "php_varfilter.h" ++#include "hardening_patch.h" ++ ++ZEND_DECLARE_MODULE_GLOBALS(varfilter) ++ ++/* True global resources - no need for thread safety here */ ++static int le_varfilter; ++ ++/* {{{ varfilter_module_entry ++ */ ++zend_module_entry varfilter_module_entry = { ++#if ZEND_MODULE_API_NO >= 20010901 ++ STANDARD_MODULE_HEADER, ++#endif ++ "varfilter", ++ NULL, ++ PHP_MINIT(varfilter), ++ PHP_MSHUTDOWN(varfilter), ++ PHP_RINIT(varfilter), /* Replace with NULL if there's nothing to do at request start */ ++ PHP_RSHUTDOWN(varfilter), /* Replace with NULL if there's nothing to do at request end */ ++ PHP_MINFO(varfilter), ++#if ZEND_MODULE_API_NO >= 20010901 ++ "0.3.2", /* Replace with version number for your extension */ ++#endif ++ STANDARD_MODULE_PROPERTIES ++}; ++/* }}} */ ++ ++#ifdef COMPILE_DL_VARFILTER ++ZEND_GET_MODULE(varfilter) ++#endif ++ ++/* {{{ PHP_INI ++ */ ++PHP_INI_BEGIN() ++ /* for backward compatibility */ ++ STD_PHP_INI_ENTRY("varfilter.max_request_variables", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.request.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.cookie.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_cookie_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_value_length", "10000", PHP_INI_PERDIR, OnUpdateLong, max_cookie_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.get.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_get_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_get_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_value_length", "512", PHP_INI_PERDIR, OnUpdateLong, max_get_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_depth", "50", PHP_INI_PERDIR, OnUpdateLong, max_get_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.post.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_post_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_post_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_post_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_post_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.upload.max_uploads", "25", PHP_INI_PERDIR, OnUpdateLong, max_uploads, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.disallow_elf_files", "1", PHP_INI_SYSTEM, OnUpdateBool, disallow_elf_files, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.verification_script", NULL, PHP_INI_SYSTEM, OnUpdateString, verification_script, zend_varfilter_globals, varfilter_globals) ++ ++ ++PHP_INI_END() ++/* }}} */ ++ ++/* {{{ php_varfilter_init_globals ++ */ ++static void php_varfilter_init_globals(zend_varfilter_globals *varfilter_globals) ++{ ++ varfilter_globals->max_request_variables = 200; ++ varfilter_globals->max_varname_length = 64; ++ varfilter_globals->max_value_length = 10000; ++ varfilter_globals->max_array_depth = 100; ++ varfilter_globals->max_totalname_length = 256; ++ varfilter_globals->max_array_index_length = 64; ++ ++ varfilter_globals->max_cookie_vars = 100; ++ varfilter_globals->max_cookie_name_length = 64; ++ varfilter_globals->max_cookie_totalname_length = 256; ++ varfilter_globals->max_cookie_value_length = 10000; ++ varfilter_globals->max_cookie_array_depth = 100; ++ varfilter_globals->max_cookie_array_index_length = 64; ++ ++ varfilter_globals->max_get_vars = 100; ++ varfilter_globals->max_get_name_length = 64; ++ varfilter_globals->max_get_totalname_length = 256; ++ varfilter_globals->max_get_value_length = 512; ++ varfilter_globals->max_get_array_depth = 50; ++ varfilter_globals->max_get_array_index_length = 64; ++ ++ varfilter_globals->max_post_vars = 200; ++ varfilter_globals->max_post_name_length = 64; ++ varfilter_globals->max_post_totalname_length = 256; ++ varfilter_globals->max_post_value_length = 65000; ++ varfilter_globals->max_post_array_depth = 100; ++ varfilter_globals->max_post_array_index_length = 64; ++ ++ varfilter_globals->max_uploads = 25; ++ varfilter_globals->disallow_elf_files = 1; ++ varfilter_globals->verification_script = NULL; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINIT_FUNCTION ++ */ ++PHP_MINIT_FUNCTION(varfilter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(varfilter, php_varfilter_init_globals, NULL); ++ REGISTER_INI_ENTRIES(); ++ ++ sapi_register_input_filter(varfilter_input_filter); ++ sapi_register_pre_upload_filter(varfilter_pre_upload_filter); ++ sapi_register_upload_content_filter(varfilter_upload_content_filter); ++ sapi_register_post_upload_filter(varfilter_post_upload_filter); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MSHUTDOWN_FUNCTION ++ */ ++PHP_MSHUTDOWN_FUNCTION(varfilter) ++{ ++// zend_hash_apply_with_arguments(&HG(lists.functionlists), (apply_func_args_t) show_stuff, 0); ++ ++ UNREGISTER_INI_ENTRIES(); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request start */ ++/* {{{ PHP_RINIT_FUNCTION ++ */ ++PHP_RINIT_FUNCTION(varfilter) ++{ ++ VARFILTER_G(cur_request_variables) = 0; ++ VARFILTER_G(cur_get_vars) = 0; ++ VARFILTER_G(cur_post_vars) = 0; ++ VARFILTER_G(cur_cookie_vars) = 0; ++ ++ VARFILTER_G(cur_uploads) = 0; ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request end */ ++/* {{{ PHP_RSHUTDOWN_FUNCTION ++ */ ++PHP_RSHUTDOWN_FUNCTION(varfilter) ++{ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINFO_FUNCTION ++ */ ++PHP_MINFO_FUNCTION(varfilter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_header(2, "Hardening-Patch's variable filter support", "enabled"); ++ php_info_print_table_end(); ++ ++ DISPLAY_INI_ENTRIES(); ++} ++/* }}} */ ++ ++/* {{{ normalize_varname ++ */ ++static void normalize_varname(char *varname) ++{ ++ char *s=varname, *index=NULL, *indexend=NULL, *p; ++ ++ /* overjump leading space */ ++ while (*s == ' ') { ++ s++; ++ } ++ ++ /* and remove it */ ++ if (s != varname) { ++ memmove(varname, s, strlen(s)+1); ++ } ++ ++ for (p=varname; *p && *p != '['; p++) { ++ switch(*p) { ++ case ' ': ++ case '.': ++ *p='_'; ++ break; ++ } ++ } ++ ++ /* find index */ ++ index = strchr(varname, '['); ++ if (index) { ++ index++; ++ s=index; ++ } else { ++ return; ++ } ++ ++ /* done? */ ++ while (index) { ++ ++ while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') { ++ index++; ++ } ++ indexend = strchr(index, ']'); ++ indexend = indexend ? indexend + 1 : index + strlen(index); ++ ++ if (s != index) { ++ memmove(s, index, strlen(index)+1); ++ s += indexend-index; ++ } else { ++ s = indexend; ++ } ++ ++ if (*s == '[') { ++ s++; ++ index = s; ++ } else { ++ index = NULL; ++ } ++ } ++ *s++='\0'; ++} ++/* }}} */ ++ ++/* {{{ SAPI_PRE_UPLOAD_FILTER_FUNC ++ */ ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter) ++{ ++ /* Drop this fileupload if the limit is reached */ ++ if (VARFILTER_G(max_uploads) && VARFILTER_G(max_uploads) <= VARFILTER_G(cur_uploads)) { ++ php_security_log(S_FILES, "configured fileupload limit exceeded - file dropped"); ++ return FAILURE; ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_UPLOAD_CONTENT_FILTER_FUNC ++ */ ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter) ++{ ++ ++ if (VARFILTER_G(disallow_elf_files)) { ++ ++ if (offset == 0 && buffer_len > 10) { ++ ++ if (buffer[0] == 0x7F && buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F') { ++ php_security_log(S_FILES, "uploaded file is an ELF executable - file dropped"); ++ return FAILURE; ++ } ++ } ++ ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_POST_UPLOAD_FILTER_FUNC ++ */ ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter) ++{ ++ int retval = SUCCESS; ++ ++ if (VARFILTER_G(verification_script)) { ++ char cmd[8192]; ++ FILE *in; ++ int first=1; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s", VARFILTER_G(verification_script), tmpfilename); ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_FILES, "unable to execute fileupload verification script - file dropped"); ++ return FAILURE; ++ } ++ ++ retval = FAILURE; ++ ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ if (first) { ++ retval = atoi(cmd) == 1 ? SUCCESS : FAILURE; ++ first = 0; ++ } ++ } ++ pclose(in); ++ } ++ ++ if (retval != SUCCESS) { ++ php_security_log(S_FILES, "fileupload verification script disallows file - file dropped"); ++ return FAILURE; ++ } ++ ++ VARFILTER_G(cur_uploads)++; ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_INPUT_FILTER_FUNC ++ */ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter) ++{ ++ char *index, *prev_index = NULL, *copy_var; ++ unsigned int var_len, total_len, depth = 0, rv; ++ ++ /* Drop this variable if the limit is reached */ ++ if (VARFILTER_G(max_request_variables) && VARFILTER_G(max_request_variables) <= VARFILTER_G(cur_request_variables)) { ++ php_security_log(S_VARS, "configured request variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_vars) && VARFILTER_G(max_get_vars) <= VARFILTER_G(cur_get_vars)) { ++ php_security_log(S_VARS, "configured GET variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_vars) && VARFILTER_G(max_cookie_vars) <= VARFILTER_G(cur_cookie_vars)) { ++ php_security_log(S_VARS, "configured COOKIE variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_vars) && VARFILTER_G(max_post_vars) <= VARFILTER_G(cur_post_vars)) { ++ php_security_log(S_VARS, "configured POST variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ ++ /* Drop this variable if it exceeds the value length limit */ ++ if (VARFILTER_G(max_value_length) && VARFILTER_G(max_value_length) < val_len) { ++ php_security_log(S_VARS, "configured request variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_value_length) && VARFILTER_G(max_get_value_length) < val_len) { ++ php_security_log(S_VARS, "configured GET variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_value_length) && VARFILTER_G(max_cookie_value_length) < val_len) { ++ php_security_log(S_VARS, "configured COOKIE variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_value_length) && VARFILTER_G(max_post_value_length) < val_len) { ++ php_security_log(S_VARS, "configured POST variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Normalize the variable name */ ++ normalize_varname(var); ++ ++ /* Find length of variable name */ ++ index = strchr(var, '['); ++ total_len = strlen(var); ++ var_len = index ? index-var : total_len; ++ ++ /* Drop this variable if it exceeds the varname/total length limit */ ++ if (VARFILTER_G(max_varname_length) && VARFILTER_G(max_varname_length) < var_len) { ++ php_security_log(S_VARS, "configured request variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_totalname_length) && VARFILTER_G(max_totalname_length) < total_len) { ++ php_security_log(S_VARS, "configured request variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_name_length) && VARFILTER_G(max_get_name_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_get_totalname_length) && VARFILTER_G(max_get_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_name_length) && VARFILTER_G(max_cookie_name_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_cookie_totalname_length) && VARFILTER_G(max_cookie_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_name_length) && VARFILTER_G(max_post_name_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_post_totalname_length) && VARFILTER_G(max_post_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Find out array depth */ ++ while (index) { ++ unsigned int index_length; ++ ++ depth++; ++ index = strchr(index+1, '['); ++ ++ if (prev_index) { ++ index_length = index ? index - 1 - prev_index - 1: strlen(prev_index); ++ ++ if (VARFILTER_G(max_array_index_length) && VARFILTER_G(max_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured request variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_index_length) && VARFILTER_G(max_get_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured GET variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_index_length) && VARFILTER_G(max_cookie_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured COOKIE variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_index_length) && VARFILTER_G(max_post_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured POST variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ prev_index = index; ++ } ++ ++ } ++ ++ /* Drop this variable if it exceeds the array depth limit */ ++ if (VARFILTER_G(max_array_depth) && VARFILTER_G(max_array_depth) < depth) { ++ php_security_log(S_VARS, "configured request variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_depth) && VARFILTER_G(max_get_array_depth) < depth) { ++ php_security_log(S_VARS, "configured GET variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_depth) && VARFILTER_G(max_cookie_array_depth) < depth) { ++ php_security_log(S_VARS, "configured COOKIE variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_depth) && VARFILTER_G(max_post_array_depth) < depth) { ++ php_security_log(S_VARS, "configured POST variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Drop this variable if it is one of GLOBALS, _GET, _POST, ... */ ++ /* This is to protect several silly scripts that do globalizing themself */ ++ ++ switch (var_len) { ++ case 18: ++ if (memcmp(var, "HTTP_RAW_POST_DATA", 18)==0) goto protected_varname; ++ break; ++ case 17: ++ if (memcmp(var, "HTTP_SESSION_VARS", 17)==0) goto protected_varname; ++ break; ++ case 16: ++ if (memcmp(var, "HTTP_SERVER_VARS", 16)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_COOKIE_VARS", 16)==0) goto protected_varname; ++ break; ++ case 15: ++ if (memcmp(var, "HTTP_POST_FILES", 15)==0) goto protected_varname; ++ break; ++ case 14: ++ if (memcmp(var, "HTTP_POST_VARS", 14)==0) goto protected_varname; ++ break; ++ case 13: ++ if (memcmp(var, "HTTP_GET_VARS", 13)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_ENV_VARS", 13)==0) goto protected_varname; ++ break; ++ case 8: ++ if (memcmp(var, "_SESSION", 8)==0) goto protected_varname; ++ if (memcmp(var, "_REQUEST", 8)==0) goto protected_varname; ++ break; ++ case 7: ++ if (memcmp(var, "GLOBALS", 7)==0) goto protected_varname; ++ if (memcmp(var, "_COOKIE", 7)==0) goto protected_varname; ++ if (memcmp(var, "_SERVER", 7)==0) goto protected_varname; ++ break; ++ case 6: ++ if (memcmp(var, "_FILES", 6)==0) goto protected_varname; ++ break; ++ case 5: ++ if (memcmp(var, "_POST", 5)==0) goto protected_varname; ++ break; ++ case 4: ++ if (memcmp(var, "_ENV", 4)==0) goto protected_varname; ++ if (memcmp(var, "_GET", 4)==0) goto protected_varname; ++ break; ++ } ++ ++ /* Okay let PHP register this variable */ ++ VARFILTER_G(cur_request_variables)++; ++ switch (arg) { ++ case PARSE_GET: ++ VARFILTER_G(cur_get_vars)++; ++ break; ++ case PARSE_COOKIE: ++ VARFILTER_G(cur_cookie_vars)++; ++ break; ++ case PARSE_POST: ++ VARFILTER_G(cur_post_vars)++; ++ break; ++ } ++ ++ if (new_val_len) { ++ *new_val_len = val_len; ++ } ++ ++ return 1; ++protected_varname: ++ php_security_log(S_VARS, "tried to register forbidden variable '%s' through %s variables", var, arg == PARSE_GET ? "GET" : arg == PARSE_POST ? "POST" : "COOKIE"); ++ return 0; ++} ++/* }}} */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: noet sw=4 ts=4 fdm=marker ++ * vim<600: noet sw=4 ts=4 ++ */ ++ ++ +diff -Naur php-4.3.11/main/fopen_wrappers.c hardening-patch-4.3.11-0.3.2/main/fopen_wrappers.c +--- php-4.3.11/main/fopen_wrappers.c 2005-02-03 00:44:07.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/main/fopen_wrappers.c 2005-07-09 08:53:02.483361136 +0200 +@@ -166,6 +166,21 @@ + char *pathbuf; + char *ptr; + char *end; ++ char path_copy[MAXPATHLEN]; ++ int path_len; ++ ++ /* Special case path ends with a trailing slash */ ++ path_len = strlen(path); ++ if (path_len >= MAXPATHLEN) { ++ errno = EPERM; /* we deny permission to open it */ ++ return -1; ++ } ++ if (path_len > 0 && path[path_len-1] == PHP_DIR_SEPARATOR) { ++ memcpy(path_copy, path, path_len+1); ++ while (path_len > 0 && path_copy[path_len-1] == PHP_DIR_SEPARATOR) path_len--; ++ path_copy[path_len] = '\0'; ++ path = (const char *)&path_copy; ++ } + + pathbuf = estrdup(PG(open_basedir)); + +diff -Naur php-4.3.11/main/hardened_globals.h hardening-patch-4.3.11-0.3.2/main/hardened_globals.h +--- php-4.3.11/main/hardened_globals.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/main/hardened_globals.h 2005-07-09 08:53:02.483361136 +0200 +@@ -0,0 +1,56 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_GLOBALS_H ++#define HARDENED_GLOBALS_H ++ ++typedef struct _hardened_globals hardened_globals_struct; ++ ++#ifdef ZTS ++# define HG(v) TSRMG(hardened_globals_id, hardened_globals_struct *, v) ++extern int hardened_globals_id; ++#else ++# define HG(v) (hardened_globals.v) ++extern struct _hardened_globals hardened_globals; ++#endif ++ ++ ++struct _hardened_globals { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_1; ++ unsigned int canary_2; ++#endif ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_3; ++ unsigned int canary_4; ++ unsigned int ll_canary_inited; ++#endif ++ zend_bool hphp_sql_bailout_on_error; ++ zend_bool hphp_multiheader; ++ unsigned int dummy; ++}; ++ ++ ++#endif /* HARDENED_GLOBALS_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Naur php-4.3.11/main/hardening_patch.c hardening-patch-4.3.11-0.3.2/main/hardening_patch.c +--- php-4.3.11/main/hardening_patch.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/main/hardening_patch.c 2005-07-09 08:53:02.484360984 +0200 +@@ -0,0 +1,322 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: hardening_patch.c,v 1.2 2004/11/21 09:38:52 ionic Exp $ */ ++ ++#include "php.h" ++ ++#include ++#include ++ ++#if HAVE_UNISTD_H ++#include ++#endif ++#include "SAPI.h" ++#include "php_globals.h" ++ ++#if HARDENING_PATCH ++ ++#ifdef HAVE_SYS_SOCKET_H ++#include ++#endif ++ ++#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE) ++#undef AF_UNIX ++#endif ++ ++#if defined(AF_UNIX) ++#include ++#endif ++ ++#define SYSLOG_PATH "/dev/log" ++ ++#include "snprintf.h" ++ ++#include "hardening_patch.h" ++ ++#ifdef ZTS ++#include "hardened_globals.h" ++int hardened_globals_id; ++#else ++struct _hardened_globals hardened_globals; ++#endif ++ ++static void hardened_globals_ctor(hardened_globals_struct *hardened_globals TSRMLS_DC) ++{ ++ memset(hardened_globals, 0, sizeof(*hardened_globals)); ++} ++ ++ ++PHPAPI void hardened_startup() ++{ ++#ifdef ZTS ++ ts_allocate_id(&hardened_globals_id, sizeof(hardened_globals_struct), (ts_allocate_ctor) hardened_globals_ctor, NULL); ++#else ++ hardened_globals_ctor(&hardened_globals TSRMLS_CC); ++#endif ++} ++ ++char *loglevel2string(int loglevel) ++{ ++ switch (loglevel) { ++ case S_FILES: ++ return "FILES"; ++ case S_INCLUDE: ++ return "INCLUDE"; ++ case S_MEMORY: ++ return "MEMORY"; ++ case S_MISC: ++ return "MISC"; ++ case S_SQL: ++ return "SQL"; ++ case S_EXECUTOR: ++ return "EXECUTOR"; ++ case S_VARS: ++ return "VARS"; ++ default: ++ return "UNKNOWN"; ++ } ++} ++ ++PHPAPI void php_security_log(int loglevel, char *fmt, ...) ++{ ++#if defined(AF_UNIX) ++ int s, r, i=0; ++ struct sockaddr_un saun; ++ char buf[4096+64]; ++ char error[4096+100]; ++ char *ip_address; ++ char *fname; ++ int lineno; ++ va_list ap; ++ TSRMLS_FETCH(); ++ ++ if (EG(hphp_log_use_x_forwarded_for)) { ++ ip_address = sapi_getenv("HTTP_X_FORWARDED_FOR", 20 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "X-FORWARDED-FOR not set"; ++ } ++ } else { ++ ip_address = sapi_getenv("REMOTE_ADDR", 11 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "REMOTE_ADDR not set"; ++ } ++ } ++ ++ ++ va_start(ap, fmt); ++ ap_php_vsnprintf(error, sizeof(error), fmt, ap); ++ va_end(ap); ++ while (error[i]) { ++ if (error[i] < 32) error[i] = '.'; ++ i++; ++ } ++ ++ if (zend_is_executing(TSRMLS_C)) { ++ lineno = zend_get_executed_lineno(TSRMLS_C); ++ fname = zend_get_executed_filename(TSRMLS_C); ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s', line %u)", error, ip_address, fname, lineno); ++ } else { ++ fname = sapi_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC); ++ if (fname==NULL) { ++ fname = "unknown"; ++ } ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s')", error, ip_address, fname); ++ } ++ ++ /* Syslog-Logging disabled? */ ++ if ((EG(hphp_log_syslog) & loglevel)==0) { ++ goto log_sapi; ++ } ++ ++ ap_php_snprintf(error, sizeof(error), "<%u>hphp[%u]: %s\n", EG(hphp_log_syslog_facility)|EG(hphp_log_syslog_priority),getpid(),buf); ++ ++ s = socket(AF_UNIX, SOCK_DGRAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ s = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ goto log_sapi; ++ } ++ } ++ send(s, error, strlen(error), 0); ++ ++ close(s); ++ ++log_sapi: ++ /* SAPI Logging activated? */ ++ if ((EG(hphp_log_syslog) & loglevel)!=0) { ++ sapi_module.log_message(buf); ++ } ++ ++log_script: ++ /* script logging activaed? */ ++ if (((EG(hphp_log_script) & loglevel)!=0) && EG(hphp_log_scriptname)!=NULL) { ++ char cmd[8192], *cmdpos, *bufpos; ++ FILE *in; ++ int space; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s \'", EG(hphp_log_scriptname), loglevel2string(loglevel)); ++ space = sizeof(cmd) - strlen(cmd); ++ cmdpos = cmd + strlen(cmd); ++ bufpos = buf; ++ if (space <= 1) return; ++ while (space > 2 && *bufpos) { ++ if (*bufpos == '\'') { ++ if (space<=5) break; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\\'; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\''; ++ bufpos++; ++ space-=4; ++ } else { ++ *cmdpos++ = *bufpos++; ++ space--; ++ } ++ } ++ *cmdpos++ = '\''; ++ *cmdpos = 0; ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ return; ++ } ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ } ++ pclose(in); ++ } ++ ++#endif ++} ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++PHPAPI unsigned int php_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++ ++PHPAPI int php_is_valid_include(zval *z) ++{ ++ char *filename; ++ int len, i; ++ TSRMLS_FETCH(); ++ ++ /* must be of type string */ ++ if (z->type != IS_STRING || z->value.str.val == NULL) { ++ return (0); ++ } ++ ++ /* short cut */ ++ filename = z->value.str.val; ++ len = z->value.str.len; ++ ++ /* 1. must be shorter than MAXPATHLEN */ ++ if (len > MAXPATHLEN) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') longer than MAXPATHLEN chars", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 2. must not be cutted */ ++ if (len != strlen(filename)) { ++ char *fname = estrndup(filename, len); ++ for (i=0; fname[i]; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename truncated by a \\0 after '%s'", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 3. must not be a URL */ ++ if (strstr(filename, "://")) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') is an URL", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 4. must not be an uploaded file */ ++ if (SG(rfc1867_uploaded_files)) { ++ if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, len+1)) { ++ php_security_log(S_INCLUDE, "Include filename is an uploaded file"); ++ return (0); ++ } ++ } ++ ++ /* passed all tests */ ++ return (1); ++} ++ ++#endif ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Naur php-4.3.11/main/hardening_patch.h hardening-patch-4.3.11-0.3.2/main/hardening_patch.h +--- php-4.3.11/main/hardening_patch.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/main/hardening_patch.h 2005-07-09 08:57:24.527524368 +0200 +@@ -0,0 +1,46 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENING_PATCH_H ++#define HARDENING_PATCH_H ++ ++#include "zend.h" ++ ++#if HARDENING_PATCH ++PHPAPI void php_security_log(int loglevel, char *fmt, ...); ++PHPAPI void hardened_startup(); ++#define HARDENING_PATCH_VERSION "0.3.2" ++ ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++PHPAPI unsigned int php_canary(); ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++PHPAPI int php_is_valid_include(zval *z); ++#endif ++ ++#endif /* HARDENING_PATCH_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Naur php-4.3.11/main/hardening_patch.m4 hardening-patch-4.3.11-0.3.2/main/hardening_patch.m4 +--- php-4.3.11/main/hardening_patch.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/main/hardening_patch.m4 2005-07-09 08:53:02.485360832 +0200 +@@ -0,0 +1,95 @@ ++dnl ++dnl $Id: hardening_patch.m4,v 1.1 2004/11/14 13:24:24 ionic Exp $ ++dnl ++dnl This file contains Hardening Patch for PHP specific autoconf functions. ++dnl ++ ++AC_ARG_ENABLE(hardening-patch-mm-protect, ++[ --disable-hardening-patch-mm-protect Disable the Memory Manager protection.],[ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-ll-protect, ++[ --disable-hardening-patch-ll-protect Disable the Linked List protection.],[ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-inc-protect, ++[ --disable-hardening-patch-inc-protect Disable include/require protection.],[ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-fmt-protect, ++[ --disable-hardening-patch-fmt-protect Disable format string protection.],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-hash-protect, ++[ --disable-hardening-patch-hash-protect Disable HashTable destructor protection.],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++]) ++ ++AC_MSG_CHECKING(whether to protect the Zend Memory Manager) ++AC_MSG_RESULT($DO_HARDENING_PATCH_MM_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the Zend Linked Lists) ++AC_MSG_RESULT($DO_HARDENING_PATCH_LL_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect include/require statements) ++AC_MSG_RESULT($DO_HARDENING_PATCH_INC_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect PHP Format String functions) ++AC_MSG_RESULT($DO_HARDENING_PATCH_FMT_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the destructor of Zend HashTables) ++AC_MSG_RESULT($DO_HARDENING_PATCH_HASH_PROTECT) ++ ++ ++AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 1, [Memory Manager Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 0, [Memory Manager Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 1, [Linked List Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 0, [Linked List Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 1, [Include/Require Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 0, [Include/Require Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 1, [Fmt String Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 0, [Fmt String Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 1, [HashTable DTOR Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 0, [HashTable DTOR Protection]) ++fi ++ +diff -Naur php-4.3.11/main/main.c hardening-patch-4.3.11-0.3.2/main/main.c +--- php-4.3.11/main/main.c 2005-03-08 22:45:51.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/main/main.c 2005-07-09 08:53:02.486360680 +0200 +@@ -100,6 +100,10 @@ + PHPAPI int core_globals_id; + #endif + ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#endif ++ + #define ERROR_BUF_LEN 1024 + + typedef struct { +@@ -150,10 +154,33 @@ + */ + static PHP_INI_MH(OnChangeMemoryLimit) + { ++#if HARDENING_PATCH ++ long orig_memory_limit; ++ ++ if (entry->modified) { ++ orig_memory_limit = zend_atoi(entry->orig_value, entry->orig_value_length); ++ } else { ++ orig_memory_limit = 1<<30; ++ } ++ if (orig_memory_limit < 0 || orig_memory_limit > (1<<30)) { ++ orig_memory_limit = 1<<30; ++ } ++#endif + if (new_value) { + PG(memory_limit) = zend_atoi(new_value, new_value_length); ++#if HARDENING_PATCH ++ if (PG(memory_limit) > orig_memory_limit) { ++ PG(memory_limit) = orig_memory_limit; ++ php_security_log(S_MISC, "script tried to increase memory_limit above allowed value"); ++ return FAILURE; ++ } ++#endif + } else { ++#if HARDENING_PATCH ++ PG(memory_limit) = orig_memory_limit; ++#else + PG(memory_limit) = 1<<30; /* effectively, no limit */ ++#endif + } + return zend_set_memory_limit(PG(memory_limit)); + } +@@ -1092,6 +1119,10 @@ + tsrm_ls = ts_resource(0); + #endif + ++#if HARDENING_PATCH ++ hardened_startup(); ++#endif ++ + sapi_initialize_empty_request(TSRMLS_C); + sapi_activate(TSRMLS_C); + +@@ -1104,6 +1135,12 @@ + php_output_startup(); + php_output_activate(TSRMLS_C); + ++#if HARDENING_PATCH_INC_PROTECT ++ zuf.is_valid_include = php_is_valid_include; ++#endif ++#if HARDENING_PATCH ++ zuf.security_log_function = php_security_log; ++#endif + zuf.error_function = php_error_cb; + zuf.printf_function = php_printf; + zuf.write_function = php_body_write_wrapper; +@@ -1205,6 +1242,10 @@ + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, sizeof(PHP_CONFIG_FILE_PATH)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("HARDENING_PATCH", 1, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_STRINGL_CONSTANT("HARDENING_PATCH_VERSION", HARDENING_PATCH_VERSION, sizeof(HARDENING_PATCH_VERSION)-1, CONST_PERSISTENT | CONST_CS); ++#endif + REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS); + php_output_register_constants(TSRMLS_C); + php_rfc1867_register_constants(TSRMLS_C); +@@ -1310,7 +1351,7 @@ + */ + static inline void php_register_server_variables(TSRMLS_D) + { +- zval *array_ptr=NULL; ++ zval *array_ptr=NULL, *vptr; + + ALLOC_ZVAL(array_ptr); + array_init(array_ptr); +@@ -1320,6 +1361,16 @@ + /* Server variables */ + if (sapi_module.register_server_variables) { + sapi_module.register_server_variables(array_ptr TSRMLS_CC); ++ if (zend_hash_find(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA"), (void **)&vptr)==SUCCESS) { ++ char *str; ++ if (vptr->type != IS_STRING) { ++ str = "Array"; ++ } else { ++ str = vptr->value.str.val; ++ } ++ php_security_log(S_VARS, "Attacker tried to overwrite HTTP_RAW_POST_DATA with '%s' through a HTTP header", str); ++ zend_hash_del(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA")); ++ } + } + + /* PHP Authentication support */ +diff -Naur php-4.3.11/main/php_config.h.in hardening-patch-4.3.11-0.3.2/main/php_config.h.in +--- php-4.3.11/main/php_config.h.in 2005-03-30 16:35:47.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/main/php_config.h.in 2005-07-09 08:53:02.487360528 +0200 +@@ -839,6 +839,39 @@ + /* Enabling BIND8 compatibility for Panther */ + #undef BIND_8_COMPAT + ++/* Hardening-Patch */ ++#undef HARDENING_PATCH ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ + /* Whether you have AOLserver */ + #undef HAVE_AOLSERVER + +@@ -1122,6 +1155,12 @@ + /* Define if you have the getaddrinfo function */ + #undef HAVE_GETADDRINFO + ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ + /* Whether system headers declare timezone */ + #undef HAVE_DECLARED_TIMEZONE + +diff -Naur php-4.3.11/main/php_content_types.c hardening-patch-4.3.11-0.3.2/main/php_content_types.c +--- php-4.3.11/main/php_content_types.c 2002-12-31 17:26:14.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/main/php_content_types.c 2005-07-09 08:53:02.487360528 +0200 +@@ -77,6 +77,7 @@ + sapi_register_post_entries(php_post_entries); + sapi_register_default_post_reader(php_default_post_reader); + sapi_register_treat_data(php_default_treat_data); ++ sapi_register_input_filter(php_default_input_filter); + return SUCCESS; + } + /* }}} */ +diff -Naur php-4.3.11/main/php.h hardening-patch-4.3.11-0.3.2/main/php.h +--- php-4.3.11/main/php.h 2005-03-08 22:45:51.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/main/php.h 2005-07-09 08:53:02.488360376 +0200 +@@ -26,7 +26,7 @@ + #include + #endif + +-#define PHP_API_VERSION 20020918 ++#define PHP_API_VERSION 1020050626 + #define PHP_HAVE_STREAMS + #define YYDEBUG 0 + +@@ -35,11 +35,19 @@ + #include "zend_qsort.h" + #include "php_compat.h" + ++ + #include "zend_API.h" + + #undef sprintf + #define sprintf php_sprintf + ++#if HARDENING_PATCH ++#if HAVE_REALPATH ++#undef realpath ++#define realpath php_realpath ++#endif ++#endif ++ + /* PHP's DEBUG value must match Zend's ZEND_DEBUG value */ + #undef PHP_DEBUG + #define PHP_DEBUG ZEND_DEBUG +@@ -436,6 +444,10 @@ + #endif + #endif /* !XtOffsetOf */ + ++#if HARDENING_PATCH ++#include "hardening_patch.h" ++#endif ++ + #endif + + /* +diff -Naur php-4.3.11/main/php_variables.c hardening-patch-4.3.11-0.3.2/main/php_variables.c +--- php-4.3.11/main/php_variables.c 2004-10-18 17:08:46.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/main/php_variables.c 2005-07-09 08:53:02.488360376 +0200 +@@ -211,17 +211,28 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(PARSE_POST, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, "&", &strtok_buf); + } + } + ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter) ++{ ++ /* TODO: check .ini setting here and apply user-defined input filter */ ++ *new_val_len = val_len; ++ return 1; ++} ++ + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) + { + char *res = NULL, *var, *val, *separator=NULL; +@@ -299,15 +310,26 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } else { ++ unsigned int val_len, new_val_len; ++ + php_url_decode(var, strlen(var)); +- php_register_variable_safe(var, "", 0, array_ptr TSRMLS_CC); ++ val_len = 0; ++ val = estrndup("", 0); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, separator, &strtok_buf); + } +diff -Naur php-4.3.11/main/rfc1867.c hardening-patch-4.3.11-0.3.2/main/rfc1867.c +--- php-4.3.11/main/rfc1867.c 2005-02-15 01:28:39.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/main/rfc1867.c 2005-07-09 08:53:02.489360224 +0200 +@@ -127,6 +127,7 @@ + #define UPLOAD_ERROR_C 3 /* Partially uploaded */ + #define UPLOAD_ERROR_D 4 /* No file uploaded */ + #define UPLOAD_ERROR_E 6 /* Missing /tmp or similar directory */ ++#define UPLOAD_ERROR_F 7 /* Filter forbids upload */ + + void php_rfc1867_register_constants(TSRMLS_D) + { +@@ -136,6 +137,7 @@ + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL", UPLOAD_ERROR_C, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE", UPLOAD_ERROR_D, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FILTER", UPLOAD_ERROR_F, CONST_CS | CONST_PERSISTENT); + } + + static void normalize_protected_variable(char *varname TSRMLS_DC) +@@ -844,6 +846,7 @@ + char buff[FILLUNIT]; + char *cd=NULL,*param=NULL,*filename=NULL, *tmp=NULL; + int blen=0, wlen=0; ++ unsigned long offset; + + zend_llist_clean(&header); + +@@ -891,21 +894,24 @@ + if (!filename && param) { + + char *value = multipart_buffer_read_body(mbuff TSRMLS_CC); ++ unsigned int new_val_len; /* Dummy variable */ + + if (!value) { + value = estrdup(""); + } + ++ if (sapi_module.input_filter(PARSE_POST, param, &value, strlen(value), &new_val_len TSRMLS_CC)) { + #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) +- if (php_mb_encoding_translation(TSRMLS_C)) { +- php_mb_gpc_stack_variable(param, value, &val_list, &len_list, +- &num_vars, &num_vars_max TSRMLS_CC); +- } else { +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); +- } ++ if (php_mb_encoding_translation(TSRMLS_C)) { ++ php_mb_gpc_stack_variable(param, value, &val_list, &len_list, ++ &num_vars, &num_vars_max TSRMLS_CC); ++ } else { ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ } + #else +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); + #endif ++ } + if (!strcasecmp(param, "MAX_FILE_SIZE")) { + max_file_size = atol(value); + } +@@ -981,6 +987,11 @@ + cancel_upload = UPLOAD_ERROR_D; + } + ++ if (sapi_module.pre_upload_filter && sapi_module.pre_upload_filter(param, filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ ++ offset = 0; + while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff) TSRMLS_CC))) + { + if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize)) { +@@ -990,6 +1001,11 @@ + sapi_module.sapi_error(E_WARNING, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename); + cancel_upload = UPLOAD_ERROR_B; + } else if (blen > 0) { ++ ++ if (sapi_module.upload_content_filter && sapi_module.upload_content_filter(offset, buff, blen, &blen TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ + wlen = fwrite(buff, 1, blen, fp); + + if (wlen < blen) { +@@ -997,6 +1013,7 @@ + cancel_upload = UPLOAD_ERROR_C; + } else { + total_bytes += wlen; ++ offset += wlen; + } + } + } +@@ -1011,6 +1028,10 @@ + } + #endif + ++ if (!cancel_upload && sapi_module.post_upload_filter && sapi_module.post_upload_filter(temp_filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ + if (cancel_upload) { + if (temp_filename) { + if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */ +diff -Naur php-4.3.11/main/SAPI.c hardening-patch-4.3.11-0.3.2/main/SAPI.c +--- php-4.3.11/main/SAPI.c 2005-02-22 15:46:24.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/main/SAPI.c 2005-07-09 08:53:02.490360072 +0200 +@@ -831,6 +831,31 @@ + return SUCCESS; + } + ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) ++{ ++ sapi_module.input_filter = input_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)) ++{ ++ sapi_module.pre_upload_filter = pre_upload_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)) ++{ ++ sapi_module.upload_content_filter = upload_content_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)) ++{ ++ sapi_module.post_upload_filter = post_upload_filter; ++ return SUCCESS; ++} ++ ++ + + SAPI_API int sapi_flush(TSRMLS_D) + { +diff -Naur php-4.3.11/main/SAPI.h hardening-patch-4.3.11-0.3.2/main/SAPI.h +--- php-4.3.11/main/SAPI.h 2003-04-09 22:27:55.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/main/SAPI.h 2005-07-09 08:53:02.491359920 +0200 +@@ -101,9 +101,10 @@ + char *current_user; + int current_user_length; + +- /* this is necessary for CLI module */ +- int argc; +- char **argv; ++ /* this is necessary for CLI module */ ++ int argc; ++ char **argv; ++ + } sapi_request_info; + + +@@ -177,6 +178,10 @@ + SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry); + SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D)); + SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC)); ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)); ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)); ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)); ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)); + + SAPI_API int sapi_flush(TSRMLS_D); + SAPI_API struct stat *sapi_get_stat(TSRMLS_D); +@@ -238,8 +243,15 @@ + int (*get_target_uid)(uid_t * TSRMLS_DC); + int (*get_target_gid)(gid_t * TSRMLS_DC); + ++ unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); ++ ++ unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC); ++ unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC); ++ unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC); ++ + void (*ini_defaults)(HashTable *configuration_hash); + int phpinfo_as_text; ++ + }; + + +@@ -262,16 +274,26 @@ + + #define SAPI_DEFAULT_MIMETYPE "text/html" + #define SAPI_DEFAULT_CHARSET "" ++ ++#if HARDENING_PATCH ++#define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION " with Hardening-Patch" ++#else + #define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION ++#endif + + #define SAPI_POST_READER_FUNC(post_reader) void post_reader(TSRMLS_D) + #define SAPI_POST_HANDLER_FUNC(post_handler) void post_handler(char *content_type_dup, void *arg TSRMLS_DC) + + #define SAPI_TREAT_DATA_FUNC(treat_data) void treat_data(int arg, char *str, zval* destArray TSRMLS_DC) ++#define SAPI_INPUT_FILTER_FUNC(input_filter) unsigned int input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) ++#define SAPI_PRE_UPLOAD_FILTER_FUNC(pre_upload_filter) unsigned int pre_upload_filter(char *varname, char *filename TSRMLS_DC) ++#define SAPI_UPLOAD_CONTENT_FILTER_FUNC(upload_content_filter) unsigned int upload_content_filter(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC) ++#define SAPI_POST_UPLOAD_FILTER_FUNC(post_upload_filter) unsigned int post_upload_filter(char *tmpfilename TSRMLS_DC) + + SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data); + SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader); + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data); ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter); + + #define STANDARD_SAPI_MODULE_PROPERTIES + +diff -Naur php-4.3.11/main/snprintf.c hardening-patch-4.3.11-0.3.2/main/snprintf.c +--- php-4.3.11/main/snprintf.c 2004-11-16 00:27:26.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/main/snprintf.c 2005-07-09 08:53:02.491359920 +0200 +@@ -850,7 +850,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Naur php-4.3.11/main/spprintf.c hardening-patch-4.3.11-0.3.2/main/spprintf.c +--- php-4.3.11/main/spprintf.c 2003-09-29 03:09:36.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/main/spprintf.c 2005-07-09 08:53:02.492359768 +0200 +@@ -531,7 +531,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Naur php-4.3.11/pear/go-pear-list.php hardening-patch-4.3.11-0.3.2/pear/go-pear-list.php +--- php-4.3.11/pear/go-pear-list.php 2005-03-18 02:58:20.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/pear/go-pear-list.php 2005-07-09 08:53:02.492359768 +0200 +@@ -8,7 +8,7 @@ + $packages = array( + // required packages for the installer + "PEAR" => "1.3.5", +-"XML_RPC" => "1.2.2", ++"XML_RPC" => "1.3.1", + "Console_Getopt" => "1.2", + "Archive_Tar" => "1.3.1", + +diff -Naur php-4.3.11/pear/packages/XML_RPC-1.2.2.tar hardening-patch-4.3.11-0.3.2/pear/packages/XML_RPC-1.2.2.tar +--- php-4.3.11/pear/packages/XML_RPC-1.2.2.tar 2005-03-28 19:02:28.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/pear/packages/XML_RPC-1.2.2.tar 1970-01-01 01:00:00.000000000 +0100 +@@ -1,3393 +0,0 @@ +-package2.xml100666 0 0 24326 10213112551 6327 +- +- XML_RPC +- pear.php.net +- PHP implementation of the XML-RPC protocol +- A PEAR-ified version of Useful Inc's XML-RPC for PHP. +- +-It has support for HTTP/HTTPS transport, proxies and authentication. +- +- Stig Bakken +- ssb +- stig@php.net +- no +- +- +- Daniel Convissor +- danielc +- danielc@php.net +- yes +- +- 2005-03-07 +- +- +- 1.2.2 +- 1.2.0 +- +- +- stable +- stable +- +- PHP License +- * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- PEAR +- pear.php.net +- 1.4.0a1 +- 1.4.0a4 +- +- +- +- +- 4.2.0 +- 6.0.0 +- +- +- 1.4.0a1 +- +- +- +- +- +- +- +- 1.2.1 +- 1.2.0 +- +- +- stable +- stable +- +- 2005-03-01 +- PHP License +- * Add isset() check before examining the dispatch map. Bug 3658. +- +- +- +- 1.2.0 +- 1.2.0 +- +- +- stable +- stable +- +- 2005-02-27 +- PHP License +- * Provide the "stable" release. +-* Add package2.xml for compatibility with PEAR 1.4.0. +-* For changes since 1.1.0, see the changelogs for the various RC releases. +- +- +- +- 1.2.0RC7 +- 1.2.0RC7 +- +- +- beta +- beta +- +- 2005-02-22 +- PHP License +- * Add the setSendEncoding() method and $send_encoding +- property to XML_RPC_Message. Request 3537. +-* Allow class methods to be mapped using either syntax: +- 'function' => 'hello::sayHello', +- or +- 'function' => array('hello', 'sayhello'), +- Bug 3363. +-* Use 8192 instead of 32768 for bytes in fread() +- in parseResponseFile(). Bug 3340. +- +- +- +- 1.2.0RC6 +- 1.2.0RC6 +- +- +- beta +- beta +- +- 2005-01-25 +- PHP License +- * Don't put the protocol in the Host field of the POST data. (danielc) +- +- +- +- 1.2.0RC5 +- 1.2.0RC5 +- +- +- beta +- beta +- +- 2005-01-24 +- PHP License +- * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. +- +- +- +- 1.2.0RC4 +- 1.2.0RC4 +- +- +- beta +- beta +- +- 2005-01-24 +- PHP License +- * When a connection attempt fails, have the method return 0. (danielc) +-* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) +-* Add tests for setting the client properties. (danielc) +-* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) +-* Bundle the tests with the package. (danielc) +- +- +- +- 1.2.0RC3 +- 1.2.0RC3 +- +- +- beta +- beta +- +- 2005-01-19 +- PHP License +- * ssl uses port 443, not 445. +- +- +- +- 1.2.0RC2 +- 1.2.0RC2 +- +- +- beta +- beta +- +- 2005-01-11 +- PHP License +- * Handle ssl:// in the $server string. (danielc) +-* Also default to port 445 for ssl:// requests as well. (danielc) +-* Enhance debugging in the server. (danielc) +- +- +- +- 1.2.0RC1 +- 1.2.0RC1 +- +- +- beta +- beta +- +- 2004-12-30 +- PHP License +- * Make things work with SSL. Bug 2489. (nkukard lbsd net) +-* Allow array function callbacks (Matt Kane) +-* Some minor speed-ups (Matt Kane) +-* Add Dump.php to the package (Christian Weiske) +-* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) +-* Silence fsockopen() errors. Bug 1714. (danielc) +-* Encode empty arrays as an array. Bug 1493. (danielc) +-* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) +-* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) +-* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) +-* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) +-* Allow raiseError() to be called statically. (danielc) +-* Stop double escaping of character entities. Bug 987. (danielc) +- NOTICE: the following have been removed: +- * XML_RPC_dh() +- * $GLOBALS['XML_RPC_entities'] +- * XML_RPC_entity_decode() +- * XML_RPC_lookup_entity() +-* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) +- +- +- +- 1.1.0 +- 1.1.0 +- +- +- stable +- stable +- +- 2004-03-15 +- PHP License +- * Added support for sequential arrays to XML_RPC_encode() (mroch) +-* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) +-* Remove "require_once 'PEAR.php'", include only when needed to raise an error +-* Replace echo and error_log() with raiseError() (mroch) +-* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) +-* be tolerant of junk after methodResponse (Luca Mariano, mroch) +-* Silent notice even in the error log (pierre) +-* fix include of shared xml extension on win32 (pierre) +- +- +- +- 1.0.4 +- 1.0.4 +- +- +- stable +- stable +- +- 2002-10-02 +- PHP License +- * added HTTP proxy authorization support (thanks to Arnaud Limbourg) +- +- +- +- 1.0.3 +- 1.0.3 +- +- +- stable +- stable +- +- 2002-05-19 +- PHP License +- * fix bug when parsing responses with boolean types +- +- +- +- 1.0.2 +- 1.0.2 +- +- +- stable +- stable +- +- 2002-04-16 +- PHP License +- * E_ALL fixes +-* fix HTTP response header parsing +- +- +- +- 1.0.1 +- 1.0.1 +- +- +- stable +- stable +- +- 2001-09-25 +- PHP License +- This is a PEAR-ified version of Useful Inc's 1.0.1 release. +-Includes an urgent security fix identified by Dan Libby <dan@libby.com>. +- +- +-XML_RPC-1.2.2/tests/protoport.php100666 0 0 25543 10213112550 11656 +- * @copyright 2005 The PHP Group +- * @license http://www.php.net/license/3_0.txt PHP License +- * @version CVS: $Id: protoport.php,v 1.4 2005/01/24 17:48:47 danielc Exp $ +- * @link http://pear.php.net/package/XML_RPC +- * @since File available since Release 1.2 +- */ +- +-/* +- * If the package version number is found in the left hand +- * portion of the if() expression below, that means this file has +- * come from the PEAR installer. Therefore, let's test the +- * installed version of XML_RPC which should be in the include path. +- * +- * If the version has not been substituted in the if() expression, +- * this file has likely come from a CVS checkout or a .tar file. +- * Therefore, we'll assume the tests should use the version of +- * XML_RPC that has come from there as well. +- */ +-if ('1.2.2' != '@'.'package_version'.'@') { +- /** +- * Get the needed class from the PEAR installation +- */ +- require_once 'XML/RPC.php'; +-} else { +- /** +- * Get the needed class from the parent directory +- */ +- require_once '../RPC.php'; +-} +- +-/** +- * Compare the test result to the expected result +- * +- * If the test fails, echo out the results. +- * +- * @param array $expect the array of object properties you expect +- * from the test +- * @param object $actual the object results from the test +- * @param string $test_name the name of the test +- * +- * @return void +- */ +-function compare($expect, $actual, $test_name) { +- $actual = get_object_vars($actual); +- if (count(array_diff($actual, $expect))) { +- echo "$test_name failed.\nExpect: "; +- print_r($expect); +- echo "Actual: "; +- print_r($actual); +- echo "\n"; +- } +-} +- +-if (php_sapi_name() != 'cli') { +- echo "
\n";
+-}
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver');
+-compare($x, $c, 'defaults');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver');
+-compare($x, $c, 'defaults with http');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver');
+-compare($x, $c, 'defaults with https');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver');
+-compare($x, $c, 'defaults with ssl');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 65);
+-compare($x, $c, 'port 65');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 65);
+-compare($x, $c, 'port 65 with http');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 65);
+-compare($x, $c, 'port 65 with https');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65);
+-compare($x, $c, 'port 65 with ssl');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 0,
+-                        'theproxy');
+-compare($x, $c, 'defaults proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 0,
+-                        'http://theproxy');
+-compare($x, $c, 'defaults with http proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 0,
+-                        'https://theproxy');
+-compare($x, $c, 'defaults with https proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 0,
+-                        'ssl://theproxy');
+-compare($x, $c, 'defaults with ssl proxy');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 65,
+-                        'theproxy', 6565);
+-compare($x, $c, 'port 65 proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 65,
+-                        'http://theproxy', 6565);
+-compare($x, $c, 'port 65 with http proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 65,
+-                        'https://theproxy', 6565);
+-compare($x, $c, 'port 65 with https proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65,
+-                        'ssl://theproxy', 6565);
+-compare($x, $c, 'port 65 with ssl proxy 6565');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 443,
+-                        'theproxy', 443);
+-compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 0,
+-                        'ssl://theproxy', 6565);
+-compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
+-XML_RPC-1.2.2/tests/test_Dump.php100666      0      0        3042 10213112550  11520 new XML_RPC_Value('das ist der Titel', 'string'),
+-    'startDate'=>new XML_RPC_Value(mktime(0,0,0,13,11,2004), 'dateTime.iso8601'),
+-    'endDate'  =>new XML_RPC_Value(mktime(0,0,0,15,11,2004), 'dateTime.iso8601'),
+-    'error'    =>'string',
+-    'arkey'    => new XML_RPC_Value( array(
+-        new XML_RPC_Value('simple string'),
+-        new XML_RPC_Value(12345, 'int')
+-        ), 'array')
+-    )
+-    ,'struct');
+-
+-XML_RPC_Dump($val);
+-
+-echo '==============' . "\r\n";
+-$val2 = new XML_RPC_Value(44353, 'int');
+-XML_RPC_Dump($val2);
+-
+-echo '==============' . "\r\n";
+-$val3 = new XML_RPC_Value('this should be a string', 'string');
+-XML_RPC_Dump($val3);
+-
+-echo '==============' . "\r\n";
+-$val4 = new XML_RPC_Value(true, 'boolean');
+-XML_RPC_Dump($val4);
+-XML_RPC-1.2.2/Dump.php100666      0      0       12074 10213112550   7344 
+- * @version    CVS: $Id: Dump.php,v 1.7 2005/01/24 03:47:55 danielc Exp $
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-
+-
+-/**
+- * Pull in the XML_RPC class
+- */
+-require_once 'XML/RPC.php';
+-
+-
+-/**
+- * Generates the dump of the XML_RPC_Value and echoes it
+- *
+- * @param object $value  the XML_RPC_Value object to dump
+- *
+- * @return void
+- */
+-function XML_RPC_Dump($value)
+-{
+-    $dumper = new XML_RPC_Dump();
+-    echo $dumper->generateDump($value);
+-}
+-
+-
+-/**
+- * Class which generates a dump of a XML_RPC_Value object
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Christian Weiske 
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Dump
+-{
+-    /**
+-     * The indentation array cache
+-     * @var array
+-     */
+-    var $arIndent      = array();
+-
+-    /**
+-     * The spaces used for indenting the XML
+-     * @var string
+-     */
+-    var $strBaseIndent = '    ';
+-
+-    /**
+-     * Returns the dump in XML format without printing it out
+-     *
+-     * @param object $value   the XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  the dump
+-     */
+-    function generateDump($value, $nLevel = 0)
+-    {
+-        if (!is_object($value) && get_class($value) != 'xml_rpc_value') {
+-            require_once 'PEAR.php';
+-            PEAR::raiseError('Tried to dump non-XML_RPC_Value variable' . "\r\n",
+-                             0, PEAR_ERROR_PRINT);
+-            if (is_object($value)) {
+-                $strType = get_class($value);
+-            } else {
+-                $strType = gettype($value);
+-            }
+-            return $this->getIndent($nLevel) . 'NOT A XML_RPC_Value: '
+-                   . $strType . "\r\n";
+-        }
+-
+-        switch ($value->kindOf()) {
+-        case 'struct':
+-            $ret = $this->genStruct($value, $nLevel);
+-            break;
+-        case 'array':
+-            $ret = $this->genArray($value, $nLevel);
+-            break;
+-        case 'scalar':
+-            $ret = $this->genScalar($value->scalarval(), $nLevel);
+-            break;
+-        default:
+-            require_once 'PEAR.php';
+-            PEAR::raiseError('Illegal type "' . $value->kindOf()
+-                             . '" in XML_RPC_Value' . "\r\n", 0,
+-                             PEAR_ERROR_PRINT);
+-        }
+-
+-        return $ret;
+-    }
+-
+-    /**
+-     * Returns the scalar value dump
+-     *
+-     * @param object $value   the scalar XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genScalar($value, $nLevel)
+-    {
+-        if (gettype($value) == 'object') {
+-            $strClass = ' ' . get_class($value);
+-        } else {
+-            $strClass = '';
+-        }
+-        return $this->getIndent($nLevel) . gettype($value) . $strClass
+-               . ' ' . $value . "\r\n";
+-    }
+-
+-    /**
+-     * Returns the dump of a struct
+-     *
+-     * @param object $value   the struct XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genStruct($value, $nLevel)
+-    {
+-        $value->structreset();
+-        $strOutput = $this->getIndent($nLevel) . 'struct' . "\r\n";
+-        while (list($key, $keyval) = $value->structeach()) {
+-            $strOutput .= $this->getIndent($nLevel + 1) . $key . "\r\n";
+-            $strOutput .= $this->generateDump($keyval, $nLevel + 2);
+-        }
+-        return $strOutput;
+-    }
+-
+-    /**
+-     * Returns the dump of an array
+-     *
+-     * @param object $value   the array XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genArray($value, $nLevel)
+-    {
+-        $nSize     = $value->arraysize();
+-        $strOutput = $this->getIndent($nLevel) . 'array' . "\r\n";
+-        for($nA = 0; $nA < $nSize; $nA++) {
+-            $strOutput .= $this->getIndent($nLevel + 1) . $nA . "\r\n";
+-            $strOutput .= $this->generateDump($value->arraymem($nA),
+-                                              $nLevel + 2);
+-        }
+-        return $strOutput;
+-    }
+-
+-    /**
+-     * Returns the indent for a specific level and caches it for faster use
+-     *
+-     * @param int $nLevel  the level
+-     *
+-     * @return string  the indented string
+-     */
+-    function getIndent($nLevel)
+-    {
+-        if (!isset($this->arIndent[$nLevel])) {
+-            $this->arIndent[$nLevel] = str_repeat($this->strBaseIndent, $nLevel);
+-        }
+-        return $this->arIndent[$nLevel];
+-    }
+-}
+-
+-/*
+- * Local variables:
+- * tab-width: 4
+- * c-basic-offset: 4
+- * c-hanging-comment-ender-p: nil
+- * End:
+- */
+-
+-?>
+-XML_RPC-1.2.2/RPC.php100666      0      0      141000 10213112550   7073 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    CVS: $Id: RPC.php,v 1.60 2005/03/07 17:45:08 danielc Exp $
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-
+-
+-if (!function_exists('xml_parser_create')) {
+-    // Win 32 fix. From: "Leo West" 
+-    if ($WINDIR) {
+-        dl('php_xml.dll');
+-    } else {
+-        dl('xml.so');
+-    }
+-}
+-
+-/**#@+
+- * Error constants
+- */
+-define('XML_RPC_ERROR_INVALID_TYPE',        101);
+-define('XML_RPC_ERROR_NON_NUMERIC_FOUND',   102);
+-define('XML_RPC_ERROR_CONNECTION_FAILED',   103);
+-define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
+-/**#@-*/
+-
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_I4']
+- */
+-$GLOBALS['XML_RPC_I4'] = 'i4';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Int']
+- */
+-$GLOBALS['XML_RPC_Int'] = 'int';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Boolean']
+- */
+-$GLOBALS['XML_RPC_Boolean'] = 'boolean';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Double']
+- */
+-$GLOBALS['XML_RPC_Double'] = 'double';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_String']
+- */
+-$GLOBALS['XML_RPC_String'] = 'string';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_DateTime']
+- */
+-$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Base64']
+- */
+-$GLOBALS['XML_RPC_Base64'] = 'base64';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Array']
+- */
+-$GLOBALS['XML_RPC_Array'] = 'array';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Struct']
+- */
+-$GLOBALS['XML_RPC_Struct'] = 'struct';
+-
+-
+-/**
+- * Data type meta-types
+- * @global array $GLOBALS['XML_RPC_Types']
+- */
+-$GLOBALS['XML_RPC_Types'] = array(
+-    $GLOBALS['XML_RPC_I4']       => 1,
+-    $GLOBALS['XML_RPC_Int']      => 1,
+-    $GLOBALS['XML_RPC_Boolean']  => 1,
+-    $GLOBALS['XML_RPC_String']   => 1,
+-    $GLOBALS['XML_RPC_Double']   => 1,
+-    $GLOBALS['XML_RPC_DateTime'] => 1,
+-    $GLOBALS['XML_RPC_Base64']   => 1,
+-    $GLOBALS['XML_RPC_Array']    => 2,
+-    $GLOBALS['XML_RPC_Struct']   => 3,
+-);
+-
+-
+-/**
+- * Error message numbers
+- * @global array $GLOBALS['XML_RPC_err']
+- */
+-$GLOBALS['XML_RPC_err'] = array(
+-    'unknown_method'      => 1,
+-    'invalid_return'      => 2,
+-    'incorrect_params'    => 3,
+-    'introspect_unknown'  => 4,
+-    'http_error'          => 5,
+-);
+-
+-/**
+- * Error message strings
+- * @global array $GLOBALS['XML_RPC_str']
+- */
+-$GLOBALS['XML_RPC_str'] = array(
+-    'unknown_method'      => 'Unknown method',
+-    'invalid_return'      => 'Invalid return payload: enable debugging to examine incoming payload',
+-    'incorrect_params'    => 'Incorrect parameters passed to method',
+-    'introspect_unknown'  => 'Can\'t introspect: method unknown',
+-    'http_error'          => 'Didn\'t receive 200 OK from remote server.',
+-);
+-
+-
+-/**
+- * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
+- * @global string $GLOBALS['XML_RPC_defencoding']
+- */
+-$GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
+-
+-/**
+- * User error codes start at 800
+- * @global int $GLOBALS['XML_RPC_erruser']
+- */
+-$GLOBALS['XML_RPC_erruser'] = 800;
+-
+-/**
+- * XML parse error codes start at 100
+- * @global int $GLOBALS['XML_RPC_errxml']
+- */
+-$GLOBALS['XML_RPC_errxml'] = 100;
+-
+-
+-/**
+- * Compose backslashes for escaping regexp
+- * @global string $GLOBALS['XML_RPC_backslash']
+- */
+-$GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
+-
+-
+-/**
+- * Stores state during parsing
+- *
+- * quick explanation of components:
+- *   + st     = builds up a string for evaluation
+- *   + ac     = accumulates values
+- *   + qt     = decides if quotes are needed for evaluation
+- *   + cm     = denotes struct or array (comma needed)
+- *   + isf    = indicates a fault
+- *   + lv     = indicates "looking for a value": implements the logic
+- *               to allow values with no types to be strings
+- *   + params = stores parameters in method calls
+- *   + method = stores method name
+- *
+- * @global array $GLOBALS['XML_RPC_xh']
+- */
+-$GLOBALS['XML_RPC_xh'] = array();
+-
+-
+-/**
+- * Start element handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_se($parser, $name, $attrs)
+-{
+-    global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String;
+-
+-    switch ($name) {
+-    case 'STRUCT':
+-    case 'ARRAY':
+-        $XML_RPC_xh[$parser]['st'] .= 'array(';
+-        $XML_RPC_xh[$parser]['cm']++;
+-        // this last line turns quoting off
+-        // this means if we get an empty array we'll
+-        // simply get a bit of whitespace in the eval
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'NAME':
+-        $XML_RPC_xh[$parser]['st'] .= "'";
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        break;
+-
+-    case 'FAULT':
+-        $XML_RPC_xh[$parser]['isf'] = 1;
+-        break;
+-
+-    case 'PARAM':
+-        $XML_RPC_xh[$parser]['st'] = '';
+-        break;
+-
+-    case 'VALUE':
+-        $XML_RPC_xh[$parser]['st'] .= 'new XML_RPC_Value(';
+-        $XML_RPC_xh[$parser]['lv'] = 1;
+-        $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        // look for a value: if this is still 1 by the
+-        // time we reach the first data segment then the type is string
+-        // by implication and we need to add in a quote
+-        break;
+-
+-    case 'I4':
+-    case 'INT':
+-    case 'STRING':
+-    case 'BOOLEAN':
+-    case 'DOUBLE':
+-    case 'DATETIME.ISO8601':
+-    case 'BASE64':
+-        $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
+-
+-        if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
+-            $XML_RPC_xh[$parser]['qt'] = 1;
+-
+-            if ($name == 'DATETIME.ISO8601') {
+-                $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
+-            }
+-
+-        } elseif ($name == 'BASE64') {
+-            $XML_RPC_xh[$parser]['qt'] = 2;
+-        } else {
+-            // No quoting is required here -- but
+-            // at the end of the element we must check
+-            // for data format errors.
+-            $XML_RPC_xh[$parser]['qt'] = 0;
+-        }
+-        break;
+-
+-    case 'MEMBER':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-    }
+-
+-    if ($name != 'VALUE') {
+-        $XML_RPC_xh[$parser]['lv'] = 0;
+-    }
+-}
+-
+-/**
+- * End element handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_ee($parser, $name)
+-{
+-    global $XML_RPC_xh, $XML_RPC_Types, $XML_RPC_String;
+-
+-    switch ($name) {
+-    case 'STRUCT':
+-    case 'ARRAY':
+-        if ($XML_RPC_xh[$parser]['cm']
+-            && substr($XML_RPC_xh[$parser]['st'], -1) == ',')
+-        {
+-            $XML_RPC_xh[$parser]['st'] = substr($XML_RPC_xh[$parser]['st'], 0, -1);
+-        }
+-
+-        $XML_RPC_xh[$parser]['st'] .= ')';
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-        $XML_RPC_xh[$parser]['cm']--;
+-        break;
+-
+-    case 'NAME':
+-        $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'] . "' => ";
+-        break;
+-
+-    case 'BOOLEAN':
+-        // special case here: we translate boolean 1 or 0 into PHP
+-        // constants true or false
+-        if ($XML_RPC_xh[$parser]['ac'] == '1') {
+-            $XML_RPC_xh[$parser]['ac'] = 'true';
+-        } else {
+-            $XML_RPC_xh[$parser]['ac'] = 'false';
+-        }
+-
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-        // Drop through intentionally.
+-
+-    case 'I4':
+-    case 'INT':
+-    case 'STRING':
+-    case 'DOUBLE':
+-    case 'DATETIME.ISO8601':
+-    case 'BASE64':
+-        if ($XML_RPC_xh[$parser]['qt'] == 1) {
+-            // we use double quotes rather than single so backslashification works OK
+-            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
+-        } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
+-            $XML_RPC_xh[$parser]['st'] .= "base64_decode('"
+-                                        . $XML_RPC_xh[$parser]['ac'] . "')";
+-        } elseif ($name == 'BOOLEAN') {
+-            $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
+-        } else {
+-            // we have an I4, INT or a DOUBLE
+-            // we must check that only 0123456789-. are characters here
+-            if (!ereg("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
+-                XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
+-                                         XML_RPC_ERROR_NON_NUMERIC_FOUND);
+-                $XML_RPC_xh[$parser]['st'] .= 'XML_RPC_ERROR_NON_NUMERIC_FOUND';
+-            } else {
+-                // it's ok, add it on
+-                $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
+-            }
+-        }
+-
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
+-        break;
+-
+-    case 'VALUE':
+-        // deal with a string value
+-        if (strlen($XML_RPC_xh[$parser]['ac']) > 0 &&
+-            $XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
+-
+-            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
+-        }
+-
+-        // This if () detects if no scalar was inside 
+-        // and pads an empty "".
+-        if ($XML_RPC_xh[$parser]['st'][strlen($XML_RPC_xh[$parser]['st'])-1] == '(') {
+-            $XML_RPC_xh[$parser]['st'] .= '""';
+-        }
+-        $XML_RPC_xh[$parser]['st'] .= ", '" . $XML_RPC_xh[$parser]['vt'] . "')";
+-        if ($XML_RPC_xh[$parser]['cm']) {
+-            $XML_RPC_xh[$parser]['st'] .= ',';
+-        }
+-        break;
+-
+-    case 'MEMBER':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'DATA':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'PARAM':
+-        $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['st'];
+-        break;
+-
+-    case 'METHODNAME':
+-        $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", '',
+-                                                      $XML_RPC_xh[$parser]['ac']);
+-        break;
+-
+-    case 'BOOLEAN':
+-        // special case here: we translate boolean 1 or 0 into PHP
+-        // constants true or false
+-        if ($XML_RPC_xh[$parser]['ac'] == '1') {
+-            $XML_RPC_xh[$parser]['ac'] = 'true';
+-        } else {
+-            $XML_RPC_xh[$parser]['ac'] = 'false';
+-        }
+-
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-    }
+-
+-    // if it's a valid type name, set the type
+-    if (isset($XML_RPC_Types[strtolower($name)])) {
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-    }
+-}
+-
+-/**
+- * Character data handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_cd($parser, $data)
+-{
+-    global $XML_RPC_xh, $XML_RPC_backslash;
+-
+-    if ($XML_RPC_xh[$parser]['lv'] != 3) {
+-        // "lookforvalue==3" means that we've found an entire value
+-        // and should discard any further character data
+-
+-        if ($XML_RPC_xh[$parser]['lv'] == 1) {
+-            // if we've found text and we're just in a  then
+-            // turn quoting on, as this will be a string
+-            $XML_RPC_xh[$parser]['qt'] = 1;
+-            // and say we've found a value
+-            $XML_RPC_xh[$parser]['lv'] = 2;
+-        }
+-
+-        // replace characters that eval would
+-        // do special things with
+-        if (!isset($XML_RPC_xh[$parser]['ac'])) {
+-            $XML_RPC_xh[$parser]['ac'] = '';
+-        }
+-        $XML_RPC_xh[$parser]['ac'] .= str_replace('$', '\$',
+-            str_replace('"', '\"', str_replace(chr(92),
+-            $XML_RPC_backslash, $data)));
+-    }
+-}
+-
+-/**
+- * Base class
+- *
+- * This class provides common functions for all of the XML_RPC classes.
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Base {
+-
+-    /**
+-     * PEAR Error handling
+-     *
+-     * @return object  PEAR_Error object
+-     */
+-    function raiseError($msg, $code)
+-    {
+-        include_once 'PEAR.php';
+-        if (is_object(@$this)) {
+-            return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
+-        } else {
+-            return PEAR::raiseError('XML_RPC: ' . $msg, $code);
+-        }
+-    }
+-
+-    /**
+-     * Tell whether something is a PEAR_Error object
+-     *
+-     * @param mixed $value  the item to check
+-     *
+-     * @return bool  whether $value is a PEAR_Error object or not
+-     *
+-     * @access public
+-     */
+-    function isError($value)
+-    {
+-        return is_a($value, 'PEAR_Error');
+-    }
+-}
+-
+-/**
+- *
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Client extends XML_RPC_Base {
+-
+-    /**
+-     * The path and name of the RPC server script you want the request to go to
+-     * @var string
+-     */
+-    var $path = '';
+-
+-    /**
+-     * The name of the remote server to connect to
+-     * @var string
+-     */
+-    var $server = '';
+-
+-    /**
+-     * The protocol to use in contacting the remote server
+-     * @var string
+-     */
+-    var $protocol = 'http://';
+-
+-    /**
+-     * The port for connecting to the remote server
+-     *
+-     * The default is 80 for http:// connections
+-     * and 443 for https:// and ssl:// connections.
+-     *
+-     * @var integer
+-     */
+-    var $port = 80;
+-
+-    /**
+-     * A user name for accessing the RPC server
+-     * @var string
+-     * @see XML_RPC_Client::setCredentials()
+-     */
+-    var $username = '';
+-
+-    /**
+-     * A password for accessing the RPC server
+-     * @var string
+-     * @see XML_RPC_Client::setCredentials()
+-     */
+-    var $password = '';
+-
+-    /**
+-     * The name of the proxy server to use, if any
+-     * @var string
+-     */
+-    var $proxy = '';
+-
+-    /**
+-     * The protocol to use in contacting the proxy server, if any
+-     * @var string
+-     */
+-    var $proxy_protocol = 'http://';
+-
+-    /**
+-     * The port for connecting to the proxy server
+-     *
+-     * The default is 8080 for http:// connections
+-     * and 443 for https:// and ssl:// connections.
+-     *
+-     * @var integer
+-     */
+-    var $proxy_port = 8080;
+-
+-    /**
+-     * A user name for accessing the proxy server
+-     * @var string
+-     */
+-    var $proxy_user = '';
+-
+-    /**
+-     * A password for accessing the proxy server
+-     * @var string
+-     */
+-    var $proxy_pass = '';
+-
+-    /**
+-     * The error number, if any
+-     * @var integer
+-     */
+-    var $errno = 0;
+-
+-    /**
+-     * The error message, if any
+-     * @var string
+-     */
+-    var $errstring = '';
+-
+-    /**
+-     * The current debug mode (1 = on, 0 = off)
+-     * @var integer
+-     */
+-    var $debug = 0;
+-
+-
+-    /**
+-     * Sets the object's properties
+-     *
+-     * @param string  $path        the path and name of the RPC server script
+-     *                              you want the request to go to
+-     * @param string  $server      the URL of the remote server to connect to.
+-     *                              If this parameter doesn't specify a
+-     *                              protocol and $port is 443, ssl:// is
+-     *                              assumed.
+-     * @param integer $port        a port for connecting to the remote server.
+-     *                              Defaults to 80 for http:// connections and
+-     *                              443 for https:// and ssl:// connections.
+-     * @param string  $proxy       the URL of the proxy server to use, if any.
+-     *                              If this parameter doesn't specify a
+-     *                              protocol and $port is 443, ssl:// is
+-     *                              assumed.
+-     * @param integer $proxy_port  a port for connecting to the remote server.
+-     *                              Defaults to 8080 for http:// connections and
+-     *                              443 for https:// and ssl:// connections.
+-     * @param string  $proxy_user  a user name for accessing the proxy server
+-     * @param string  $proxy_pass  a password for accessing the proxy server
+-     *
+-     * @return void
+-     */
+-    function XML_RPC_Client($path, $server, $port = 0,
+-                            $proxy = '', $proxy_port = 0,
+-                            $proxy_user = '', $proxy_pass = '')
+-    {
+-        $this->path       = $path;
+-        $this->proxy_user = $proxy_user;
+-        $this->proxy_pass = $proxy_pass;
+-
+-        preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match);
+-        if ($match[1] == '') {
+-            if ($port == 443) {
+-                $this->server   = $match[2];
+-                $this->protocol = 'ssl://';
+-                $this->port     = 443;
+-            } else {
+-                $this->server = $match[2];
+-                if ($port) {
+-                    $this->port = $port;
+-                }
+-            }
+-        } elseif ($match[1] == 'http://') {
+-            $this->server = $match[2];
+-            if ($port) {
+-                $this->port = $port;
+-            }
+-        } else {
+-            $this->server   = $match[2];
+-            $this->protocol = 'ssl://';
+-            if ($port) {
+-                $this->port = $port;
+-            } else {
+-                $this->port = 443;
+-            }
+-        }
+-
+-        if ($proxy) {
+-            preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match);
+-            if ($match[1] == '') {
+-                if ($proxy_port == 443) {
+-                    $this->proxy          = $match[2];
+-                    $this->proxy_protocol = 'ssl://';
+-                    $this->proxy_port     = 443;
+-                } else {
+-                    $this->proxy = $match[2];
+-                    if ($proxy_port) {
+-                        $this->proxy_port = $proxy_port;
+-                    }
+-                }
+-            } elseif ($match[1] == 'http://') {
+-                $this->proxy = $match[2];
+-                if ($proxy_port) {
+-                    $this->proxy_port = $proxy_port;
+-                }
+-            } else {
+-                $this->proxy          = $match[2];
+-                $this->proxy_protocol = 'ssl://';
+-                if ($proxy_port) {
+-                    $this->proxy_port = $proxy_port;
+-                } else {
+-                    $this->proxy_port = 443;
+-                }
+-            }
+-        }
+-    }
+-
+-    /**
+-     * Change the current debug mode
+-     *
+-     * @param int $in  where 1 = on, 0 = off
+-     *
+-     * @return void
+-     */
+-    function setDebug($in)
+-    {
+-        if ($in) {
+-            $this->debug = 1;
+-        } else {
+-            $this->debug = 0;
+-        }
+-    }
+-
+-    /**
+-     * Set username and password properties for connecting to the RPC server
+-     *
+-     * @param string $u  the user name
+-     * @param string $p  the password
+-     *
+-     * @return void
+-     *
+-     * @see XML_RPC_Client::$username, XML_RPC_Client::$password
+-     */
+-    function setCredentials($u, $p)
+-    {
+-        $this->username = $u;
+-        $this->password = $p;
+-    }
+-
+-    /**
+-     * Transmit the RPC request via HTTP 1.0 protocol
+-     *
+-     * @param object $msg       the XML_RPC_Message object
+-     * @param int    $timeout   how many seconds to wait for the request
+-     *
+-     * @return object  an XML_RPC_Response object.  0 is returned if any
+-     *                  problems happen.
+-     *
+-     * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
+-     *      XML_RPC_Client::setCredentials()
+-     */
+-    function send($msg, $timeout = 0)
+-    {
+-        $msg->debug = $this->debug;
+-        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
+-                                        $timeout, $this->username,
+-                                        $this->password);
+-    }
+-
+-    /**
+-     * Transmit the RPC request via HTTP 1.0 protocol
+-     *
+-     * Requests should be sent using XML_RPC_Client send() rather than
+-     * calling this method directly.
+-     *
+-     * @param object $msg       the XML_RPC_Message object
+-     * @param string $server    the server to send the request to
+-     * @param int    $port      the server port send the request to
+-     * @param int    $timeout   how many seconds to wait for the request
+-     *                           before giving up
+-     * @param string $username  a user name for accessing the RPC server
+-     * @param string $password  a password for accessing the RPC server
+-     *
+-     * @return object  an XML_RPC_Response object.  0 is returned if any
+-     *                  problems happen.
+-     *
+-     * @see XML_RPC_Client::send()
+-     */
+-    function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
+-                               $username = '', $password = '')
+-    {
+-        /*
+-         * If we're using a proxy open a socket to the proxy server
+-         * instead to the xml-rpc server
+-         */
+-        if ($this->proxy) {
+-            if ($this->proxy_protocol == 'http://') {
+-                $protocol = '';
+-            } else {
+-                $protocol = $this->proxy_protocol;
+-            }
+-            if ($timeout > 0) {
+-                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
+-                                 $this->errno, $this->errstr, $timeout);
+-            } else {
+-                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
+-                                 $this->errno, $this->errstr);
+-            }
+-        } else {
+-            if ($this->protocol == 'http://') {
+-                $protocol = '';
+-            } else {
+-                $protocol = $this->protocol;
+-            }
+-            if ($timeout > 0) {
+-                $fp = @fsockopen($protocol . $server, $port,
+-                                 $this->errno, $this->errstr, $timeout);
+-            } else {
+-                $fp = @fsockopen($protocol . $server, $port,
+-                                 $this->errno, $this->errstr);
+-            }
+-        }
+-
+-        /*
+-         * Just raising the error without returning it is strange,
+-         * but keep it here for backwards compatibility.
+-         */
+-        if (!$fp && $this->proxy) {
+-            $this->raiseError('Connection to proxy server '
+-                              . $this->proxy . ':' . $this->proxy_port
+-                              . ' failed. ' . $this->errstr,
+-                              XML_RPC_ERROR_CONNECTION_FAILED);
+-            return 0;
+-        } elseif (!$fp) {
+-            $this->raiseError('Connection to RPC server '
+-                              . $server . ':' . $port
+-                              . ' failed. ' . $this->errstr,
+-                              XML_RPC_ERROR_CONNECTION_FAILED);
+-            return 0;
+-        }
+-
+-        // Only create the payload if it was not created previously
+-        if (empty($msg->payload)) {
+-            $msg->createPayload();
+-        }
+-
+-        // thanks to Grant Rauscher  for this
+-        $credentials = '';
+-        if ($username != '') {
+-            $credentials = 'Authorization: Basic ' .
+-                base64_encode($username . ':' . $password) . "\r\n";
+-        }
+-
+-        if ($this->proxy) {
+-            $op = 'POST ' . $this->protocol . $server;
+-            if ($this->proxy_port) {
+-                $op .= ':' . $this->port;
+-            }
+-        } else {
+-           $op = 'POST ';
+-        }
+-
+-        $op .= $this->path. " HTTP/1.0\r\n" .
+-               "User-Agent: PEAR XML_RPC\r\n" .
+-               'Host: ' . $server . "\r\n";
+-        if ($this->proxy && $this->proxy_user != '') {
+-            $op .= 'Proxy-Authorization: Basic ' .
+-                base64_encode($this->proxy_user . ':' . $this->proxy_pass) .
+-                "\r\n";
+-        }
+-        $op .= $credentials .
+-               "Content-Type: text/xml\r\n" .
+-               'Content-Length: ' . strlen($msg->payload) . "\r\n\r\n" .
+-               $msg->payload;
+-
+-        if (!fputs($fp, $op, strlen($op))) {
+-            $this->errstr = 'Write error';
+-            return 0;
+-        }
+-        $resp = $msg->parseResponseFile($fp);
+-        fclose($fp);
+-        return $resp;
+-    }
+-}
+-
+-/**
+- *
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Response extends XML_RPC_Base
+-{
+-    var $xv;
+-    var $fn;
+-    var $fs;
+-    var $hdrs;
+-
+-    /**
+-     * @return void
+-     */
+-    function XML_RPC_Response($val, $fcode = 0, $fstr = '')
+-    {
+-        if ($fcode != 0) {
+-            $this->fn = $fcode;
+-            $this->fs = htmlspecialchars($fstr);
+-        } else {
+-            $this->xv = $val;
+-        }
+-    }
+-
+-    /**
+-     * @return int  the error code
+-     */
+-    function faultCode()
+-    {
+-        if (isset($this->fn)) {
+-            return $this->fn;
+-        } else {
+-            return 0;
+-        }
+-    }
+-
+-    /**
+-     * @return string  the error string
+-     */
+-    function faultString()
+-    {
+-        return $this->fs;
+-    }
+-
+-    /**
+-     * @return mixed  the value
+-     */
+-    function value()
+-    {
+-        return $this->xv;
+-    }
+-
+-    /**
+-     * @return string  the error message in XML format
+-     */
+-    function serialize()
+-    {
+-        $rs = "\n";
+-        if ($this->fn) {
+-            $rs .= "
+-  
+-    
+-      
+-        faultCode
+-        " . $this->fn . "
+-      
+-      
+-        faultString
+-        " . $this->fs . "
+-      
+-    
+-  
+-";
+-        } else {
+-            $rs .= "\n\n" . $this->xv->serialize() .
+-        "\n";
+-        }
+-        $rs .= "\n";
+-        return $rs;
+-    }
+-}
+-
+-/**
+- *
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Message extends XML_RPC_Base
+-{
+-    /**
+-     * The current debug mode (1 = on, 0 = off)
+-     * @var integer
+-     */
+-    var $debug = 0;
+-
+-    /**
+-     * The encoding to be used for outgoing messages
+-     *
+-     * Defaults to the value of $GLOBALS['XML_RPC_defencoding']
+-     *
+-     * @var string
+-     * @see XML_RPC_Message::setSendEncoding(),
+-     *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
+-     */
+-    var $send_encoding = '';
+-
+-    /**
+-     * The method presently being evaluated
+-     * @var string
+-     */
+-    var $methodname = '';
+-
+-    /**
+-     * @var array
+-     */
+-    var $params = array();
+-
+-    /**
+-     * The XML message being generated
+-     * @var string
+-     */
+-    var $payload = '';
+-
+-    /**
+-     * @return void
+-     */
+-    function XML_RPC_Message($meth, $pars = 0)
+-    {
+-        $this->methodname = $meth;
+-        if (is_array($pars) && sizeof($pars) > 0) {
+-            for ($i = 0; $i < sizeof($pars); $i++) {
+-                $this->addParam($pars[$i]);
+-            }
+-        }
+-    }
+-
+-    /**
+-     * Produces the XML declaration including the encoding attribute
+-     *
+-     * The encoding is determined by this class' $send_encoding
+-     * property.  If the $send_encoding property is not set, use
+-     * $GLOBALS['XML_RPC_defencoding'].
+-     *
+-     * @return string  the XML declaration and  element
+-     *
+-     * @see XML_RPC_Message::setSendEncoding(),
+-     *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
+-     */
+-    function xml_header()
+-    {
+-        global $XML_RPC_defencoding;
+-        if (!$this->send_encoding) {
+-            $this->send_encoding = $XML_RPC_defencoding;
+-        }
+-        return 'send_encoding . '"?>'
+-               . "\n\n";
+-    }
+-
+-    /**
+-     * @return string  the closing  tag
+-     */
+-    function xml_footer()
+-    {
+-        return "\n";
+-    }
+-
+-    /**
+-     * @return void
+-     *
+-     * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
+-     */
+-    function createPayload()
+-    {
+-        $this->payload = $this->xml_header();
+-        $this->payload .= '' . $this->methodname . "\n";
+-        $this->payload .= "\n";
+-        for ($i = 0; $i < sizeof($this->params); $i++) {
+-            $p = $this->params[$i];
+-            $this->payload .= "\n" . $p->serialize() . "\n";
+-        }
+-        $this->payload .= "\n";
+-        $this->payload .= $this->xml_footer();
+-        $this->payload = ereg_replace("[\r\n]+", "\r\n", $this->payload);
+-    }
+-
+-    /**
+-     * @return string  the name of the method
+-     */
+-    function method($meth = '')
+-    {
+-        if ($meth != '') {
+-            $this->methodname = $meth;
+-        }
+-        return $this->methodname;
+-    }
+-
+-    /**
+-     * @return string  the payload
+-     */
+-    function serialize()
+-    {
+-        $this->createPayload();
+-        return $this->payload;
+-    }
+-
+-    /**
+-     * @return void
+-     */
+-    function addParam($par)
+-    {
+-        $this->params[] = $par;
+-    }
+-
+-    /**
+-     * @return void
+-     */
+-    function getParam($i)
+-    {
+-        return $this->params[$i];
+-    }
+-
+-    /**
+-     * @return int  the number of parameters
+-     */
+-    function getNumParams()
+-    {
+-        return sizeof($this->params);
+-    }
+-
+-    /**
+-     * Sets the XML declaration's encoding attribute
+-     *
+-     * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
+-     *
+-     * @return void
+-     *
+-     * @see XML_RPC_Message::$send_encoding, XML_RPC_Message::xml_header()
+-     * @since Method available since Release 1.2.0
+-     */
+-    function setSendEncoding($type)
+-    {
+-        $this->send_encoding = $type;
+-    }
+-
+-    /**
+-     * Determine the XML's encoding via the encoding attribute
+-     * in the XML declaration
+-     *
+-     * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
+-     * or US-ASCII, $XML_RPC_defencoding will be returned.
+-     *
+-     * @param string $data  the XML that will be parsed
+-     *
+-     * @return string  the encoding to be used
+-     *
+-     * @link   http://php.net/xml_parser_create
+-     * @since  Method available since Release 1.2.0
+-     */
+-    function getEncoding($data)
+-    {
+-        global $XML_RPC_defencoding;
+-
+-        if (preg_match('/<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]/i',
+-                       $data, $match))
+-        {
+-            $match[1] = trim(strtoupper($match[1]));
+-            switch ($match[1]) {
+-                case 'ISO-8859-1':
+-                case 'UTF-8':
+-                case 'US-ASCII':
+-                    return $match[1];
+-                    break;
+-
+-                default:
+-                    return $XML_RPC_defencoding;
+-            }
+-        } else {
+-            return $XML_RPC_defencoding;
+-        }
+-    }
+-
+-    /**
+-     * @return object  a new XML_RPC_Response object
+-     */
+-    function parseResponseFile($fp)
+-    {
+-        $ipd = '';
+-        while ($data = @fread($fp, 8192)) {
+-            $ipd .= $data;
+-        }
+-        return $this->parseResponse($ipd);
+-    }
+-
+-    /**
+-     * @return object  a new XML_RPC_Response object
+-     */
+-    function parseResponse($data = '')
+-    {
+-        global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
+-
+-        $encoding = $this->getEncoding($data);
+-        $parser = xml_parser_create($encoding);
+-
+-        $XML_RPC_xh[$parser] = array();
+-
+-        $XML_RPC_xh[$parser]['st'] = '';
+-        $XML_RPC_xh[$parser]['cm'] = 0;
+-        $XML_RPC_xh[$parser]['isf'] = 0;
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = '';
+-
+-        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
+-        xml_set_element_handler($parser, 'XML_RPC_se', 'XML_RPC_ee');
+-        xml_set_character_data_handler($parser, 'XML_RPC_cd');
+-
+-        $hdrfnd = 0;
+-        if ($this->debug) {
+-            print "
---GOT---\n";
+-            print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
+-            print "\n---END---\n
"; +- } +- +- // see if we got an HTTP 200 OK, else bomb +- // but only do this if we're using the HTTP protocol. +- if (ereg('^HTTP', $data) && +- !ereg('^HTTP/[0-9\.]+ 200 ', $data)) { +- $errstr = substr($data, 0, strpos($data, "\n") - 1); +- error_log('HTTP error, got response: ' . $errstr); +- $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], +- $XML_RPC_str['http_error'] . ' (' . +- $errstr . ')'); +- xml_parser_free($parser); +- return $r; +- } +- // gotta get rid of headers here +- +- +- if ((!$hdrfnd) && ($brpos = strpos($data,"\r\n\r\n"))) { +- $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos); +- $data = substr($data, $brpos + 4); +- $hdrfnd = 1; +- } +- +- /* +- * be tolerant of junk after methodResponse +- * (e.g. javascript automatically inserted by free hosts) +- * thanks to Luca Mariano +- */ +- $data = substr($data, 0, strpos($data, "") + 17); +- +- if (!xml_parse($parser, $data, sizeof($data))) { +- // thanks to Peter Kocks +- if ((xml_get_current_line_number($parser)) == 1) { +- $errstr = 'XML error at line 1, check URL'; +- } else { +- $errstr = sprintf('XML error: %s at line %d', +- xml_error_string(xml_get_error_code($parser)), +- xml_get_current_line_number($parser)); +- } +- error_log($errstr); +- $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], +- $XML_RPC_str['invalid_return']); +- xml_parser_free($parser); +- return $r; +- } +- xml_parser_free($parser); +- if ($this->debug) { +- print '
---EVALING---[' .
+-            strlen($XML_RPC_xh[$parser]['st']) . " chars]---\n" .
+-            htmlspecialchars($XML_RPC_xh[$parser]['st']) . ";\n---END---
"; +- } +- if (strlen($XML_RPC_xh[$parser]['st']) == 0) { +- // then something odd has happened +- // and it's time to generate a client side error +- // indicating something odd went on +- $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], +- $XML_RPC_str['invalid_return']); +- } else { +- eval('$v=' . $XML_RPC_xh[$parser]['st'] . '; $allOK=1;'); +- if ($XML_RPC_xh[$parser]['isf']) { +- $f = $v->structmem('faultCode'); +- $fs = $v->structmem('faultString'); +- $r = new XML_RPC_Response($v, $f->scalarval(), +- $fs->scalarval()); +- } else { +- $r = new XML_RPC_Response($v); +- } +- } +- $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]); +- return $r; +- } +-} +- +-/** +- * +- * +- * @category Web Services +- * @package XML_RPC +- * @author Edd Dumbill +- * @author Stig Bakken +- * @author Martin Jansen +- * @copyright 1999-2001 Edd Dumbill +- * @version Release: 1.2.2 +- * @link http://pear.php.net/package/XML_RPC +- */ +-class XML_RPC_Value extends XML_RPC_Base +-{ +- var $me = array(); +- var $mytype = 0; +- +- /** +- * @return void +- */ +- function XML_RPC_Value($val = -1, $type = '') +- { +- global $XML_RPC_Types; +- $this->me = array(); +- $this->mytype = 0; +- if ($val != -1 || $type != '') { +- if ($type == '') { +- $type = 'string'; +- } +- if (!array_key_exists($type, $XML_RPC_Types)) { +- // XXX +- // need some way to report this error +- } elseif ($XML_RPC_Types[$type] == 1) { +- $this->addScalar($val, $type); +- } elseif ($XML_RPC_Types[$type] == 2) { +- $this->addArray($val); +- } elseif ($XML_RPC_Types[$type] == 3) { +- $this->addStruct($val); +- } +- } +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addScalar($val, $type = 'string') +- { +- global $XML_RPC_Types, $XML_RPC_Boolean; +- +- if ($this->mytype == 1) { +- $this->raiseError('Scalar can have only one value', +- XML_RPC_ERROR_INVALID_TYPE); +- return 0; +- } +- $typeof = $XML_RPC_Types[$type]; +- if ($typeof != 1) { +- $this->raiseError("Not a scalar type (${typeof})", +- XML_RPC_ERROR_INVALID_TYPE); +- return 0; +- } +- +- if ($type == $XML_RPC_Boolean) { +- if (strcasecmp($val, 'true') == 0 +- || $val == 1 +- || ($val == true && strcasecmp($val, 'false'))) +- { +- $val = 1; +- } else { +- $val = 0; +- } +- } +- +- if ($this->mytype == 2) { +- // we're adding to an array here +- $ar = $this->me['array']; +- $ar[] = new XML_RPC_Value($val, $type); +- $this->me['array'] = $ar; +- } else { +- // a scalar, so set the value and remember we're scalar +- $this->me[$type] = $val; +- $this->mytype = $typeof; +- } +- return 1; +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addArray($vals) +- { +- global $XML_RPC_Types; +- if ($this->mytype != 0) { +- $this->raiseError( +- 'Already initialized as a [' . $this->kindOf() . ']', +- XML_RPC_ERROR_ALREADY_INITIALIZED); +- return 0; +- } +- $this->mytype = $XML_RPC_Types['array']; +- $this->me['array'] = $vals; +- return 1; +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addStruct($vals) +- { +- global $XML_RPC_Types; +- if ($this->mytype != 0) { +- $this->raiseError( +- 'Already initialized as a [' . $this->kindOf() . ']', +- XML_RPC_ERROR_ALREADY_INITIALIZED); +- return 0; +- } +- $this->mytype = $XML_RPC_Types['struct']; +- $this->me['struct'] = $vals; +- return 1; +- } +- +- /** +- * @return void +- */ +- function dump($ar) +- { +- reset($ar); +- while (list($key, $val) = each($ar)) { +- echo "$key => $val
"; +- if ($key == 'array') { +- while (list($key2, $val2) = each($val)) { +- echo "-- $key2 => $val2
"; +- } +- } +- } +- } +- +- /** +- * @return string the data type of the current value +- */ +- function kindOf() +- { +- switch ($this->mytype) { +- case 3: +- return 'struct'; +- +- case 2: +- return 'array'; +- +- case 1: +- return 'scalar'; +- +- default: +- return 'undef'; +- } +- } +- +- /** +- * @return string the data in XML format +- */ +- function serializedata($typ, $val) +- { +- $rs = ''; +- global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean; +- if (!array_key_exists($typ, $XML_RPC_Types)) { +- // XXX +- // need some way to report this error +- return; +- } +- switch ($XML_RPC_Types[$typ]) { +- case 3: +- // struct +- $rs .= "\n"; +- reset($val); +- while (list($key2, $val2) = each($val)) { +- $rs .= "${key2}\n"; +- $rs .= $this->serializeval($val2); +- $rs .= "\n"; +- } +- $rs .= ''; +- break; +- +- case 2: +- // array +- $rs .= "\n\n"; +- for ($i = 0; $i < sizeof($val); $i++) { +- $rs .= $this->serializeval($val[$i]); +- } +- $rs .= "\n"; +- break; +- +- case 1: +- switch ($typ) { +- case $XML_RPC_Base64: +- $rs .= "<${typ}>" . base64_encode($val) . ""; +- break; +- case $XML_RPC_Boolean: +- $rs .= "<${typ}>" . ($val ? '1' : '0') . ""; +- break; +- case $XML_RPC_String: +- $rs .= "<${typ}>" . htmlspecialchars($val). ""; +- break; +- default: +- $rs .= "<${typ}>${val}"; +- } +- } +- return $rs; +- } +- +- /** +- * @return string the data in XML format +- */ +- function serialize() +- { +- return $this->serializeval($this); +- } +- +- /** +- * @return string the data in XML format +- */ +- function serializeval($o) +- { +- $rs = ''; +- $ar = $o->me; +- reset($ar); +- list($typ, $val) = each($ar); +- $rs .= ''; +- $rs .= $this->serializedata($typ, $val); +- $rs .= "\n"; +- return $rs; +- } +- +- /** +- * @return mixed the contents of the element requested +- */ +- function structmem($m) +- { +- return $this->me['struct'][$m]; +- } +- +- /** +- * @return void +- */ +- function structreset() +- { +- reset($this->me['struct']); +- } +- +- /** +- * @return the key/value pair of the struct's current element +- */ +- function structeach() +- { +- return each($this->me['struct']); +- } +- +- /** +- * @return mixed the current value +- */ +- function getval() { +- // UNSTABLE +- global $XML_RPC_BOOLEAN, $XML_RPC_Base64; +- +- reset($this->me); +- list($a, $b) = each($this->me); +- +- // contributed by I Sofer, 2001-03-24 +- // add support for nested arrays to scalarval +- // i've created a new method here, so as to +- // preserve back compatibility +- +- if (is_array($b)) { +- foreach ($b as $id => $cont) { +- $b[$id] = $cont->scalarval(); +- } +- } +- +- // add support for structures directly encoding php objects +- if (is_object($b)) { +- $t = get_object_vars($b); +- foreach ($t as $id => $cont) { +- $t[$id] = $cont->scalarval(); +- } +- foreach ($t as $id => $cont) { +- eval('$b->'.$id.' = $cont;'); +- } +- } +- +- // end contrib +- return $b; +- } +- +- /** +- * @return mixed +- */ +- function scalarval() +- { +- global $XML_RPC_Boolean, $XML_RPC_Base64; +- reset($this->me); +- list($a, $b) = each($this->me); +- return $b; +- } +- +- /** +- * @return string +- */ +- function scalartyp() +- { +- global $XML_RPC_I4, $XML_RPC_Int; +- reset($this->me); +- list($a, $b) = each($this->me); +- if ($a == $XML_RPC_I4) { +- $a = $XML_RPC_Int; +- } +- return $a; +- } +- +- /** +- * @return mixed the struct's current element +- */ +- function arraymem($m) +- { +- return $this->me['array'][$m]; +- } +- +- /** +- * @return int the number of elements in the array +- */ +- function arraysize() +- { +- reset($this->me); +- list($a, $b) = each($this->me); +- return sizeof($b); +- } +-} +- +-/** +- * Return an ISO8601 encoded string +- * +- * While timezones ought to be supported, the XML-RPC spec says: +- * +- * "Don't assume a timezone. It should be specified by the server in its +- * documentation what assumptions it makes about timezones." +- * +- * This routine always assumes localtime unless $utc is set to 1, in which +- * case UTC is assumed and an adjustment for locale is made when encoding. +- * +- * @return string the formatted date +- */ +-function XML_RPC_iso8601_encode($timet, $utc = 0) { +- if (!$utc) { +- $t = strftime('%Y%m%dT%H:%M:%S', $timet); +- } else { +- if (function_exists('gmstrftime')) { +- // gmstrftime doesn't exist in some versions +- // of PHP +- $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); +- } else { +- $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); +- } +- } +- return $t; +-} +- +-/** +- * Convert a datetime string into a Unix timestamp +- * +- * While timezones ought to be supported, the XML-RPC spec says: +- * +- * "Don't assume a timezone. It should be specified by the server in its +- * documentation what assumptions it makes about timezones." +- * +- * This routine always assumes localtime unless $utc is set to 1, in which +- * case UTC is assumed and an adjustment for locale is made when encoding. +- * +- * @return int the unix timestamp of the date submitted +- */ +-function XML_RPC_iso8601_decode($idate, $utc = 0) { +- $t = 0; +- if (ereg('([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})', $idate, $regs)) { +- if ($utc) { +- $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +- } else { +- $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +- } +- } +- return $t; +-} +- +-/** +- * Takes a message in PHP XML_RPC object format and translates it into +- * native PHP types +- * +- * @return mixed +- * +- * @author Dan Libby +- */ +-function XML_RPC_decode($XML_RPC_val) +-{ +- $kind = $XML_RPC_val->kindOf(); +- +- if ($kind == 'scalar') { +- return $XML_RPC_val->scalarval(); +- +- } elseif ($kind == 'array') { +- $size = $XML_RPC_val->arraysize(); +- $arr = array(); +- for ($i = 0; $i < $size; $i++) { +- $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i)); +- } +- return $arr; +- +- } elseif ($kind == 'struct') { +- $XML_RPC_val->structreset(); +- $arr = array(); +- while (list($key, $value) = $XML_RPC_val->structeach()) { +- $arr[$key] = XML_RPC_decode($value); +- } +- return $arr; +- } +-} +- +-/** +- * Takes native php types and encodes them into XML_RPC PHP object format +- * +- * Feature creep -- could support more types via optional type argument. +- * +- * @return string +- * +- * @author Dan Libby +- */ +-function XML_RPC_encode($php_val) { +- global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double, $XML_RPC_String, +- $XML_RPC_Array, $XML_RPC_Struct; +- +- $type = gettype($php_val); +- $XML_RPC_val = new XML_RPC_Value; +- +- switch ($type) { +- case 'array': +- if (empty($php_val)) { +- $XML_RPC_val->addArray($php_val); +- break; +- } +- $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); +- if (empty($tmp)) { +- $arr = array(); +- foreach ($php_val as $k => $v) { +- $arr[$k] = XML_RPC_encode($v); +- } +- $XML_RPC_val->addArray($arr); +- break; +- } +- // fall though if it's not an enumerated array +- +- case 'object': +- $arr = array(); +- foreach ($php_val as $k => $v) { +- $arr[$k] = XML_RPC_encode($v); +- } +- $XML_RPC_val->addStruct($arr); +- break; +- +- case 'integer': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Int); +- break; +- +- case 'double': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Double); +- break; +- +- case 'string': +- case 'NULL': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_String); +- break; +- +- case 'boolean': +- // Add support for encoding/decoding of booleans, since they +- // are supported in PHP +- // by +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean); +- break; +- +- case 'unknown type': +- default: +- $XML_RPC_val = false; +- } +- return $XML_RPC_val; +-} +- +-/* +- * Local variables: +- * tab-width: 4 +- * c-basic-offset: 4 +- * c-hanging-comment-ender-p: nil +- * End: +- */ +- +-?> +-XML_RPC-1.2.2/Server.php100666 0 0 36235 10213112551 7713 +- * @author Stig Bakken +- * @author Martin Jansen +- * @copyright 1999-2001 Edd Dumbill +- * @version CVS: $Id: Server.php,v 1.17 2005/03/01 17:09:49 danielc Exp $ +- * @link http://pear.php.net/package/XML_RPC +- */ +- +- +-/** +- * Pull in the XML_RPC class +- */ +-require_once 'XML/RPC.php'; +- +- +-/** +- * listMethods: either a string, or nothing +- * @global array $GLOBALS['XML_RPC_Server_listMethods_sig'] +- */ +-$GLOBALS['XML_RPC_Server_listMethods_sig'] = array( +- array($GLOBALS['XML_RPC_Array'], +- $GLOBALS['XML_RPC_String'] +- ), +- array($GLOBALS['XML_RPC_Array']) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_listMethods_doc'] +- */ +-$GLOBALS['XML_RPC_Server_listMethods_doc'] = 'This method lists all the' +- . ' methods that the XML-RPC server knows how to dispatch'; +- +-/** +- * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig'] +- */ +-$GLOBALS['XML_RPC_Server_methodSignature_sig'] = array( +- array($GLOBALS['XML_RPC_Array'], +- $GLOBALS['XML_RPC_String'] +- ) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc'] +- */ +-$GLOBALS['XML_RPC_Server_methodSignature_doc'] = 'Returns an array of known' +- . ' signatures (an array of arrays) for the method name passed. If' +- . ' no signatures are known, returns a none-array (test for type !=' +- . ' array to detect missing signature)'; +- +-/** +- * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig'] +- */ +-$GLOBALS['XML_RPC_Server_methodHelp_sig'] = array( +- array($GLOBALS['XML_RPC_String'], +- $GLOBALS['XML_RPC_String'] +- ) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc'] +- */ +-$GLOBALS['XML_RPC_Server_methodHelp_doc'] = 'Returns help text if defined' +- . ' for the method passed, otherwise returns an empty string'; +- +-/** +- * @global array $GLOBALS['XML_RPC_Server_dmap'] +- */ +-$GLOBALS['XML_RPC_Server_dmap'] = array( +- 'system.listMethods' => array( +- 'function' => 'XML_RPC_Server_listMethods', +- 'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc'] +- ), +- 'system.methodHelp' => array( +- 'function' => 'XML_RPC_Server_methodHelp', +- 'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc'] +- ), +- 'system.methodSignature' => array( +- 'function' => 'XML_RPC_Server_methodSignature', +- 'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc'] +- ) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_debuginfo'] +- */ +-$GLOBALS['XML_RPC_Server_debuginfo'] = ''; +- +- +-/** +- * Lists all the methods that the XML-RPC server knows how to dispatch +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_listMethods($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $v = new XML_RPC_Value(); +- $dmap = $server->dmap; +- $outAr = array(); +- for (reset($dmap); list($key, $val) = each($dmap); ) { +- $outAr[] = new XML_RPC_Value($key, 'string'); +- } +- $dmap = $XML_RPC_Server_dmap; +- for (reset($dmap); list($key, $val) = each($dmap); ) { +- $outAr[] = new XML_RPC_Value($key, 'string'); +- } +- $v->addArray($outAr); +- return new XML_RPC_Response($v); +-} +- +-/** +- * Returns an array of known signatures (an array of arrays) +- * for the given method +- * +- * If no signatures are known, returns a none-array +- * (test for type != array to detect missing signature) +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_methodSignature($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $methName = $m->getParam(0); +- $methName = $methName->scalarval(); +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $server->dmap; +- $sysCall = 0; +- } +- // print "\n"; +- if (isset($dmap[$methName])) { +- if ($dmap[$methName]['signature']) { +- $sigs = array(); +- $thesigs = $dmap[$methName]['signature']; +- for ($i = 0; $i < sizeof($thesigs); $i++) { +- $cursig = array(); +- $inSig = $thesigs[$i]; +- for ($j = 0; $j < sizeof($inSig); $j++) { +- $cursig[] = new XML_RPC_Value($inSig[$j], 'string'); +- } +- $sigs[] = new XML_RPC_Value($cursig, 'array'); +- } +- $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array')); +- } else { +- $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string')); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], +- $XML_RPC_str['introspect_unknown']); +- } +- return $r; +-} +- +-/** +- * Returns help text if defined for the method passed, otherwise returns +- * an empty string +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_methodHelp($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $methName = $m->getParam(0); +- $methName = $methName->scalarval(); +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $server->dmap; +- $sysCall = 0; +- } +- // print "\n"; +- if (isset($dmap[$methName])) { +- if ($dmap[$methName]['docstring']) { +- $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']), +- 'string'); +- } else { +- $r = new XML_RPC_Response(new XML_RPC_Value('', 'string')); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], +- $XML_RPC_str['introspect_unknown']); +- } +- return $r; +-} +- +-/** +- * @return void +- */ +-function XML_RPC_Server_debugmsg($m) +-{ +- global $XML_RPC_Server_debuginfo; +- $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n"; +-} +- +- +-/** +- * +- * +- * @category Web Services +- * @package XML_RPC +- * @author Edd Dumbill +- * @author Stig Bakken +- * @author Martin Jansen +- * @copyright 1999-2001 Edd Dumbill +- * @version Release: 1.2.2 +- * @link http://pear.php.net/package/XML_RPC +- */ +-class XML_RPC_Server +-{ +- var $dmap = array(); +- var $encoding = ''; +- var $debug = 0; +- +- /** +- * @return void +- */ +- function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) +- { +- global $HTTP_RAW_POST_DATA; +- +- if ($debug) { +- $this->debug = 1; +- } else { +- $this->debug = 0; +- } +- +- // dispMap is a despatch array of methods +- // mapped to function names and signatures +- // if a method +- // doesn't appear in the map then an unknown +- // method error is generated +- $this->dmap = $dispMap; +- if ($serviceNow) { +- $this->service(); +- } +- } +- +- /** +- * @return string the debug information if debug debug mode is on +- */ +- function serializeDebug() +- { +- global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA; +- +- if ($this->debug) { +- XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n" +- . $HTTP_RAW_POST_DATA +- . "\n" . '^^^ END POST DATA ^^^'); +- } +- +- if ($XML_RPC_Server_debuginfo != '') { +- return "\n"; +- } else { +- return ''; +- } +- } +- +- /** +- * Print out the result +- * +- * The encoding and content-type are determined by +- * XML_RPC_Message::getEncoding() +- * +- * @return void +- * +- * @see XML_RPC_Message::getEncoding() +- */ +- function service() +- { +- $r = $this->parseRequest(); +- $payload = 'encoding . '"?>' . "\n" +- . $this->serializeDebug() +- . $r->serialize(); +- header('Content-Length: ' . strlen($payload)); +- header('Content-Type: text/xml; charset=' . $this->encoding); +- print $payload; +- } +- +- /** +- * @return array +- */ +- function verifySignature($in, $sig) +- { +- for ($i = 0; $i < sizeof($sig); $i++) { +- // check each possible signature in turn +- $cursig = $sig[$i]; +- if (sizeof($cursig) == $in->getNumParams() + 1) { +- $itsOK = 1; +- for ($n = 0; $n < $in->getNumParams(); $n++) { +- $p = $in->getParam($n); +- // print "\n"; +- if ($p->kindOf() == 'scalar') { +- $pt = $p->scalartyp(); +- } else { +- $pt = $p->kindOf(); +- } +- // $n+1 as first type of sig is return type +- if ($pt != $cursig[$n+1]) { +- $itsOK = 0; +- $pno = $n+1; +- $wanted = $cursig[$n+1]; +- $got = $pt; +- break; +- } +- } +- if ($itsOK) { +- return array(1); +- } +- } +- } +- return array(0, "Wanted ${wanted}, got ${got} at param ${pno})"); +- } +- +- /** +- * @return object a new XML_RPC_Response object +- */ +- function parseRequest($data = '') +- { +- global $XML_RPC_xh, $HTTP_RAW_POST_DATA, +- $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml, +- $XML_RPC_defencoding, $XML_RPC_Server_dmap; +- +- if ($data == '') { +- $data = $HTTP_RAW_POST_DATA; +- } +- +- $this->encoding = XML_RPC_Message::getEncoding($data); +- $parser = xml_parser_create($this->encoding); +- +- $XML_RPC_xh[$parser] = array(); +- $XML_RPC_xh[$parser]['st'] = ''; +- $XML_RPC_xh[$parser]['cm'] = 0; +- $XML_RPC_xh[$parser]['isf'] = 0; +- $XML_RPC_xh[$parser]['params'] = array(); +- $XML_RPC_xh[$parser]['method'] = ''; +- +- $plist = ''; +- +- // decompose incoming XML into request structure +- +- xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); +- xml_set_element_handler($parser, 'XML_RPC_se', 'XML_RPC_ee'); +- xml_set_character_data_handler($parser, 'XML_RPC_cd'); +- if (!xml_parse($parser, $data, 1)) { +- // return XML error as a faultCode +- $r = new XML_RPC_Response(0, +- $XML_RPC_errxml+xml_get_error_code($parser), +- sprintf('XML error: %s at line %d', +- xml_error_string(xml_get_error_code($parser)), +- xml_get_current_line_number($parser))); +- xml_parser_free($parser); +- } else { +- xml_parser_free($parser); +- $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']); +- // now add parameters in +- for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) { +- // print '\n"; +- $plist .= "$i - " . $XML_RPC_xh[$parser]['params'][$i] . " \n"; +- eval('$m->addParam(' . $XML_RPC_xh[$parser]['params'][$i] . ');'); +- } +- XML_RPC_Server_debugmsg($plist); +- +- // now to deal with the method +- $methName = $XML_RPC_xh[$parser]['method']; +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $this->dmap; +- $sysCall = 0; +- } +- +- if (isset($dmap[$methName]['function']) +- && is_string($dmap[$methName]['function']) +- && strpos($dmap[$methName]['function'], '::') !== false) +- { +- $dmap[$methName]['function'] = +- explode('::', $dmap[$methName]['function']); +- } +- +- if (isset($dmap[$methName]['function']) +- && is_callable($dmap[$methName]['function'])) +- { +- // dispatch if exists +- if (isset($dmap[$methName]['signature'])) { +- $sr = $this->verifySignature($m, +- $dmap[$methName]['signature'] ); +- } +- if ( (!isset($dmap[$methName]['signature'])) || $sr[0]) { +- // if no signature or correct signature +- if ($sysCall) { +- $r = call_user_func($dmap[$methName]['function'], $this, $m); +- } else { +- $r = call_user_func($dmap[$methName]['function'], $m); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], +- $XML_RPC_str['incorrect_params'] +- . ': ' . $sr[1]); +- } +- } else { +- // else prepare error response +- $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'], +- $XML_RPC_str['unknown_method']); +- } +- } +- return $r; +- } +- +- /** +- * Echos back the input packet as a string value +- * +- * @return void +- * +- * Useful for debugging. +- */ +- function echoInput() { +- global $HTTP_RAW_POST_DATA; +- +- $r = new XML_RPC_Response(0); +- $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); +- print $r->serialize(); +- } +-} +- +-/* +- * Local variables: +- * tab-width: 4 +- * c-basic-offset: 4 +- * c-hanging-comment-ender-p: nil +- * End: +- */ +- +-?> +-package.xml100666 0 0 15556 10213112551 6252 +- +- +- XML_RPC +- PHP implementation of the XML-RPC protocol +- A PEAR-ified version of Useful Inc's XML-RPC for PHP. +- +-It has support for HTTP/HTTPS transport, proxies and authentication. +- +- +- +- ssb +- Stig Bakken +- stig@php.net +- lead +- +- +- danielc +- Daniel Convissor +- danielc@php.net +- lead +- +- +- +- 1.2.2 +- 2005-03-07 +- PHP License +- stable +- * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- 1.2.1 +- 2005-03-01 +- stable +- * Add isset() check before examining the dispatch map. Bug 3658. +- +- +- +- 1.2.0 +- 2005-02-27 +- stable +- * Provide the "stable" release. +-* Add package2.xml for compatibility with PEAR 1.4.0. +-* For changes since 1.1.0, see the changelogs for the various RC releases. +- +- +- +- 1.2.0RC7 +- 2005-02-22 +- beta +- * Add the setSendEncoding() method and $send_encoding +- property to XML_RPC_Message. Request 3537. +-* Allow class methods to be mapped using either syntax: +- 'function' => 'hello::sayHello', +- or +- 'function' => array('hello', 'sayhello'), +- Bug 3363. +-* Use 8192 instead of 32768 for bytes in fread() +- in parseResponseFile(). Bug 3340. +- +- +- +- 1.2.0RC6 +- 2005-01-25 +- beta +- * Don't put the protocol in the Host field of the POST data. (danielc) +- +- +- +- 1.2.0RC5 +- 2005-01-24 +- beta +- * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. +- +- +- +- 1.2.0RC4 +- 2005-01-24 +- beta +- * When a connection attempt fails, have the method return 0. (danielc) +-* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) +-* Add tests for setting the client properties. (danielc) +-* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) +-* Bundle the tests with the package. (danielc) +- +- +- +- 1.2.0RC3 +- 2005-01-19 +- beta +- * ssl uses port 443, not 445. +- +- +- +- 1.2.0RC2 +- 2005-01-11 +- beta +- * Handle ssl:// in the $server string. (danielc) +-* Also default to port 445 for ssl:// requests as well. (danielc) +-* Enhance debugging in the server. (danielc) +- +- +- +- 1.2.0RC1 +- 2004-12-30 +- beta +- * Make things work with SSL. Bug 2489. (nkukard lbsd net) +-* Allow array function callbacks (Matt Kane) +-* Some minor speed-ups (Matt Kane) +-* Add Dump.php to the package (Christian Weiske) +-* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) +-* Silence fsockopen() errors. Bug 1714. (danielc) +-* Encode empty arrays as an array. Bug 1493. (danielc) +-* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) +-* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) +-* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) +-* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) +-* Allow raiseError() to be called statically. (danielc) +-* Stop double escaping of character entities. Bug 987. (danielc) +- NOTICE: the following have been removed: +- * XML_RPC_dh() +- * $GLOBALS['XML_RPC_entities'] +- * XML_RPC_entity_decode() +- * XML_RPC_lookup_entity() +-* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) +- +- +- +- 1.1.0 +- 2004-03-15 +- stable +- * Added support for sequential arrays to XML_RPC_encode() (mroch) +-* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) +-* Remove "require_once 'PEAR.php'", include only when needed to raise an error +-* Replace echo and error_log() with raiseError() (mroch) +-* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) +-* be tolerant of junk after methodResponse (Luca Mariano, mroch) +-* Silent notice even in the error log (pierre) +-* fix include of shared xml extension on win32 (pierre) +- +- +- +- 1.0.4 +- 2002-10-02 +- stable +- * added HTTP proxy authorization support (thanks to Arnaud Limbourg) +- +- +- +- 1.0.3 +- 2002-05-19 +- stable +- * fix bug when parsing responses with boolean types +- +- +- +- 1.0.2 +- 2002-04-16 +- stable +- * E_ALL fixes +-* fix HTTP response header parsing +- +- +- +- 1.0.1 +- 2001-09-25 +- stable +- This is a PEAR-ified version of Useful Inc's 1.0.1 release. +-Includes an urgent security fix identified by Dan Libby <dan@libby.com>. +- +- +- +- +- +\ Kein Zeilenumbruch am Dateiende. +diff -Naur php-4.3.11/pear/packages/XML_RPC-1.3.1.tar hardening-patch-4.3.11-0.3.2/pear/packages/XML_RPC-1.3.1.tar +--- php-4.3.11/pear/packages/XML_RPC-1.3.1.tar 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/pear/packages/XML_RPC-1.3.1.tar 2005-07-09 08:53:02.503358096 +0200 +@@ -0,0 +1,3733 @@ ++package2.xml100644 1750 144 32557 10260516576 6517 ++ ++ XML_RPC ++ pear.php.net ++ PHP implementation of the XML-RPC protocol ++ A PEAR-ified version of Useful Inc's XML-RPC for PHP. ++ ++It has support for HTTP/HTTPS transport, proxies and authentication. ++ ++ Stig Bakken ++ ssb ++ stig@php.net ++ no ++ ++ ++ Daniel Convissor ++ danielc ++ danielc@php.net ++ yes ++ ++ 2005-06-29 ++ ++ ++ 1.3.1 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ PHP License ++ * Security fix. Update highly recommended! ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ PEAR ++ pear.php.net ++ 1.4.0a1 ++ 1.4.0a12 ++ ++ ++ ++ ++ 4.2.0 ++ 6.0.0 ++ ++ ++ 1.4.0a1 ++ ++ ++ ++ ++ ++ ++ ++ 1.3.0RC3 ++ 1.3.0 ++ ++ ++ beta ++ stable ++ ++ 2005-05-10 ++ PHP License ++ * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. ++* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. ++* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. ++* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. ++* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). ++* Use <br /> instead of <br> in XML_RPC_Value::dump(). ++ ++ ++ ++ 1.3.0RC2 ++ 1.3.0 ++ ++ ++ beta ++ beta ++ ++ 2005-05-05 ++ PHP License ++ * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. ++* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. ++* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. ++* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. ++ ++ ++ ++ 1.3.0RC1 ++ 1.3.0 ++ ++ ++ beta ++ beta ++ ++ 2005-04-07 ++ PHP License ++ * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. ++* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. ++* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. ++* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. ++* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. ++* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. ++ ++ ++ ++ 1.2.2 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-03-07 ++ PHP License ++ * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. ++ ++ ++ ++ 1.2.1 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-03-01 ++ PHP License ++ * Add isset() check before examining the dispatch map. Bug 3658. ++ ++ ++ ++ 1.2.0 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-02-27 ++ PHP License ++ * Provide the "stable" release. ++* Add package2.xml for compatibility with PEAR 1.4.0. ++* For changes since 1.1.0, see the changelogs for the various RC releases. ++ ++ ++ ++ 1.2.0RC7 ++ 1.2.0RC7 ++ ++ ++ beta ++ beta ++ ++ 2005-02-22 ++ PHP License ++ * Add the setSendEncoding() method and $send_encoding ++ property to XML_RPC_Message. Request 3537. ++* Allow class methods to be mapped using either syntax: ++ 'function' => 'hello::sayHello', ++ or ++ 'function' => array('hello', 'sayhello'), ++ Bug 3363. ++* Use 8192 instead of 32768 for bytes in fread() ++ in parseResponseFile(). Bug 3340. ++ ++ ++ ++ 1.2.0RC6 ++ 1.2.0RC6 ++ ++ ++ beta ++ beta ++ ++ 2005-01-25 ++ PHP License ++ * Don't put the protocol in the Host field of the POST data. (danielc) ++ ++ ++ ++ 1.2.0RC5 ++ 1.2.0RC5 ++ ++ ++ beta ++ beta ++ ++ 2005-01-24 ++ PHP License ++ * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. ++ ++ ++ ++ 1.2.0RC4 ++ 1.2.0RC4 ++ ++ ++ beta ++ beta ++ ++ 2005-01-24 ++ PHP License ++ * When a connection attempt fails, have the method return 0. (danielc) ++* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) ++* Add tests for setting the client properties. (danielc) ++* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) ++* Bundle the tests with the package. (danielc) ++ ++ ++ ++ 1.2.0RC3 ++ 1.2.0RC3 ++ ++ ++ beta ++ beta ++ ++ 2005-01-19 ++ PHP License ++ * ssl uses port 443, not 445. ++ ++ ++ ++ 1.2.0RC2 ++ 1.2.0RC2 ++ ++ ++ beta ++ beta ++ ++ 2005-01-11 ++ PHP License ++ * Handle ssl:// in the $server string. (danielc) ++* Also default to port 445 for ssl:// requests as well. (danielc) ++* Enhance debugging in the server. (danielc) ++ ++ ++ ++ 1.2.0RC1 ++ 1.2.0RC1 ++ ++ ++ beta ++ beta ++ ++ 2004-12-30 ++ PHP License ++ * Make things work with SSL. Bug 2489. (nkukard lbsd net) ++* Allow array function callbacks (Matt Kane) ++* Some minor speed-ups (Matt Kane) ++* Add Dump.php to the package (Christian Weiske) ++* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) ++* Silence fsockopen() errors. Bug 1714. (danielc) ++* Encode empty arrays as an array. Bug 1493. (danielc) ++* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) ++* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) ++* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) ++* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) ++* Allow raiseError() to be called statically. (danielc) ++* Stop double escaping of character entities. Bug 987. (danielc) ++ NOTICE: the following have been removed: ++ * XML_RPC_dh() ++ * $GLOBALS['XML_RPC_entities'] ++ * XML_RPC_entity_decode() ++ * XML_RPC_lookup_entity() ++* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) ++ ++ ++ ++ 1.1.0 ++ 1.1.0 ++ ++ ++ stable ++ stable ++ ++ 2004-03-15 ++ PHP License ++ * Added support for sequential arrays to XML_RPC_encode() (mroch) ++* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) ++* Remove "require_once 'PEAR.php'", include only when needed to raise an error ++* Replace echo and error_log() with raiseError() (mroch) ++* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) ++* be tolerant of junk after methodResponse (Luca Mariano, mroch) ++* Silent notice even in the error log (pierre) ++* fix include of shared xml extension on win32 (pierre) ++ ++ ++ ++ 1.0.4 ++ 1.0.4 ++ ++ ++ stable ++ stable ++ ++ 2002-10-02 ++ PHP License ++ * added HTTP proxy authorization support (thanks to Arnaud Limbourg) ++ ++ ++ ++ 1.0.3 ++ 1.0.3 ++ ++ ++ stable ++ stable ++ ++ 2002-05-19 ++ PHP License ++ * fix bug when parsing responses with boolean types ++ ++ ++ ++ 1.0.2 ++ 1.0.2 ++ ++ ++ stable ++ stable ++ ++ 2002-04-16 ++ PHP License ++ * E_ALL fixes ++* fix HTTP response header parsing ++ ++ ++ ++ 1.0.1 ++ 1.0.1 ++ ++ ++ stable ++ stable ++ ++ 2001-09-25 ++ PHP License ++ This is a PEAR-ified version of Useful Inc's 1.0.1 release. ++Includes an urgent security fix identified by Dan Libby <dan@libby.com>. ++ ++ ++ ++XML_RPC-1.3.1/tests/protoport.php100644 1750 144 25543 10260516576 12042 ++ * @copyright 2005 The PHP Group ++ * @license http://www.php.net/license/3_0.txt PHP License ++ * @version CVS: $Id: protoport.php,v 1.4 2005/01/24 17:48:47 danielc Exp $ ++ * @link http://pear.php.net/package/XML_RPC ++ * @since File available since Release 1.2 ++ */ ++ ++/* ++ * If the package version number is found in the left hand ++ * portion of the if() expression below, that means this file has ++ * come from the PEAR installer. Therefore, let's test the ++ * installed version of XML_RPC which should be in the include path. ++ * ++ * If the version has not been substituted in the if() expression, ++ * this file has likely come from a CVS checkout or a .tar file. ++ * Therefore, we'll assume the tests should use the version of ++ * XML_RPC that has come from there as well. ++ */ ++if ('1.3.1' != '@'.'package_version'.'@') { ++ /** ++ * Get the needed class from the PEAR installation ++ */ ++ require_once 'XML/RPC.php'; ++} else { ++ /** ++ * Get the needed class from the parent directory ++ */ ++ require_once '../RPC.php'; ++} ++ ++/** ++ * Compare the test result to the expected result ++ * ++ * If the test fails, echo out the results. ++ * ++ * @param array $expect the array of object properties you expect ++ * from the test ++ * @param object $actual the object results from the test ++ * @param string $test_name the name of the test ++ * ++ * @return void ++ */ ++function compare($expect, $actual, $test_name) { ++ $actual = get_object_vars($actual); ++ if (count(array_diff($actual, $expect))) { ++ echo "$test_name failed.\nExpect: "; ++ print_r($expect); ++ echo "Actual: "; ++ print_r($actual); ++ echo "\n"; ++ } ++} ++ ++if (php_sapi_name() != 'cli') { ++ echo "
\n";
++}
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver');
++compare($x, $c, 'defaults');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver');
++compare($x, $c, 'defaults with http');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver');
++compare($x, $c, 'defaults with https');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver');
++compare($x, $c, 'defaults with ssl');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 65);
++compare($x, $c, 'port 65');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 65);
++compare($x, $c, 'port 65 with http');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 65);
++compare($x, $c, 'port 65 with https');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65);
++compare($x, $c, 'port 65 with ssl');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 0,
++                        'theproxy');
++compare($x, $c, 'defaults proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 0,
++                        'http://theproxy');
++compare($x, $c, 'defaults with http proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 0,
++                        'https://theproxy');
++compare($x, $c, 'defaults with https proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 0,
++                        'ssl://theproxy');
++compare($x, $c, 'defaults with ssl proxy');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 65,
++                        'theproxy', 6565);
++compare($x, $c, 'port 65 proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 65,
++                        'http://theproxy', 6565);
++compare($x, $c, 'port 65 with http proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 65,
++                        'https://theproxy', 6565);
++compare($x, $c, 'port 65 with https proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65,
++                        'ssl://theproxy', 6565);
++compare($x, $c, 'port 65 with ssl proxy 6565');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 443,
++                        'theproxy', 443);
++compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 0,
++                        'ssl://theproxy', 6565);
++compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
++XML_RPC-1.3.1/tests/test_Dump.php100644   1750    144        3042 10260516576  11704 new XML_RPC_Value('das ist der Titel', 'string'),
++    'startDate'=>new XML_RPC_Value(mktime(0,0,0,13,11,2004), 'dateTime.iso8601'),
++    'endDate'  =>new XML_RPC_Value(mktime(0,0,0,15,11,2004), 'dateTime.iso8601'),
++    'error'    =>'string',
++    'arkey'    => new XML_RPC_Value( array(
++        new XML_RPC_Value('simple string'),
++        new XML_RPC_Value(12345, 'int')
++        ), 'array')
++    )
++    ,'struct');
++
++XML_RPC_Dump($val);
++
++echo '==============' . "\r\n";
++$val2 = new XML_RPC_Value(44353, 'int');
++XML_RPC_Dump($val2);
++
++echo '==============' . "\r\n";
++$val3 = new XML_RPC_Value('this should be a string', 'string');
++XML_RPC_Dump($val3);
++
++echo '==============' . "\r\n";
++$val4 = new XML_RPC_Value(true, 'boolean');
++XML_RPC_Dump($val4);
++XML_RPC-1.3.1/Dump.php100644   1750    144       12074 10260516576   7530 
++ * @version    CVS: $Id: Dump.php,v 1.7 2005/01/24 03:47:55 danielc Exp $
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++
++
++/**
++ * Pull in the XML_RPC class
++ */
++require_once 'XML/RPC.php';
++
++
++/**
++ * Generates the dump of the XML_RPC_Value and echoes it
++ *
++ * @param object $value  the XML_RPC_Value object to dump
++ *
++ * @return void
++ */
++function XML_RPC_Dump($value)
++{
++    $dumper = new XML_RPC_Dump();
++    echo $dumper->generateDump($value);
++}
++
++
++/**
++ * Class which generates a dump of a XML_RPC_Value object
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Christian Weiske 
++ * @version    Release: 1.3.1
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Dump
++{
++    /**
++     * The indentation array cache
++     * @var array
++     */
++    var $arIndent      = array();
++
++    /**
++     * The spaces used for indenting the XML
++     * @var string
++     */
++    var $strBaseIndent = '    ';
++
++    /**
++     * Returns the dump in XML format without printing it out
++     *
++     * @param object $value   the XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  the dump
++     */
++    function generateDump($value, $nLevel = 0)
++    {
++        if (!is_object($value) && get_class($value) != 'xml_rpc_value') {
++            require_once 'PEAR.php';
++            PEAR::raiseError('Tried to dump non-XML_RPC_Value variable' . "\r\n",
++                             0, PEAR_ERROR_PRINT);
++            if (is_object($value)) {
++                $strType = get_class($value);
++            } else {
++                $strType = gettype($value);
++            }
++            return $this->getIndent($nLevel) . 'NOT A XML_RPC_Value: '
++                   . $strType . "\r\n";
++        }
++
++        switch ($value->kindOf()) {
++        case 'struct':
++            $ret = $this->genStruct($value, $nLevel);
++            break;
++        case 'array':
++            $ret = $this->genArray($value, $nLevel);
++            break;
++        case 'scalar':
++            $ret = $this->genScalar($value->scalarval(), $nLevel);
++            break;
++        default:
++            require_once 'PEAR.php';
++            PEAR::raiseError('Illegal type "' . $value->kindOf()
++                             . '" in XML_RPC_Value' . "\r\n", 0,
++                             PEAR_ERROR_PRINT);
++        }
++
++        return $ret;
++    }
++
++    /**
++     * Returns the scalar value dump
++     *
++     * @param object $value   the scalar XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genScalar($value, $nLevel)
++    {
++        if (gettype($value) == 'object') {
++            $strClass = ' ' . get_class($value);
++        } else {
++            $strClass = '';
++        }
++        return $this->getIndent($nLevel) . gettype($value) . $strClass
++               . ' ' . $value . "\r\n";
++    }
++
++    /**
++     * Returns the dump of a struct
++     *
++     * @param object $value   the struct XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genStruct($value, $nLevel)
++    {
++        $value->structreset();
++        $strOutput = $this->getIndent($nLevel) . 'struct' . "\r\n";
++        while (list($key, $keyval) = $value->structeach()) {
++            $strOutput .= $this->getIndent($nLevel + 1) . $key . "\r\n";
++            $strOutput .= $this->generateDump($keyval, $nLevel + 2);
++        }
++        return $strOutput;
++    }
++
++    /**
++     * Returns the dump of an array
++     *
++     * @param object $value   the array XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genArray($value, $nLevel)
++    {
++        $nSize     = $value->arraysize();
++        $strOutput = $this->getIndent($nLevel) . 'array' . "\r\n";
++        for($nA = 0; $nA < $nSize; $nA++) {
++            $strOutput .= $this->getIndent($nLevel + 1) . $nA . "\r\n";
++            $strOutput .= $this->generateDump($value->arraymem($nA),
++                                              $nLevel + 2);
++        }
++        return $strOutput;
++    }
++
++    /**
++     * Returns the indent for a specific level and caches it for faster use
++     *
++     * @param int $nLevel  the level
++     *
++     * @return string  the indented string
++     */
++    function getIndent($nLevel)
++    {
++        if (!isset($this->arIndent[$nLevel])) {
++            $this->arIndent[$nLevel] = str_repeat($this->strBaseIndent, $nLevel);
++        }
++        return $this->arIndent[$nLevel];
++    }
++}
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * c-hanging-comment-ender-p: nil
++ * End:
++ */
++
++?>
++XML_RPC-1.3.1/RPC.php100644   1750    144      150065 10260516576   7272 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    CVS: $Id: RPC.php,v 1.74 2005/05/09 20:51:54 danielc Exp $
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++
++
++if (!function_exists('xml_parser_create')) {
++    PEAR::loadExtension('xml');
++}
++
++/**#@+
++ * Error constants
++ */
++/**
++ * Parameter values don't match parameter types
++ */
++define('XML_RPC_ERROR_INVALID_TYPE', 101);
++/**
++ * Parameter declared to be numeric but the values are not
++ */
++define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102);
++/**
++ * Communication error
++ */
++define('XML_RPC_ERROR_CONNECTION_FAILED', 103);
++/**
++ * The array or struct has already been started
++ */
++define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
++/**
++ * Incorrect parameters submitted
++ */
++define('XML_RPC_ERROR_INCORRECT_PARAMS', 105);
++/**
++ * Programming error by developer
++ */
++define('XML_RPC_ERROR_PROGRAMMING', 106);
++/**#@-*/
++
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_I4']
++ */
++$GLOBALS['XML_RPC_I4'] = 'i4';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Int']
++ */
++$GLOBALS['XML_RPC_Int'] = 'int';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Boolean']
++ */
++$GLOBALS['XML_RPC_Boolean'] = 'boolean';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Double']
++ */
++$GLOBALS['XML_RPC_Double'] = 'double';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_String']
++ */
++$GLOBALS['XML_RPC_String'] = 'string';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_DateTime']
++ */
++$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Base64']
++ */
++$GLOBALS['XML_RPC_Base64'] = 'base64';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Array']
++ */
++$GLOBALS['XML_RPC_Array'] = 'array';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Struct']
++ */
++$GLOBALS['XML_RPC_Struct'] = 'struct';
++
++
++/**
++ * Data type meta-types
++ * @global array $GLOBALS['XML_RPC_Types']
++ */
++$GLOBALS['XML_RPC_Types'] = array(
++    $GLOBALS['XML_RPC_I4']       => 1,
++    $GLOBALS['XML_RPC_Int']      => 1,
++    $GLOBALS['XML_RPC_Boolean']  => 1,
++    $GLOBALS['XML_RPC_String']   => 1,
++    $GLOBALS['XML_RPC_Double']   => 1,
++    $GLOBALS['XML_RPC_DateTime'] => 1,
++    $GLOBALS['XML_RPC_Base64']   => 1,
++    $GLOBALS['XML_RPC_Array']    => 2,
++    $GLOBALS['XML_RPC_Struct']   => 3,
++);
++
++
++/**
++ * Error message numbers
++ * @global array $GLOBALS['XML_RPC_err']
++ */
++$GLOBALS['XML_RPC_err'] = array(
++    'unknown_method'      => 1,
++    'invalid_return'      => 2,
++    'incorrect_params'    => 3,
++    'introspect_unknown'  => 4,
++    'http_error'          => 5,
++    'not_response_object' => 6,
++);
++
++/**
++ * Error message strings
++ * @global array $GLOBALS['XML_RPC_str']
++ */
++$GLOBALS['XML_RPC_str'] = array(
++    'unknown_method'      => 'Unknown method',
++    'invalid_return'      => 'Invalid return payload: enable debugging to examine incoming payload',
++    'incorrect_params'    => 'Incorrect parameters passed to method',
++    'introspect_unknown'  => 'Can\'t introspect: method unknown',
++    'http_error'          => 'Didn\'t receive 200 OK from remote server.',
++    'not_response_object' => 'The requested method didn\'t return an XML_RPC_Response object.',
++);
++
++
++/**
++ * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
++ * @global string $GLOBALS['XML_RPC_defencoding']
++ */
++$GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
++
++/**
++ * User error codes start at 800
++ * @global int $GLOBALS['XML_RPC_erruser']
++ */
++$GLOBALS['XML_RPC_erruser'] = 800;
++
++/**
++ * XML parse error codes start at 100
++ * @global int $GLOBALS['XML_RPC_errxml']
++ */
++$GLOBALS['XML_RPC_errxml'] = 100;
++
++
++/**
++ * Compose backslashes for escaping regexp
++ * @global string $GLOBALS['XML_RPC_backslash']
++ */
++$GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
++
++
++/**
++ * Stores state during parsing
++ *
++ * quick explanation of components:
++ *   + st     = builds up a string for evaluation
++ *   + ac     = accumulates values
++ *   + qt     = decides if quotes are needed for evaluation
++ *   + cm     = denotes struct or array (comma needed)
++ *   + isf    = indicates a fault
++ *   + lv     = indicates "looking for a value": implements the logic
++ *               to allow values with no types to be strings
++ *   + params = stores parameters in method calls
++ *   + method = stores method name
++ *
++ * @global array $GLOBALS['XML_RPC_xh']
++ */
++$GLOBALS['XML_RPC_xh'] = array();
++
++
++/**
++ * Start element handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_se($parser_resource, $name, $attrs)
++{
++    global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String;
++    $parser = (int) $parser_resource;
++
++    switch ($name) {
++    case 'STRUCT':
++    case 'ARRAY':
++        $XML_RPC_xh[$parser]['st'] .= 'array(';
++        $XML_RPC_xh[$parser]['cm']++;
++        // this last line turns quoting off
++        // this means if we get an empty array we'll
++        // simply get a bit of whitespace in the eval
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        break;
++
++    case 'NAME':
++        $XML_RPC_xh[$parser]['st'] .= '"';
++        $XML_RPC_xh[$parser]['ac'] = '';
++        break;
++
++    case 'FAULT':
++        $XML_RPC_xh[$parser]['isf'] = 1;
++        break;
++
++    case 'PARAM':
++        $XML_RPC_xh[$parser]['st'] = '';
++        break;
++
++    case 'VALUE':
++        $XML_RPC_xh[$parser]['st'] .= 'new XML_RPC_Value(';
++        $XML_RPC_xh[$parser]['lv'] = 1;
++        $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        // look for a value: if this is still 1 by the
++        // time we reach the first data segment then the type is string
++        // by implication and we need to add in a quote
++        break;
++
++    case 'I4':
++    case 'INT':
++    case 'STRING':
++    case 'BOOLEAN':
++    case 'DOUBLE':
++    case 'DATETIME.ISO8601':
++    case 'BASE64':
++        $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
++
++        if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
++            $XML_RPC_xh[$parser]['qt'] = 1;
++
++            if ($name == 'DATETIME.ISO8601') {
++                $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
++            }
++
++        } elseif ($name == 'BASE64') {
++            $XML_RPC_xh[$parser]['qt'] = 2;
++        } else {
++            // No quoting is required here -- but
++            // at the end of the element we must check
++            // for data format errors.
++            $XML_RPC_xh[$parser]['qt'] = 0;
++        }
++        break;
++
++    case 'MEMBER':
++        $XML_RPC_xh[$parser]['ac'] = '';
++    }
++
++    if ($name != 'VALUE') {
++        $XML_RPC_xh[$parser]['lv'] = 0;
++    }
++}
++
++/**
++ * End element handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_ee($parser_resource, $name)
++{
++    global $XML_RPC_xh, $XML_RPC_Types, $XML_RPC_String;
++    $parser = (int) $parser_resource;
++
++    switch ($name) {
++    case 'STRUCT':
++    case 'ARRAY':
++        if ($XML_RPC_xh[$parser]['cm']
++            && substr($XML_RPC_xh[$parser]['st'], -1) == ',')
++        {
++            $XML_RPC_xh[$parser]['st'] = substr($XML_RPC_xh[$parser]['st'], 0, -1);
++        }
++
++        $XML_RPC_xh[$parser]['st'] .= ')';
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++        $XML_RPC_xh[$parser]['cm']--;
++        break;
++
++    case 'NAME':
++        $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'] . '" => ';
++        break;
++
++    case 'BOOLEAN':
++        // special case here: we translate boolean 1 or 0 into PHP
++        // constants true or false
++        if ($XML_RPC_xh[$parser]['ac'] == '1') {
++            $XML_RPC_xh[$parser]['ac'] = 'true';
++        } else {
++            $XML_RPC_xh[$parser]['ac'] = 'false';
++        }
++
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++        // Drop through intentionally.
++
++    case 'I4':
++    case 'INT':
++    case 'STRING':
++    case 'DOUBLE':
++    case 'DATETIME.ISO8601':
++    case 'BASE64':
++        if ($XML_RPC_xh[$parser]['qt'] == 1) {
++            // we use double quotes rather than single so backslashification works OK
++            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
++        } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
++            $XML_RPC_xh[$parser]['st'] .= 'base64_decode("'
++                                        . $XML_RPC_xh[$parser]['ac'] . '")';
++        } elseif ($name == 'BOOLEAN') {
++            $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
++        } else {
++            // we have an I4, INT or a DOUBLE
++            // we must check that only 0123456789-. are characters here
++            if (!ereg("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
++                XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
++                                         XML_RPC_ERROR_NON_NUMERIC_FOUND);
++                $XML_RPC_xh[$parser]['st'] .= 'XML_RPC_ERROR_NON_NUMERIC_FOUND';
++            } else {
++                // it's ok, add it on
++                $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
++            }
++        }
++
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
++        break;
++
++    case 'VALUE':
++        // deal with a string value
++        if (strlen($XML_RPC_xh[$parser]['ac']) > 0 &&
++            $XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
++
++            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
++        }
++
++        // This if () detects if no scalar was inside 
++        // and pads an empty "".
++        if ($XML_RPC_xh[$parser]['st'][strlen($XML_RPC_xh[$parser]['st'])-1] == '(') {
++            $XML_RPC_xh[$parser]['st'] .= '""';
++        }
++        $XML_RPC_xh[$parser]['st'] .= ", '" . $XML_RPC_xh[$parser]['vt'] . "')";
++        if ($XML_RPC_xh[$parser]['cm']) {
++            $XML_RPC_xh[$parser]['st'] .= ',';
++        }
++        break;
++
++    case 'MEMBER':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        break;
++
++    case 'DATA':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        break;
++
++    case 'PARAM':
++        $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['st'];
++        break;
++
++    case 'METHODNAME':
++    case 'RPCMETHODNAME':
++        $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", '',
++                                                      $XML_RPC_xh[$parser]['ac']);
++        break;
++    }
++
++    // if it's a valid type name, set the type
++    if (isset($XML_RPC_Types[strtolower($name)])) {
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++    }
++}
++
++/**
++ * Character data handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_cd($parser_resource, $data)
++{
++    global $XML_RPC_xh, $XML_RPC_backslash;
++    $parser = (int) $parser_resource;
++
++    if ($XML_RPC_xh[$parser]['lv'] != 3) {
++        // "lookforvalue==3" means that we've found an entire value
++        // and should discard any further character data
++
++        if ($XML_RPC_xh[$parser]['lv'] == 1) {
++            // if we've found text and we're just in a  then
++            // turn quoting on, as this will be a string
++            $XML_RPC_xh[$parser]['qt'] = 1;
++            // and say we've found a value
++            $XML_RPC_xh[$parser]['lv'] = 2;
++        }
++
++        // replace characters that eval would
++        // do special things with
++        if (!isset($XML_RPC_xh[$parser]['ac'])) {
++            $XML_RPC_xh[$parser]['ac'] = '';
++        }
++        $XML_RPC_xh[$parser]['ac'] .= str_replace('$', '\$',
++            str_replace('"', '\"', str_replace(chr(92),
++            $XML_RPC_backslash, $data)));
++    }
++}
++
++/**
++ * The common methods and properties for all of the XML_RPC classes
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.3.1
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Base {
++
++    /**
++     * PEAR Error handling
++     *
++     * @return object  PEAR_Error object
++     */
++    function raiseError($msg, $code)
++    {
++        include_once 'PEAR.php';
++        if (is_object(@$this)) {
++            return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
++        } else {
++            return PEAR::raiseError('XML_RPC: ' . $msg, $code);
++        }
++    }
++
++    /**
++     * Tell whether something is a PEAR_Error object
++     *
++     * @param mixed $value  the item to check
++     *
++     * @return bool  whether $value is a PEAR_Error object or not
++     *
++     * @access public
++     */
++    function isError($value)
++    {
++        return is_a($value, 'PEAR_Error');
++    }
++}
++
++/**
++ * The methods and properties for submitting XML RPC requests
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.3.1
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Client extends XML_RPC_Base {
++
++    /**
++     * The path and name of the RPC server script you want the request to go to
++     * @var string
++     */
++    var $path = '';
++
++    /**
++     * The name of the remote server to connect to
++     * @var string
++     */
++    var $server = '';
++
++    /**
++     * The protocol to use in contacting the remote server
++     * @var string
++     */
++    var $protocol = 'http://';
++
++    /**
++     * The port for connecting to the remote server
++     *
++     * The default is 80 for http:// connections
++     * and 443 for https:// and ssl:// connections.
++     *
++     * @var integer
++     */
++    var $port = 80;
++
++    /**
++     * A user name for accessing the RPC server
++     * @var string
++     * @see XML_RPC_Client::setCredentials()
++     */
++    var $username = '';
++
++    /**
++     * A password for accessing the RPC server
++     * @var string
++     * @see XML_RPC_Client::setCredentials()
++     */
++    var $password = '';
++
++    /**
++     * The name of the proxy server to use, if any
++     * @var string
++     */
++    var $proxy = '';
++
++    /**
++     * The protocol to use in contacting the proxy server, if any
++     * @var string
++     */
++    var $proxy_protocol = 'http://';
++
++    /**
++     * The port for connecting to the proxy server
++     *
++     * The default is 8080 for http:// connections
++     * and 443 for https:// and ssl:// connections.
++     *
++     * @var integer
++     */
++    var $proxy_port = 8080;
++
++    /**
++     * A user name for accessing the proxy server
++     * @var string
++     */
++    var $proxy_user = '';
++
++    /**
++     * A password for accessing the proxy server
++     * @var string
++     */
++    var $proxy_pass = '';
++
++    /**
++     * The error number, if any
++     * @var integer
++     */
++    var $errno = 0;
++
++    /**
++     * The error message, if any
++     * @var string
++     */
++    var $errstring = '';
++
++    /**
++     * The current debug mode (1 = on, 0 = off)
++     * @var integer
++     */
++    var $debug = 0;
++
++    /**
++     * The HTTP headers for the current request.
++     * @var string
++     */
++    var $headers = '';
++
++
++    /**
++     * Sets the object's properties
++     *
++     * @param string  $path        the path and name of the RPC server script
++     *                              you want the request to go to
++     * @param string  $server      the URL of the remote server to connect to.
++     *                              If this parameter doesn't specify a
++     *                              protocol and $port is 443, ssl:// is
++     *                              assumed.
++     * @param integer $port        a port for connecting to the remote server.
++     *                              Defaults to 80 for http:// connections and
++     *                              443 for https:// and ssl:// connections.
++     * @param string  $proxy       the URL of the proxy server to use, if any.
++     *                              If this parameter doesn't specify a
++     *                              protocol and $port is 443, ssl:// is
++     *                              assumed.
++     * @param integer $proxy_port  a port for connecting to the remote server.
++     *                              Defaults to 8080 for http:// connections and
++     *                              443 for https:// and ssl:// connections.
++     * @param string  $proxy_user  a user name for accessing the proxy server
++     * @param string  $proxy_pass  a password for accessing the proxy server
++     *
++     * @return void
++     */
++    function XML_RPC_Client($path, $server, $port = 0,
++                            $proxy = '', $proxy_port = 0,
++                            $proxy_user = '', $proxy_pass = '')
++    {
++        $this->path       = $path;
++        $this->proxy_user = $proxy_user;
++        $this->proxy_pass = $proxy_pass;
++
++        preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match);
++        if ($match[1] == '') {
++            if ($port == 443) {
++                $this->server   = $match[2];
++                $this->protocol = 'ssl://';
++                $this->port     = 443;
++            } else {
++                $this->server = $match[2];
++                if ($port) {
++                    $this->port = $port;
++                }
++            }
++        } elseif ($match[1] == 'http://') {
++            $this->server = $match[2];
++            if ($port) {
++                $this->port = $port;
++            }
++        } else {
++            $this->server   = $match[2];
++            $this->protocol = 'ssl://';
++            if ($port) {
++                $this->port = $port;
++            } else {
++                $this->port = 443;
++            }
++        }
++
++        if ($proxy) {
++            preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match);
++            if ($match[1] == '') {
++                if ($proxy_port == 443) {
++                    $this->proxy          = $match[2];
++                    $this->proxy_protocol = 'ssl://';
++                    $this->proxy_port     = 443;
++                } else {
++                    $this->proxy = $match[2];
++                    if ($proxy_port) {
++                        $this->proxy_port = $proxy_port;
++                    }
++                }
++            } elseif ($match[1] == 'http://') {
++                $this->proxy = $match[2];
++                if ($proxy_port) {
++                    $this->proxy_port = $proxy_port;
++                }
++            } else {
++                $this->proxy          = $match[2];
++                $this->proxy_protocol = 'ssl://';
++                if ($proxy_port) {
++                    $this->proxy_port = $proxy_port;
++                } else {
++                    $this->proxy_port = 443;
++                }
++            }
++        }
++    }
++
++    /**
++     * Change the current debug mode
++     *
++     * @param int $in  where 1 = on, 0 = off
++     *
++     * @return void
++     */
++    function setDebug($in)
++    {
++        if ($in) {
++            $this->debug = 1;
++        } else {
++            $this->debug = 0;
++        }
++    }
++
++    /**
++     * Set username and password properties for connecting to the RPC server
++     *
++     * @param string $u  the user name
++     * @param string $p  the password
++     *
++     * @return void
++     *
++     * @see XML_RPC_Client::$username, XML_RPC_Client::$password
++     */
++    function setCredentials($u, $p)
++    {
++        $this->username = $u;
++        $this->password = $p;
++    }
++
++    /**
++     * Transmit the RPC request via HTTP 1.0 protocol
++     *
++     * @param object $msg       the XML_RPC_Message object
++     * @param int    $timeout   how many seconds to wait for the request
++     *
++     * @return object  an XML_RPC_Response object.  0 is returned if any
++     *                  problems happen.
++     *
++     * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
++     *      XML_RPC_Client::setCredentials()
++     */
++    function send($msg, $timeout = 0)
++    {
++        if (strtolower(get_class($msg)) != 'xml_rpc_message') {
++            $this->errstr = 'send()\'s $msg parameter must be an'
++                          . ' XML_RPC_Message object.';
++            $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING);
++            return 0;
++        }
++        $msg->debug = $this->debug;
++        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
++                                        $timeout, $this->username,
++                                        $this->password);
++    }
++
++    /**
++     * Transmit the RPC request via HTTP 1.0 protocol
++     *
++     * Requests should be sent using XML_RPC_Client send() rather than
++     * calling this method directly.
++     *
++     * @param object $msg       the XML_RPC_Message object
++     * @param string $server    the server to send the request to
++     * @param int    $port      the server port send the request to
++     * @param int    $timeout   how many seconds to wait for the request
++     *                           before giving up
++     * @param string $username  a user name for accessing the RPC server
++     * @param string $password  a password for accessing the RPC server
++     *
++     * @return object  an XML_RPC_Response object.  0 is returned if any
++     *                  problems happen.
++     *
++     * @access protected
++     * @see XML_RPC_Client::send()
++     */
++    function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
++                               $username = '', $password = '')
++    {
++        /*
++         * If we're using a proxy open a socket to the proxy server
++         * instead to the xml-rpc server
++         */
++        if ($this->proxy) {
++            if ($this->proxy_protocol == 'http://') {
++                $protocol = '';
++            } else {
++                $protocol = $this->proxy_protocol;
++            }
++            if ($timeout > 0) {
++                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
++                                 $this->errno, $this->errstr, $timeout);
++            } else {
++                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
++                                 $this->errno, $this->errstr);
++            }
++        } else {
++            if ($this->protocol == 'http://') {
++                $protocol = '';
++            } else {
++                $protocol = $this->protocol;
++            }
++            if ($timeout > 0) {
++                $fp = @fsockopen($protocol . $server, $port,
++                                 $this->errno, $this->errstr, $timeout);
++            } else {
++                $fp = @fsockopen($protocol . $server, $port,
++                                 $this->errno, $this->errstr);
++            }
++        }
++
++        /*
++         * Just raising the error without returning it is strange,
++         * but keep it here for backwards compatibility.
++         */
++        if (!$fp && $this->proxy) {
++            $this->raiseError('Connection to proxy server '
++                              . $this->proxy . ':' . $this->proxy_port
++                              . ' failed. ' . $this->errstr,
++                              XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        } elseif (!$fp) {
++            $this->raiseError('Connection to RPC server '
++                              . $server . ':' . $port
++                              . ' failed. ' . $this->errstr,
++                              XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        }
++
++        if ($timeout) {
++            stream_set_timeout($fp, $timeout);
++        }
++
++        // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly
++        if ($username != $this->username) {
++            $this->setCredentials($username, $password);
++        }
++
++        // Only create the payload if it was not created previously
++        if (empty($msg->payload)) {
++            $msg->createPayload();
++        }
++        $this->createHeaders($msg);
++
++        $op  = $this->headers . "\r\n\r\n";
++        $op .= $msg->payload;
++
++        if (!fputs($fp, $op, strlen($op))) {
++            $this->errstr = 'Write error';
++            return 0;
++        }
++        $resp = $msg->parseResponseFile($fp);
++
++        $meta = stream_get_meta_data($fp);
++        if ($meta['timed_out']) {
++            fclose($fp);
++            $this->errstr = 'RPC server did not send response before timeout.';
++            $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        }
++
++        fclose($fp);
++        return $resp;
++    }
++
++    /**
++     * Determines the HTTP headers and puts it in the $headers property
++     *
++     * @param object $msg       the XML_RPC_Message object
++     *
++     * @return boolean  TRUE if okay, FALSE if the message payload isn't set.
++     *
++     * @access protected
++     */
++    function createHeaders($msg)
++    {
++        if (empty($msg->payload)) {
++            return false;
++        }
++        if ($this->proxy) {
++            $this->headers = 'POST ' . $this->protocol . $this->server;
++            if ($this->proxy_port) {
++                $this->headers .= ':' . $this->port;
++            }
++        } else {
++           $this->headers = 'POST ';
++        }
++        $this->headers .= $this->path. " HTTP/1.0\r\n";
++        
++        $this->headers .= "User-Agent: PEAR XML_RPC\r\n";
++        $this->headers .= 'Host: ' . $this->server . "\r\n";
++
++        if ($this->proxy && $this->proxy_user) {
++            $this->headers .= 'Proxy-Authorization: Basic '
++                     . base64_encode("$this->proxy_user:$this->proxy_pass")
++                     . "\r\n";
++        }
++
++        // thanks to Grant Rauscher  for this
++        if ($this->username) {
++            $this->headers .= 'Authorization: Basic '
++                     . base64_encode("$this->username:$this->password")
++                     . "\r\n";
++        }
++
++        $this->headers .= "Content-Type: text/xml\r\n";
++        $this->headers .= 'Content-Length: ' . strlen($msg->payload);
++        return true;
++    }
++}
++
++/**
++ * The methods and properties for interpreting responses to XML RPC requests
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.3.1
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Response extends XML_RPC_Base
++{
++    var $xv;
++    var $fn;
++    var $fs;
++    var $hdrs;
++
++    /**
++     * @return void
++     */
++    function XML_RPC_Response($val, $fcode = 0, $fstr = '')
++    {
++        if ($fcode != 0) {
++            $this->fn = $fcode;
++            $this->fs = htmlspecialchars($fstr);
++        } else {
++            $this->xv = $val;
++        }
++    }
++
++    /**
++     * @return int  the error code
++     */
++    function faultCode()
++    {
++        if (isset($this->fn)) {
++            return $this->fn;
++        } else {
++            return 0;
++        }
++    }
++
++    /**
++     * @return string  the error string
++     */
++    function faultString()
++    {
++        return $this->fs;
++    }
++
++    /**
++     * @return mixed  the value
++     */
++    function value()
++    {
++        return $this->xv;
++    }
++
++    /**
++     * @return string  the error message in XML format
++     */
++    function serialize()
++    {
++        $rs = "\n";
++        if ($this->fn) {
++            $rs .= "
++  
++    
++      
++        faultCode
++        " . $this->fn . "
++      
++      
++        faultString
++        " . $this->fs . "
++      
++    
++  
++";
++        } else {
++            $rs .= "\n\n" . $this->xv->serialize() .
++        "\n";
++        }
++        $rs .= "\n";
++        return $rs;
++    }
++}
++
++/**
++ * The methods and properties for composing XML RPC messages
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.3.1
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Message extends XML_RPC_Base
++{
++    /**
++     * The current debug mode (1 = on, 0 = off)
++     * @var integer
++     */
++    var $debug = 0;
++
++    /**
++     * The encoding to be used for outgoing messages
++     *
++     * Defaults to the value of $GLOBALS['XML_RPC_defencoding']
++     *
++     * @var string
++     * @see XML_RPC_Message::setSendEncoding(),
++     *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
++     */
++    var $send_encoding = '';
++
++    /**
++     * The method presently being evaluated
++     * @var string
++     */
++    var $methodname = '';
++
++    /**
++     * @var array
++     */
++    var $params = array();
++
++    /**
++     * The XML message being generated
++     * @var string
++     */
++    var $payload = '';
++
++    /**
++     * @return void
++     */
++    function XML_RPC_Message($meth, $pars = 0)
++    {
++        $this->methodname = $meth;
++        if (is_array($pars) && sizeof($pars) > 0) {
++            for ($i = 0; $i < sizeof($pars); $i++) {
++                $this->addParam($pars[$i]);
++            }
++        }
++    }
++
++    /**
++     * Produces the XML declaration including the encoding attribute
++     *
++     * The encoding is determined by this class' $send_encoding
++     * property.  If the $send_encoding property is not set, use
++     * $GLOBALS['XML_RPC_defencoding'].
++     *
++     * @return string  the XML declaration and  element
++     *
++     * @see XML_RPC_Message::setSendEncoding(),
++     *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
++     */
++    function xml_header()
++    {
++        global $XML_RPC_defencoding;
++        if (!$this->send_encoding) {
++            $this->send_encoding = $XML_RPC_defencoding;
++        }
++        return 'send_encoding . '"?>'
++               . "\n\n";
++    }
++
++    /**
++     * @return string  the closing  tag
++     */
++    function xml_footer()
++    {
++        return "\n";
++    }
++
++    /**
++     * @return void
++     *
++     * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
++     */
++    function createPayload()
++    {
++        $this->payload = $this->xml_header();
++        $this->payload .= '' . $this->methodname . "\n";
++        $this->payload .= "\n";
++        for ($i = 0; $i < sizeof($this->params); $i++) {
++            $p = $this->params[$i];
++            $this->payload .= "\n" . $p->serialize() . "\n";
++        }
++        $this->payload .= "\n";
++        $this->payload .= $this->xml_footer();
++        $this->payload = ereg_replace("[\r\n]+", "\r\n", $this->payload);
++    }
++
++    /**
++     * @return string  the name of the method
++     */
++    function method($meth = '')
++    {
++        if ($meth != '') {
++            $this->methodname = $meth;
++        }
++        return $this->methodname;
++    }
++
++    /**
++     * @return string  the payload
++     */
++    function serialize()
++    {
++        $this->createPayload();
++        return $this->payload;
++    }
++
++    /**
++     * @return void
++     */
++    function addParam($par)
++    {
++        $this->params[] = $par;
++    }
++
++    /**
++     * Obtains an XML_RPC_Value object for the given parameter
++     *
++     * @param int $i  the index number of the parameter to obtain
++     *
++     * @return object  the XML_RPC_Value object.
++     *                  If the parameter doesn't exist, an XML_RPC_Response object.
++     *
++     * @since Returns XML_RPC_Response object on error since Release 1.3.0
++     */
++    function getParam($i)
++    {
++        global $XML_RPC_err, $XML_RPC_str;
++
++        if (isset($this->params[$i])) {
++            return $this->params[$i];
++        } else {
++            $this->raiseError('The submitted request did not contain this parameter',
++                              XML_RPC_ERROR_INCORRECT_PARAMS);
++            return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
++                                        $XML_RPC_str['incorrect_params']);
++        }
++    }
++
++    /**
++     * @return int  the number of parameters
++     */
++    function getNumParams()
++    {
++        return sizeof($this->params);
++    }
++
++    /**
++     * Sets the XML declaration's encoding attribute
++     *
++     * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
++     *
++     * @return void
++     *
++     * @see XML_RPC_Message::$send_encoding, XML_RPC_Message::xml_header()
++     * @since Method available since Release 1.2.0
++     */
++    function setSendEncoding($type)
++    {
++        $this->send_encoding = $type;
++    }
++
++    /**
++     * Determine the XML's encoding via the encoding attribute
++     * in the XML declaration
++     *
++     * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
++     * or US-ASCII, $XML_RPC_defencoding will be returned.
++     *
++     * @param string $data  the XML that will be parsed
++     *
++     * @return string  the encoding to be used
++     *
++     * @link   http://php.net/xml_parser_create
++     * @since  Method available since Release 1.2.0
++     */
++    function getEncoding($data)
++    {
++        global $XML_RPC_defencoding;
++
++        if (preg_match('/<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]/i',
++                       $data, $match))
++        {
++            $match[1] = trim(strtoupper($match[1]));
++            switch ($match[1]) {
++                case 'ISO-8859-1':
++                case 'UTF-8':
++                case 'US-ASCII':
++                    return $match[1];
++                    break;
++
++                default:
++                    return $XML_RPC_defencoding;
++            }
++        } else {
++            return $XML_RPC_defencoding;
++        }
++    }
++
++    /**
++     * @return object  a new XML_RPC_Response object
++     */
++    function parseResponseFile($fp)
++    {
++        $ipd = '';
++        while ($data = @fread($fp, 8192)) {
++            $ipd .= $data;
++        }
++        return $this->parseResponse($ipd);
++    }
++
++    /**
++     * @return object  a new XML_RPC_Response object
++     */
++    function parseResponse($data = '')
++    {
++        global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
++
++        $encoding = $this->getEncoding($data);
++        $parser_resource = xml_parser_create($encoding);
++        $parser = (int) $parser_resource;
++
++        $XML_RPC_xh[$parser] = array();
++
++        $XML_RPC_xh[$parser]['st'] = '';
++        $XML_RPC_xh[$parser]['cm'] = 0;
++        $XML_RPC_xh[$parser]['isf'] = 0;
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = '';
++
++        xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
++        xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
++        xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
++
++        $hdrfnd = 0;
++        if ($this->debug) {
++            print "
---GOT---\n";
++            print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
++            print "\n---END---\n
"; ++ } ++ ++ // See if response is a 200 or a 100 then a 200, else raise error. ++ // But only do this if we're using the HTTP protocol. ++ if (ereg('^HTTP', $data) && ++ !ereg('^HTTP/[0-9\.]+ 200 ', $data) && ++ !preg_match('@^HTTP/[0-9\.]+ 10[0-9]([A-Za-z ]+)?[\r\n]+HTTP/[0-9\.]+ 200@', $data)) ++ { ++ $errstr = substr($data, 0, strpos($data, "\n") - 1); ++ error_log('HTTP error, got response: ' . $errstr); ++ $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], ++ $XML_RPC_str['http_error'] . ' (' . ++ $errstr . ')'); ++ xml_parser_free($parser_resource); ++ return $r; ++ } ++ // gotta get rid of headers here ++ ++ ++ if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) { ++ $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos); ++ $data = substr($data, $brpos + 4); ++ $hdrfnd = 1; ++ } ++ ++ /* ++ * be tolerant of junk after methodResponse ++ * (e.g. javascript automatically inserted by free hosts) ++ * thanks to Luca Mariano ++ */ ++ $data = substr($data, 0, strpos($data, "") + 17); ++ ++ if (!xml_parse($parser_resource, $data, sizeof($data))) { ++ // thanks to Peter Kocks ++ if (xml_get_current_line_number($parser_resource) == 1) { ++ $errstr = 'XML error at line 1, check URL'; ++ } else { ++ $errstr = sprintf('XML error: %s at line %d', ++ xml_error_string(xml_get_error_code($parser_resource)), ++ xml_get_current_line_number($parser_resource)); ++ } ++ error_log($errstr); ++ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], ++ $XML_RPC_str['invalid_return']); ++ xml_parser_free($parser_resource); ++ return $r; ++ } ++ xml_parser_free($parser_resource); ++ if ($this->debug) { ++ print '
---EVALING---[' .
++            strlen($XML_RPC_xh[$parser]['st']) . " chars]---\n" .
++            htmlspecialchars($XML_RPC_xh[$parser]['st']) . ";\n---END---
"; ++ } ++ if (strlen($XML_RPC_xh[$parser]['st']) == 0) { ++ // then something odd has happened ++ // and it's time to generate a client side error ++ // indicating something odd went on ++ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], ++ $XML_RPC_str['invalid_return']); ++ } else { ++ eval('$v=' . $XML_RPC_xh[$parser]['st'] . '; $allOK=1;'); ++ if ($XML_RPC_xh[$parser]['isf']) { ++ $f = $v->structmem('faultCode'); ++ $fs = $v->structmem('faultString'); ++ $r = new XML_RPC_Response($v, $f->scalarval(), ++ $fs->scalarval()); ++ } else { ++ $r = new XML_RPC_Response($v); ++ } ++ } ++ $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]); ++ return $r; ++ } ++} ++ ++/** ++ * The methods and properties that represent data in XML RPC format ++ * ++ * @category Web Services ++ * @package XML_RPC ++ * @author Edd Dumbill ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version Release: 1.3.1 ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++class XML_RPC_Value extends XML_RPC_Base ++{ ++ var $me = array(); ++ var $mytype = 0; ++ ++ /** ++ * @return void ++ */ ++ function XML_RPC_Value($val = -1, $type = '') ++ { ++ global $XML_RPC_Types; ++ $this->me = array(); ++ $this->mytype = 0; ++ if ($val != -1 || $type != '') { ++ if ($type == '') { ++ $type = 'string'; ++ } ++ if (!array_key_exists($type, $XML_RPC_Types)) { ++ // XXX ++ // need some way to report this error ++ } elseif ($XML_RPC_Types[$type] == 1) { ++ $this->addScalar($val, $type); ++ } elseif ($XML_RPC_Types[$type] == 2) { ++ $this->addArray($val); ++ } elseif ($XML_RPC_Types[$type] == 3) { ++ $this->addStruct($val); ++ } ++ } ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addScalar($val, $type = 'string') ++ { ++ global $XML_RPC_Types, $XML_RPC_Boolean; ++ ++ if ($this->mytype == 1) { ++ $this->raiseError('Scalar can have only one value', ++ XML_RPC_ERROR_INVALID_TYPE); ++ return 0; ++ } ++ $typeof = $XML_RPC_Types[$type]; ++ if ($typeof != 1) { ++ $this->raiseError("Not a scalar type (${typeof})", ++ XML_RPC_ERROR_INVALID_TYPE); ++ return 0; ++ } ++ ++ if ($type == $XML_RPC_Boolean) { ++ if (strcasecmp($val, 'true') == 0 ++ || $val == 1 ++ || ($val == true && strcasecmp($val, 'false'))) ++ { ++ $val = 1; ++ } else { ++ $val = 0; ++ } ++ } ++ ++ if ($this->mytype == 2) { ++ // we're adding to an array here ++ $ar = $this->me['array']; ++ $ar[] = new XML_RPC_Value($val, $type); ++ $this->me['array'] = $ar; ++ } else { ++ // a scalar, so set the value and remember we're scalar ++ $this->me[$type] = $val; ++ $this->mytype = $typeof; ++ } ++ return 1; ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addArray($vals) ++ { ++ global $XML_RPC_Types; ++ if ($this->mytype != 0) { ++ $this->raiseError( ++ 'Already initialized as a [' . $this->kindOf() . ']', ++ XML_RPC_ERROR_ALREADY_INITIALIZED); ++ return 0; ++ } ++ $this->mytype = $XML_RPC_Types['array']; ++ $this->me['array'] = $vals; ++ return 1; ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addStruct($vals) ++ { ++ global $XML_RPC_Types; ++ if ($this->mytype != 0) { ++ $this->raiseError( ++ 'Already initialized as a [' . $this->kindOf() . ']', ++ XML_RPC_ERROR_ALREADY_INITIALIZED); ++ return 0; ++ } ++ $this->mytype = $XML_RPC_Types['struct']; ++ $this->me['struct'] = $vals; ++ return 1; ++ } ++ ++ /** ++ * @return void ++ */ ++ function dump($ar) ++ { ++ reset($ar); ++ foreach ($ar as $key => $val) { ++ echo "$key => $val
"; ++ if ($key == 'array') { ++ foreach ($val as $key2 => $val2) { ++ echo "-- $key2 => $val2
"; ++ } ++ } ++ } ++ } ++ ++ /** ++ * @return string the data type of the current value ++ */ ++ function kindOf() ++ { ++ switch ($this->mytype) { ++ case 3: ++ return 'struct'; ++ ++ case 2: ++ return 'array'; ++ ++ case 1: ++ return 'scalar'; ++ ++ default: ++ return 'undef'; ++ } ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serializedata($typ, $val) ++ { ++ $rs = ''; ++ global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean; ++ if (!array_key_exists($typ, $XML_RPC_Types)) { ++ // XXX ++ // need some way to report this error ++ return; ++ } ++ switch ($XML_RPC_Types[$typ]) { ++ case 3: ++ // struct ++ $rs .= "\n"; ++ reset($val); ++ foreach ($val as $key2 => $val2) { ++ $rs .= "${key2}\n"; ++ $rs .= $this->serializeval($val2); ++ $rs .= "\n"; ++ } ++ $rs .= ''; ++ break; ++ ++ case 2: ++ // array ++ $rs .= "\n\n"; ++ for ($i = 0; $i < sizeof($val); $i++) { ++ $rs .= $this->serializeval($val[$i]); ++ } ++ $rs .= "\n"; ++ break; ++ ++ case 1: ++ switch ($typ) { ++ case $XML_RPC_Base64: ++ $rs .= "<${typ}>" . base64_encode($val) . ""; ++ break; ++ case $XML_RPC_Boolean: ++ $rs .= "<${typ}>" . ($val ? '1' : '0') . ""; ++ break; ++ case $XML_RPC_String: ++ $rs .= "<${typ}>" . htmlspecialchars($val). ""; ++ break; ++ default: ++ $rs .= "<${typ}>${val}"; ++ } ++ } ++ return $rs; ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serialize() ++ { ++ return $this->serializeval($this); ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serializeval($o) ++ { ++ $rs = ''; ++ $ar = $o->me; ++ reset($ar); ++ list($typ, $val) = each($ar); ++ $rs .= ''; ++ $rs .= $this->serializedata($typ, $val); ++ $rs .= "\n"; ++ return $rs; ++ } ++ ++ /** ++ * @return mixed the contents of the element requested ++ */ ++ function structmem($m) ++ { ++ return $this->me['struct'][$m]; ++ } ++ ++ /** ++ * @return void ++ */ ++ function structreset() ++ { ++ reset($this->me['struct']); ++ } ++ ++ /** ++ * @return the key/value pair of the struct's current element ++ */ ++ function structeach() ++ { ++ return each($this->me['struct']); ++ } ++ ++ /** ++ * @return mixed the current value ++ */ ++ function getval() ++ { ++ // UNSTABLE ++ global $XML_RPC_BOOLEAN, $XML_RPC_Base64; ++ ++ reset($this->me); ++ $b = current($this->me); ++ ++ // contributed by I Sofer, 2001-03-24 ++ // add support for nested arrays to scalarval ++ // i've created a new method here, so as to ++ // preserve back compatibility ++ ++ if (is_array($b)) { ++ foreach ($b as $id => $cont) { ++ $b[$id] = $cont->scalarval(); ++ } ++ } ++ ++ // add support for structures directly encoding php objects ++ if (is_object($b)) { ++ $t = get_object_vars($b); ++ foreach ($t as $id => $cont) { ++ $t[$id] = $cont->scalarval(); ++ } ++ foreach ($t as $id => $cont) { ++ eval('$b->'.$id.' = $cont;'); ++ } ++ } ++ ++ // end contrib ++ return $b; ++ } ++ ++ /** ++ * @return mixed ++ */ ++ function scalarval() ++ { ++ global $XML_RPC_Boolean, $XML_RPC_Base64; ++ reset($this->me); ++ return current($this->me); ++ } ++ ++ /** ++ * @return string ++ */ ++ function scalartyp() ++ { ++ global $XML_RPC_I4, $XML_RPC_Int; ++ reset($this->me); ++ $a = key($this->me); ++ if ($a == $XML_RPC_I4) { ++ $a = $XML_RPC_Int; ++ } ++ return $a; ++ } ++ ++ /** ++ * @return mixed the struct's current element ++ */ ++ function arraymem($m) ++ { ++ return $this->me['array'][$m]; ++ } ++ ++ /** ++ * @return int the number of elements in the array ++ */ ++ function arraysize() ++ { ++ reset($this->me); ++ list($a, $b) = each($this->me); ++ return sizeof($b); ++ } ++ ++ /** ++ * Determines if the item submitted is an XML_RPC_Value object ++ * ++ * @param mixed $val the variable to be evaluated ++ * ++ * @return bool TRUE if the item is an XML_RPC_Value object ++ * ++ * @static ++ * @since Method available since Release 1.3.0 ++ */ ++ function isValue($val) ++ { ++ return (strtolower(get_class($val)) == 'xml_rpc_value'); ++ } ++} ++ ++/** ++ * Return an ISO8601 encoded string ++ * ++ * While timezones ought to be supported, the XML-RPC spec says: ++ * ++ * "Don't assume a timezone. It should be specified by the server in its ++ * documentation what assumptions it makes about timezones." ++ * ++ * This routine always assumes localtime unless $utc is set to 1, in which ++ * case UTC is assumed and an adjustment for locale is made when encoding. ++ * ++ * @return string the formatted date ++ */ ++function XML_RPC_iso8601_encode($timet, $utc = 0) ++{ ++ if (!$utc) { ++ $t = strftime('%Y%m%dT%H:%M:%S', $timet); ++ } else { ++ if (function_exists('gmstrftime')) { ++ // gmstrftime doesn't exist in some versions ++ // of PHP ++ $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); ++ } else { ++ $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); ++ } ++ } ++ return $t; ++} ++ ++/** ++ * Convert a datetime string into a Unix timestamp ++ * ++ * While timezones ought to be supported, the XML-RPC spec says: ++ * ++ * "Don't assume a timezone. It should be specified by the server in its ++ * documentation what assumptions it makes about timezones." ++ * ++ * This routine always assumes localtime unless $utc is set to 1, in which ++ * case UTC is assumed and an adjustment for locale is made when encoding. ++ * ++ * @return int the unix timestamp of the date submitted ++ */ ++function XML_RPC_iso8601_decode($idate, $utc = 0) ++{ ++ $t = 0; ++ if (ereg('([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})', $idate, $regs)) { ++ if ($utc) { ++ $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); ++ } else { ++ $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); ++ } ++ } ++ return $t; ++} ++ ++/** ++ * Converts an XML_RPC_Value object into native PHP types ++ * ++ * @param object $XML_RPC_val the XML_RPC_Value object to decode ++ * ++ * @return mixed the PHP values ++ */ ++function XML_RPC_decode($XML_RPC_val) ++{ ++ $kind = $XML_RPC_val->kindOf(); ++ ++ if ($kind == 'scalar') { ++ return $XML_RPC_val->scalarval(); ++ ++ } elseif ($kind == 'array') { ++ $size = $XML_RPC_val->arraysize(); ++ $arr = array(); ++ for ($i = 0; $i < $size; $i++) { ++ $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i)); ++ } ++ return $arr; ++ ++ } elseif ($kind == 'struct') { ++ $XML_RPC_val->structreset(); ++ $arr = array(); ++ while (list($key, $value) = $XML_RPC_val->structeach()) { ++ $arr[$key] = XML_RPC_decode($value); ++ } ++ return $arr; ++ } ++} ++ ++/** ++ * Converts native PHP types into an XML_RPC_Value object ++ * ++ * @param mixed $php_val the PHP value or variable you want encoded ++ * ++ * @return object the XML_RPC_Value object ++ */ ++function XML_RPC_encode($php_val) ++{ ++ global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double, $XML_RPC_String, ++ $XML_RPC_Array, $XML_RPC_Struct; ++ ++ $type = gettype($php_val); ++ $XML_RPC_val = new XML_RPC_Value; ++ ++ switch ($type) { ++ case 'array': ++ if (empty($php_val)) { ++ $XML_RPC_val->addArray($php_val); ++ break; ++ } ++ $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); ++ if (empty($tmp)) { ++ $arr = array(); ++ foreach ($php_val as $k => $v) { ++ $arr[$k] = XML_RPC_encode($v); ++ } ++ $XML_RPC_val->addArray($arr); ++ break; ++ } ++ // fall though if it's not an enumerated array ++ ++ case 'object': ++ $arr = array(); ++ foreach ($php_val as $k => $v) { ++ $arr[$k] = XML_RPC_encode($v); ++ } ++ $XML_RPC_val->addStruct($arr); ++ break; ++ ++ case 'integer': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Int); ++ break; ++ ++ case 'double': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Double); ++ break; ++ ++ case 'string': ++ case 'NULL': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_String); ++ break; ++ ++ case 'boolean': ++ // Add support for encoding/decoding of booleans, since they ++ // are supported in PHP ++ // by ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean); ++ break; ++ ++ case 'unknown type': ++ default: ++ $XML_RPC_val = false; ++ } ++ return $XML_RPC_val; ++} ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * c-hanging-comment-ender-p: nil ++ * End: ++ */ ++ ++?> ++XML_RPC-1.3.1/Server.php100644 1750 144 47770 10260516576 10104 ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version CVS: $Id: Server.php,v 1.26 2005/05/09 21:39:47 danielc Exp $ ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++ ++ ++/** ++ * Pull in the XML_RPC class ++ */ ++require_once 'XML/RPC.php'; ++ ++ ++/** ++ * signature for system.listMethods: return = array, ++ * parameters = a string or nothing ++ * @global array $GLOBALS['XML_RPC_Server_listMethods_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_listMethods_sig'] = array( ++ array($GLOBALS['XML_RPC_Array'], ++ $GLOBALS['XML_RPC_String'] ++ ), ++ array($GLOBALS['XML_RPC_Array']) ++); ++ ++/** ++ * docstring for system.listMethods ++ * @global string $GLOBALS['XML_RPC_Server_listMethods_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_listMethods_doc'] = 'This method lists all the' ++ . ' methods that the XML-RPC server knows how to dispatch'; ++ ++/** ++ * signature for system.methodSignature: return = array, ++ * parameters = string ++ * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_methodSignature_sig'] = array( ++ array($GLOBALS['XML_RPC_Array'], ++ $GLOBALS['XML_RPC_String'] ++ ) ++); ++ ++/** ++ * docstring for system.methodSignature ++ * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_methodSignature_doc'] = 'Returns an array of known' ++ . ' signatures (an array of arrays) for the method name passed. If' ++ . ' no signatures are known, returns a none-array (test for type !=' ++ . ' array to detect missing signature)'; ++ ++/** ++ * signature for system.methodHelp: return = string, ++ * parameters = string ++ * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_methodHelp_sig'] = array( ++ array($GLOBALS['XML_RPC_String'], ++ $GLOBALS['XML_RPC_String'] ++ ) ++); ++ ++/** ++ * docstring for methodHelp ++ * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_methodHelp_doc'] = 'Returns help text if defined' ++ . ' for the method passed, otherwise returns an empty string'; ++ ++/** ++ * dispatch map for the automatically declared XML-RPC methods. ++ * @global array $GLOBALS['XML_RPC_Server_dmap'] ++ */ ++$GLOBALS['XML_RPC_Server_dmap'] = array( ++ 'system.listMethods' => array( ++ 'function' => 'XML_RPC_Server_listMethods', ++ 'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc'] ++ ), ++ 'system.methodHelp' => array( ++ 'function' => 'XML_RPC_Server_methodHelp', ++ 'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc'] ++ ), ++ 'system.methodSignature' => array( ++ 'function' => 'XML_RPC_Server_methodSignature', ++ 'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc'] ++ ) ++); ++ ++/** ++ * @global string $GLOBALS['XML_RPC_Server_debuginfo'] ++ */ ++$GLOBALS['XML_RPC_Server_debuginfo'] = ''; ++ ++ ++/** ++ * Lists all the methods that the XML-RPC server knows how to dispatch ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_listMethods($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $v = new XML_RPC_Value(); ++ $outAr = array(); ++ foreach ($server->dmap as $key => $val) { ++ $outAr[] = new XML_RPC_Value($key, 'string'); ++ } ++ foreach ($XML_RPC_Server_dmap as $key => $val) { ++ $outAr[] = new XML_RPC_Value($key, 'string'); ++ } ++ $v->addArray($outAr); ++ return new XML_RPC_Response($v); ++} ++ ++/** ++ * Returns an array of known signatures (an array of arrays) ++ * for the given method ++ * ++ * If no signatures are known, returns a none-array ++ * (test for type != array to detect missing signature) ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_methodSignature($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $methName = $m->getParam(0); ++ $methName = $methName->scalarval(); ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $server->dmap; ++ $sysCall = 0; ++ } ++ // print "\n"; ++ if (isset($dmap[$methName])) { ++ if ($dmap[$methName]['signature']) { ++ $sigs = array(); ++ $thesigs = $dmap[$methName]['signature']; ++ for ($i = 0; $i < sizeof($thesigs); $i++) { ++ $cursig = array(); ++ $inSig = $thesigs[$i]; ++ for ($j = 0; $j < sizeof($inSig); $j++) { ++ $cursig[] = new XML_RPC_Value($inSig[$j], 'string'); ++ } ++ $sigs[] = new XML_RPC_Value($cursig, 'array'); ++ } ++ $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array')); ++ } else { ++ $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string')); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], ++ $XML_RPC_str['introspect_unknown']); ++ } ++ return $r; ++} ++ ++/** ++ * Returns help text if defined for the method passed, otherwise returns ++ * an empty string ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_methodHelp($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $methName = $m->getParam(0); ++ $methName = $methName->scalarval(); ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $server->dmap; ++ $sysCall = 0; ++ } ++ // print "\n"; ++ if (isset($dmap[$methName])) { ++ if ($dmap[$methName]['docstring']) { ++ $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']), ++ 'string'); ++ } else { ++ $r = new XML_RPC_Response(new XML_RPC_Value('', 'string')); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], ++ $XML_RPC_str['introspect_unknown']); ++ } ++ return $r; ++} ++ ++/** ++ * @return void ++ */ ++function XML_RPC_Server_debugmsg($m) ++{ ++ global $XML_RPC_Server_debuginfo; ++ $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n"; ++} ++ ++ ++/** ++ * A server for receiving and replying to XML RPC requests ++ * ++ * ++ * $server = new XML_RPC_Server( ++ * array( ++ * 'isan8' => ++ * array( ++ * 'function' => 'is_8', ++ * 'signature' => ++ * array( ++ * array('boolean', 'int'), ++ * array('boolean', 'int', 'boolean'), ++ * array('boolean', 'string'), ++ * array('boolean', 'string', 'boolean'), ++ * ), ++ * 'docstring' => 'Is the value an 8?' ++ * ), ++ * ), ++ * 1, ++ * 0 ++ * ); ++ * ++ * ++ * @category Web Services ++ * @package XML_RPC ++ * @author Edd Dumbill ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version Release: 1.3.1 ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++class XML_RPC_Server ++{ ++ /** ++ * The dispatch map, listing the methods this server provides. ++ * @var array ++ */ ++ var $dmap = array(); ++ ++ /** ++ * The present response's encoding ++ * @var string ++ * @see XML_RPC_Message::getEncoding() ++ */ ++ var $encoding = ''; ++ ++ /** ++ * Debug mode (0 = off, 1 = on) ++ * @var integer ++ */ ++ var $debug = 0; ++ ++ /** ++ * The response's HTTP headers ++ * @var string ++ */ ++ var $server_headers = ''; ++ ++ /** ++ * The response's XML payload ++ * @var string ++ */ ++ var $server_payload = ''; ++ ++ ++ /** ++ * Constructor for the XML_RPC_Server class ++ * ++ * @param array $dispMap the dispatch map. An associative array ++ * explaining each function. The keys of the main ++ * array are the procedure names used by the ++ * clients. The value is another associative array ++ * that contains up to three elements: ++ * + The 'function' element's value is the name ++ * of the function or method that gets called. ++ * To define a class' method: 'class::method'. ++ * + The 'signature' element (optional) is an ++ * array describing the return values and ++ * parameters ++ * + The 'docstring' element (optional) is a ++ * string describing what the method does ++ * @param int $serviceNow should the HTTP response be sent now? ++ * (1 = yes, 0 = no) ++ * @param int $debug should debug output be displayed? ++ * (1 = yes, 0 = no) ++ * ++ * @return void ++ */ ++ function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) ++ { ++ global $HTTP_RAW_POST_DATA; ++ ++ if ($debug) { ++ $this->debug = 1; ++ } else { ++ $this->debug = 0; ++ } ++ ++ $this->dmap = $dispMap; ++ ++ if ($serviceNow) { ++ $this->service(); ++ } else { ++ $this->createServerPayload(); ++ $this->createServerHeaders(); ++ } ++ } ++ ++ /** ++ * @return string the debug information if debug debug mode is on ++ */ ++ function serializeDebug() ++ { ++ global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA; ++ ++ if ($this->debug) { ++ XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n" ++ . $HTTP_RAW_POST_DATA ++ . "\n" . '^^^ END POST DATA ^^^'); ++ } ++ ++ if ($XML_RPC_Server_debuginfo != '') { ++ return "\n"; ++ } else { ++ return ''; ++ } ++ } ++ ++ /** ++ * Sends the response ++ * ++ * The encoding and content-type are determined by ++ * XML_RPC_Message::getEncoding() ++ * ++ * @return void ++ * ++ * @uses XML_RPC_Server::createServerPayload(), ++ * XML_RPC_Server::createServerHeaders() ++ */ ++ function service() ++ { ++ $this->createServerPayload(); ++ $this->createServerHeaders(); ++ header($this->server_headers); ++ print $this->server_payload; ++ } ++ ++ /** ++ * Generates the payload and puts it in the $server_payload property ++ * ++ * @return void ++ * ++ * @uses XML_RPC_Server::parseRequest(), XML_RPC_Server::$encoding, ++ * XML_RPC_Response::serialize(), XML_RPC_Server::serializeDebug() ++ */ ++ function createServerPayload() ++ { ++ $r = $this->parseRequest(); ++ $this->server_payload = 'encoding . '"?>' . "\n" ++ . $this->serializeDebug() ++ . $r->serialize(); ++ } ++ ++ /** ++ * Determines the HTTP headers and puts them in the $server_headers ++ * property ++ * ++ * @return boolean TRUE if okay, FALSE if $server_payload isn't set. ++ * ++ * @uses XML_RPC_Server::createServerPayload(), ++ * XML_RPC_Server::$server_headers ++ */ ++ function createServerHeaders() ++ { ++ if (!$this->server_payload) { ++ return false; ++ } ++ $this->server_headers = 'Content-Length: ' ++ . strlen($this->server_payload) . "\r\n" ++ . 'Content-Type: text/xml;' ++ . ' charset=' . $this->encoding; ++ return true; ++ } ++ ++ /** ++ * @return array ++ */ ++ function verifySignature($in, $sig) ++ { ++ for ($i = 0; $i < sizeof($sig); $i++) { ++ // check each possible signature in turn ++ $cursig = $sig[$i]; ++ if (sizeof($cursig) == $in->getNumParams() + 1) { ++ $itsOK = 1; ++ for ($n = 0; $n < $in->getNumParams(); $n++) { ++ $p = $in->getParam($n); ++ // print "\n"; ++ if ($p->kindOf() == 'scalar') { ++ $pt = $p->scalartyp(); ++ } else { ++ $pt = $p->kindOf(); ++ } ++ // $n+1 as first type of sig is return type ++ if ($pt != $cursig[$n+1]) { ++ $itsOK = 0; ++ $pno = $n+1; ++ $wanted = $cursig[$n+1]; ++ $got = $pt; ++ break; ++ } ++ } ++ if ($itsOK) { ++ return array(1); ++ } ++ } ++ } ++ if (isset($wanted)) { ++ return array(0, "Wanted ${wanted}, got ${got} at param ${pno}"); ++ } else { ++ $allowed = array(); ++ foreach ($sig as $val) { ++ end($val); ++ $allowed[] = key($val); ++ } ++ $allowed = array_unique($allowed); ++ $last = count($allowed) - 1; ++ if ($last > 0) { ++ $allowed[$last] = 'or ' . $allowed[$last]; ++ } ++ return array(0, ++ 'Signature permits ' . implode(', ', $allowed) ++ . ' parameters but the request had ' ++ . $in->getNumParams()); ++ } ++ } ++ ++ /** ++ * @return object a new XML_RPC_Response object ++ * ++ * @uses XML_RPC_Message::getEncoding(), XML_RPC_Server::$encoding ++ */ ++ function parseRequest($data = '') ++ { ++ global $XML_RPC_xh, $HTTP_RAW_POST_DATA, ++ $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml, ++ $XML_RPC_defencoding, $XML_RPC_Server_dmap; ++ ++ if ($data == '') { ++ $data = $HTTP_RAW_POST_DATA; ++ } ++ ++ $this->encoding = XML_RPC_Message::getEncoding($data); ++ $parser_resource = xml_parser_create($this->encoding); ++ $parser = (int) $parser_resource; ++ ++ $XML_RPC_xh[$parser] = array(); ++ $XML_RPC_xh[$parser]['st'] = ''; ++ $XML_RPC_xh[$parser]['cm'] = 0; ++ $XML_RPC_xh[$parser]['isf'] = 0; ++ $XML_RPC_xh[$parser]['params'] = array(); ++ $XML_RPC_xh[$parser]['method'] = ''; ++ ++ $plist = ''; ++ ++ // decompose incoming XML into request structure ++ ++ xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true); ++ xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee'); ++ xml_set_character_data_handler($parser_resource, 'XML_RPC_cd'); ++ if (!xml_parse($parser_resource, $data, 1)) { ++ // return XML error as a faultCode ++ $r = new XML_RPC_Response(0, ++ $XML_RPC_errxml+xml_get_error_code($parser_resource), ++ sprintf('XML error: %s at line %d', ++ xml_error_string(xml_get_error_code($parser_resource)), ++ xml_get_current_line_number($parser_resource))); ++ xml_parser_free($parser_resource); ++ } else { ++ xml_parser_free($parser_resource); ++ $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']); ++ // now add parameters in ++ for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) { ++ // print '\n"; ++ $plist .= "$i - " . $XML_RPC_xh[$parser]['params'][$i] . " \n"; ++ eval('$m->addParam(' . $XML_RPC_xh[$parser]['params'][$i] . ');'); ++ } ++ XML_RPC_Server_debugmsg($plist); ++ ++ // now to deal with the method ++ $methName = $XML_RPC_xh[$parser]['method']; ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $this->dmap; ++ $sysCall = 0; ++ } ++ ++ if (isset($dmap[$methName]['function']) ++ && is_string($dmap[$methName]['function']) ++ && strpos($dmap[$methName]['function'], '::') !== false) ++ { ++ $dmap[$methName]['function'] = ++ explode('::', $dmap[$methName]['function']); ++ } ++ ++ if (isset($dmap[$methName]['function']) ++ && is_callable($dmap[$methName]['function'])) ++ { ++ // dispatch if exists ++ if (isset($dmap[$methName]['signature'])) { ++ $sr = $this->verifySignature($m, ++ $dmap[$methName]['signature'] ); ++ } ++ if (!isset($dmap[$methName]['signature']) || $sr[0]) { ++ // if no signature or correct signature ++ if ($sysCall) { ++ $r = call_user_func($dmap[$methName]['function'], $this, $m); ++ } else { ++ $r = call_user_func($dmap[$methName]['function'], $m); ++ } ++ if (!is_a($r, 'XML_RPC_Response')) { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['not_response_object'], ++ $XML_RPC_str['not_response_object']); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], ++ $XML_RPC_str['incorrect_params'] ++ . ': ' . $sr[1]); ++ } ++ } else { ++ // else prepare error response ++ $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'], ++ $XML_RPC_str['unknown_method']); ++ } ++ } ++ return $r; ++ } ++ ++ /** ++ * Echos back the input packet as a string value ++ * ++ * @return void ++ * ++ * Useful for debugging. ++ */ ++ function echoInput() ++ { ++ global $HTTP_RAW_POST_DATA; ++ ++ $r = new XML_RPC_Response(0); ++ $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); ++ print $r->serialize(); ++ } ++} ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * c-hanging-comment-ender-p: nil ++ * End: ++ */ ++ ++?> ++package.xml100644 1750 144 22507 10260516576 6427 ++ ++ ++ XML_RPC ++ PHP implementation of the XML-RPC protocol ++ A PEAR-ified version of Useful Inc's XML-RPC for PHP. ++ ++It has support for HTTP/HTTPS transport, proxies and authentication. ++ ++ ++ ++ ssb ++ Stig Bakken ++ stig@php.net ++ lead ++ ++ ++ danielc ++ Daniel Convissor ++ danielc@php.net ++ lead ++ ++ ++ ++ 1.3.1 ++ 2005-06-29 ++ PHP License ++ stable ++ * Security fix. Update highly recommended! ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 1.3.0RC3 ++ 2005-05-10 ++ beta ++ * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. ++* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. ++* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. ++* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. ++* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). ++* Use <br /> instead of <br> in XML_RPC_Value::dump(). ++ ++ ++ ++ 1.3.0RC2 ++ 2005-05-05 ++ beta ++ * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. ++* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. ++* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. ++* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. ++ ++ ++ ++ 1.3.0RC1 ++ 2005-04-07 ++ beta ++ * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. ++* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. ++* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. ++* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. ++* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. ++* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. ++ ++ ++ ++ 1.2.2 ++ 2005-03-07 ++ stable ++ * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. ++ ++ ++ ++ 1.2.1 ++ 2005-03-01 ++ stable ++ * Add isset() check before examining the dispatch map. Bug 3658. ++ ++ ++ ++ 1.2.0 ++ 2005-02-27 ++ stable ++ * Provide the "stable" release. ++* Add package2.xml for compatibility with PEAR 1.4.0. ++* For changes since 1.1.0, see the changelogs for the various RC releases. ++ ++ ++ ++ 1.2.0RC7 ++ 2005-02-22 ++ beta ++ * Add the setSendEncoding() method and $send_encoding ++ property to XML_RPC_Message. Request 3537. ++* Allow class methods to be mapped using either syntax: ++ 'function' => 'hello::sayHello', ++ or ++ 'function' => array('hello', 'sayhello'), ++ Bug 3363. ++* Use 8192 instead of 32768 for bytes in fread() ++ in parseResponseFile(). Bug 3340. ++ ++ ++ ++ 1.2.0RC6 ++ 2005-01-25 ++ beta ++ * Don't put the protocol in the Host field of the POST data. (danielc) ++ ++ ++ ++ 1.2.0RC5 ++ 2005-01-24 ++ beta ++ * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. ++ ++ ++ ++ 1.2.0RC4 ++ 2005-01-24 ++ beta ++ * When a connection attempt fails, have the method return 0. (danielc) ++* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) ++* Add tests for setting the client properties. (danielc) ++* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) ++* Bundle the tests with the package. (danielc) ++ ++ ++ ++ 1.2.0RC3 ++ 2005-01-19 ++ beta ++ * ssl uses port 443, not 445. ++ ++ ++ ++ 1.2.0RC2 ++ 2005-01-11 ++ beta ++ * Handle ssl:// in the $server string. (danielc) ++* Also default to port 445 for ssl:// requests as well. (danielc) ++* Enhance debugging in the server. (danielc) ++ ++ ++ ++ 1.2.0RC1 ++ 2004-12-30 ++ beta ++ * Make things work with SSL. Bug 2489. (nkukard lbsd net) ++* Allow array function callbacks (Matt Kane) ++* Some minor speed-ups (Matt Kane) ++* Add Dump.php to the package (Christian Weiske) ++* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) ++* Silence fsockopen() errors. Bug 1714. (danielc) ++* Encode empty arrays as an array. Bug 1493. (danielc) ++* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) ++* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) ++* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) ++* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) ++* Allow raiseError() to be called statically. (danielc) ++* Stop double escaping of character entities. Bug 987. (danielc) ++ NOTICE: the following have been removed: ++ * XML_RPC_dh() ++ * $GLOBALS['XML_RPC_entities'] ++ * XML_RPC_entity_decode() ++ * XML_RPC_lookup_entity() ++* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) ++ ++ ++ ++ 1.1.0 ++ 2004-03-15 ++ stable ++ * Added support for sequential arrays to XML_RPC_encode() (mroch) ++* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) ++* Remove "require_once 'PEAR.php'", include only when needed to raise an error ++* Replace echo and error_log() with raiseError() (mroch) ++* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) ++* be tolerant of junk after methodResponse (Luca Mariano, mroch) ++* Silent notice even in the error log (pierre) ++* fix include of shared xml extension on win32 (pierre) ++ ++ ++ ++ 1.0.4 ++ 2002-10-02 ++ stable ++ * added HTTP proxy authorization support (thanks to Arnaud Limbourg) ++ ++ ++ ++ 1.0.3 ++ 2002-05-19 ++ stable ++ * fix bug when parsing responses with boolean types ++ ++ ++ ++ 1.0.2 ++ 2002-04-16 ++ stable ++ * E_ALL fixes ++* fix HTTP response header parsing ++ ++ ++ ++ 1.0.1 ++ 2001-09-25 ++ stable ++ This is a PEAR-ified version of Useful Inc's 1.0.1 release. ++Includes an urgent security fix identified by Dan Libby <dan@libby.com>. ++ ++ ++ ++ ++ +\ Kein Zeilenumbruch am Dateiende. +diff -Naur php-4.3.11/php.ini-dist hardening-patch-4.3.11-0.3.2/php.ini-dist +--- php-4.3.11/php.ini-dist 2005-02-14 09:26:10.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/php.ini-dist 2005-07-09 08:53:02.504357944 +0200 +@@ -1109,6 +1109,177 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Naur php-4.3.11/php.ini-recommended hardening-patch-4.3.11-0.3.2/php.ini-recommended +--- php-4.3.11/php.ini-recommended 2005-02-14 09:26:10.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/php.ini-recommended 2005-07-09 08:53:02.505357792 +0200 +@@ -1107,6 +1107,177 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Naur php-4.3.11/README.input_filter hardening-patch-4.3.11-0.3.2/README.input_filter +--- php-4.3.11/README.input_filter 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/README.input_filter 2005-07-09 08:53:02.506357640 +0200 +@@ -0,0 +1,193 @@ ++Input Filter Support ported from PHP 5 ++-------------------------------------- ++ ++XSS (Cross Site Scripting) hacks are becoming more and more prevalent, ++and can be quite difficult to prevent. Whenever you accept user data ++and somehow display this data back to users, you are likely vulnerable ++to XSS hacks. ++ ++The Input Filter support in PHP 5 is aimed at providing the framework ++through which a company-wide or site-wide security policy can be ++enforced. It is implemented as a SAPI hook and is called from the ++treat_data and post handler functions. To implement your own security ++policy you will need to write a standard PHP extension. ++ ++A simple implementation might look like the following. This stores the ++original raw user data and adds a my_get_raw() function while the normal ++$_POST, $_GET and $_COOKIE arrays are only populated with stripped ++data. In this simple example all I am doing is calling strip_tags() on ++the data. If register_globals is turned on, the default globals that ++are created will be stripped ($foo) while a $RAW_foo is created with the ++original user input. ++ ++ZEND_BEGIN_MODULE_GLOBALS(my_input_filter) ++ zval *post_array; ++ zval *get_array; ++ zval *cookie_array; ++ZEND_END_MODULE_GLOBALS(my_input_filter) ++ ++#ifdef ZTS ++#define IF_G(v) TSRMG(my_input_filter_globals_id, zend_my_input_filter_globals *, v) ++#else ++#define IF_G(v) (my_input_filter_globals.v) ++#endif ++ ++ZEND_DECLARE_MODULE_GLOBALS(my_input_filter) ++ ++function_entry my_input_filter_functions[] = { ++ PHP_FE(my_get_raw, NULL) ++ {NULL, NULL, NULL} ++}; ++ ++zend_module_entry my_input_filter_module_entry = { ++ STANDARD_MODULE_HEADER, ++ "my_input_filter", ++ my_input_filter_functions, ++ PHP_MINIT(my_input_filter), ++ PHP_MSHUTDOWN(my_input_filter), ++ NULL, ++ PHP_RSHUTDOWN(my_input_filter), ++ PHP_MINFO(my_input_filter), ++ "0.1", ++ STANDARD_MODULE_PROPERTIES ++}; ++ ++PHP_MINIT_FUNCTION(my_input_filter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(my_input_filter, php_my_input_filter_init_globals, NULL); ++ ++ REGISTER_LONG_CONSTANT("POST", PARSE_POST, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("GET", PARSE_GET, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("COOKIE", PARSE_COOKIE, CONST_CS | CONST_PERSISTENT); ++ ++ sapi_register_input_filter(my_sapi_input_filter); ++ return SUCCESS; ++} ++ ++PHP_RSHUTDOWN_FUNCTION(my_input_filter) ++{ ++ if(IF_G(get_array)) { ++ zval_ptr_dtor(&IF_G(get_array)); ++ IF_G(get_array) = NULL; ++ } ++ if(IF_G(post_array)) { ++ zval_ptr_dtor(&IF_G(post_array)); ++ IF_G(post_array) = NULL; ++ } ++ if(IF_G(cookie_array)) { ++ zval_ptr_dtor(&IF_G(cookie_array)); ++ IF_G(cookie_array) = NULL; ++ } ++ return SUCCESS; ++} ++ ++PHP_MINFO_FUNCTION(my_input_filter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_row( 2, "My Input Filter Support", "enabled" ); ++ php_info_print_table_row( 2, "Revision", "$Revision: 1.1 $"); ++ php_info_print_table_end(); ++} ++ ++/* The filter handler. If you return 1 from it, then PHP also registers the ++ * (modified) variable. Returning 0 prevents PHP from registering the variable; ++ * you can use this if your filter already registers the variable under a ++ * different name, or if you just don't want the variable registered at all. */ ++SAPI_INPUT_FILTER_FUNC(my_sapi_input_filter) ++{ ++ zval new_var; ++ zval *array_ptr = NULL; ++ char *raw_var; ++ int var_len; ++ ++ assert(*val != NULL); ++ ++ switch(arg) { ++ case PARSE_GET: ++ if(!IF_G(get_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(get_array) = array_ptr; ++ break; ++ case PARSE_POST: ++ if(!IF_G(post_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(post_array) = array_ptr; ++ break; ++ case PARSE_COOKIE: ++ if(!IF_G(cookie_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(cookie_array) = array_ptr; ++ break; ++ } ++ Z_STRLEN(new_var) = val_len; ++ Z_STRVAL(new_var) = estrndup(*val, val_len); ++ Z_TYPE(new_var) = IS_STRING; ++ ++ var_len = strlen(var); ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ ++ php_register_variable_ex(raw_var, &new_var, array_ptr TSRMLS_DC); ++ ++ php_strip_tags(*val, val_len, NULL, NULL, 0); ++ ++ *new_val_len = strlen(*val); ++ return 1; ++} ++ ++PHP_FUNCTION(my_get_raw) ++{ ++ long arg; ++ char *var; ++ int var_len; ++ zval **tmp; ++ zval *array_ptr = NULL; ++ HashTable *hash_ptr; ++ char *raw_var; ++ ++ if(zend_parse_parameters(2 TSRMLS_CC, "ls", &arg, &var, &var_len) == FAILURE) { ++ return; ++ } ++ ++ switch(arg) { ++ case PARSE_GET: ++ array_ptr = IF_G(get_array); ++ break; ++ case PARSE_POST: ++ array_ptr = IF_G(post_array); ++ break; ++ case PARSE_COOKIE: ++ array_ptr = IF_G(post_array); ++ break; ++ } ++ ++ if(!array_ptr) RETURN_FALSE; ++ ++ /* ++ * I'm changing the variable name here because when running with register_globals on, ++ * the variable will end up in the global symbol table ++ */ ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ hash_ptr = HASH_OF(array_ptr); ++ ++ if(zend_hash_find(hash_ptr, raw_var, var_len+5, (void **)&tmp) == SUCCESS) { ++ *return_value = **tmp; ++ zval_copy_ctor(return_value); ++ } else { ++ RETVAL_FALSE; ++ } ++ efree(raw_var); ++} ++ +diff -Naur php-4.3.11/sapi/apache/mod_php4.c hardening-patch-4.3.11-0.3.2/sapi/apache/mod_php4.c +--- php-4.3.11/sapi/apache/mod_php4.c 2004-07-21 18:25:28.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/sapi/apache/mod_php4.c 2005-07-09 08:53:02.507357488 +0200 +@@ -446,7 +446,7 @@ + sapi_apache_get_fd, + sapi_apache_force_http_10, + sapi_apache_get_target_uid, +- sapi_apache_get_target_gid ++ sapi_apache_get_target_gid, + }; + /* }}} */ + +@@ -892,7 +892,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component("PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component("PHP/" PHP_VERSION); ++#endif + } + } + #endif +diff -Naur php-4.3.11/sapi/apache2filter/sapi_apache2.c hardening-patch-4.3.11-0.3.2/sapi/apache2filter/sapi_apache2.c +--- php-4.3.11/sapi/apache2filter/sapi_apache2.c 2005-01-07 07:28:36.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/sapi/apache2filter/sapi_apache2.c 2005-07-09 08:53:02.507357488 +0200 +@@ -563,7 +563,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Naur php-4.3.11/sapi/apache2handler/sapi_apache2.c hardening-patch-4.3.11-0.3.2/sapi/apache2handler/sapi_apache2.c +--- php-4.3.11/sapi/apache2handler/sapi_apache2.c 2005-03-10 12:39:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/sapi/apache2handler/sapi_apache2.c 2005-07-09 08:53:02.508357336 +0200 +@@ -345,7 +345,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Naur php-4.3.11/sapi/cgi/cgi_main.c hardening-patch-4.3.11-0.3.2/sapi/cgi/cgi_main.c +--- php-4.3.11/sapi/cgi/cgi_main.c 2005-02-11 03:12:30.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/sapi/cgi/cgi_main.c 2005-07-09 08:53:02.509357184 +0200 +@@ -1435,11 +1435,19 @@ + SG(headers_sent) = 1; + SG(request_info).no_headers = 1; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit(1); + break; +diff -Naur php-4.3.11/sapi/cli/php_cli.c hardening-patch-4.3.11-0.3.2/sapi/cli/php_cli.c +--- php-4.3.11/sapi/cli/php_cli.c 2005-03-22 16:09:36.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/sapi/cli/php_cli.c 2005-07-09 08:53:02.510357032 +0200 +@@ -652,11 +652,19 @@ + if (php_request_startup(TSRMLS_C)==FAILURE) { + goto err; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit_status=1; + goto out; +diff -Naur php-4.3.11/TSRM/TSRM.h hardening-patch-4.3.11-0.3.2/TSRM/TSRM.h +--- php-4.3.11/TSRM/TSRM.h 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/TSRM/TSRM.h 2005-07-09 08:53:02.510357032 +0200 +@@ -33,6 +33,13 @@ + # define TSRM_API + #endif + ++#if HARDENING_PATCH ++# if HAVE_REALPATH ++# undef realpath ++# define realpath php_realpath ++# endif ++#endif ++ + /* Only compile multi-threading functions if we're in ZTS mode */ + #ifdef ZTS + +@@ -90,6 +97,7 @@ + + #define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts + ++ + #ifdef __cplusplus + extern "C" { + #endif +diff -Naur php-4.3.11/TSRM/tsrm_virtual_cwd.c hardening-patch-4.3.11-0.3.2/TSRM/tsrm_virtual_cwd.c +--- php-4.3.11/TSRM/tsrm_virtual_cwd.c 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/TSRM/tsrm_virtual_cwd.c 2005-07-09 08:53:02.511356880 +0200 +@@ -192,6 +192,165 @@ + return p; + } + ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved) ++{ ++ struct stat sb; ++ char *p, *q, *s; ++ size_t left_len, resolved_len; ++ unsigned symlinks; ++ int serrno, slen; ++ int is_dir = 1; ++ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; ++ ++ serrno = errno; ++ symlinks = 0; ++ if (path[0] == '/') { ++ resolved[0] = '/'; ++ resolved[1] = '\0'; ++ if (path[1] == '\0') ++ return (resolved); ++ resolved_len = 1; ++ left_len = strlcpy(left, path + 1, sizeof(left)); ++ } else { ++ if (getcwd(resolved, PATH_MAX) == NULL) { ++ strlcpy(resolved, ".", PATH_MAX); ++ return (NULL); ++ } ++ resolved_len = strlen(resolved); ++ left_len = strlcpy(left, path, sizeof(left)); ++ } ++ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ ++ /* ++ * Iterate over path components in `left'. ++ */ ++ while (left_len != 0) { ++ /* ++ * Extract the next path component and adjust `left' ++ * and its length. ++ */ ++ p = strchr(left, '/'); ++ s = p ? p : left + left_len; ++ if (s - left >= sizeof(next_token)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ memcpy(next_token, left, s - left); ++ next_token[s - left] = '\0'; ++ left_len -= s - left; ++ if (p != NULL) ++ memmove(left, s + 1, left_len + 1); ++ if (resolved[resolved_len - 1] != '/') { ++ if (resolved_len + 1 >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ resolved[resolved_len++] = '/'; ++ resolved[resolved_len] = '\0'; ++ } ++ if (next_token[0] == '\0') ++ continue; ++ else if (strcmp(next_token, ".") == 0) ++ continue; ++ else if (strcmp(next_token, "..") == 0) { ++ /* ++ * Strip the last path component except when we have ++ * single "/" ++ */ ++ if (!is_dir) { ++ errno = ENOENT; ++ return (NULL); ++ } ++ if (resolved_len > 1) { ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ continue; ++ } ++ ++ /* ++ * Append the next path component and lstat() it. If ++ * lstat() fails we still can return successfully if ++ * there are no more path components left. ++ */ ++ resolved_len = strlcat(resolved, next_token, PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ if (lstat(resolved, &sb) != 0) { ++ if (errno == ENOENT && p == NULL) { ++ errno = serrno; ++ return (resolved); ++ } ++ return (NULL); ++ } ++ if (S_ISLNK(sb.st_mode)) { ++ if (symlinks++ > MAXSYMLINKS) { ++ errno = ELOOP; ++ return (NULL); ++ } ++ slen = readlink(resolved, symlink, sizeof(symlink) - 1); ++ if (slen < 0) ++ return (NULL); ++ symlink[slen] = '\0'; ++ if (symlink[0] == '/') { ++ resolved[1] = 0; ++ resolved_len = 1; ++ } else if (resolved_len > 1) { ++ /* Strip the last path component. */ ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ ++ /* ++ * If there are any path components left, then ++ * append them to symlink. The result is placed ++ * in `left'. ++ */ ++ if (p != NULL) { ++ if (symlink[slen - 1] != '/') { ++ if (slen + 1 >= sizeof(symlink)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ symlink[slen] = '/'; ++ symlink[slen + 1] = 0; ++ } ++ left_len = strlcat(symlink, left, sizeof(left)); ++ if (left_len >= sizeof(left)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ } ++ left_len = strlcpy(left, symlink, sizeof(left)); ++ } else { ++ if (S_ISDIR(sb.st_mode)) { ++ is_dir = 1; ++ } else { ++ is_dir = 0; ++ } ++ } ++ } ++ ++ /* ++ * Remove trailing slash except when the resolved pathname ++ * is a single "/". ++ */ ++ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') ++ resolved[resolved_len - 1] = '\0'; ++ return (resolved); ++} ++#endif ++ + CWD_API void virtual_cwd_startup(void) + { + char cwd[MAXPATHLEN]; +@@ -314,8 +473,7 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now +- return 1; */ ++ return 1; + } + } + } else { /* Concat current directory with relative path and then run realpath() on it */ +@@ -341,9 +499,8 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now + free(tmp); +- return 1; */ ++ return 1; + } + } + free(tmp); +diff -Naur php-4.3.11/TSRM/tsrm_virtual_cwd.h hardening-patch-4.3.11-0.3.2/TSRM/tsrm_virtual_cwd.h +--- php-4.3.11/TSRM/tsrm_virtual_cwd.h 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/TSRM/tsrm_virtual_cwd.h 2005-07-09 08:53:02.511356880 +0200 +@@ -128,6 +128,22 @@ + + typedef int (*verify_path_func)(const cwd_state *); + ++#ifndef HAVE_STRLCPY ++CWD_API size_t php_strlcpy(char *dst, const char *src, size_t siz); ++#undef strlcpy ++#define strlcpy php_strlcpy ++#endif ++ ++#ifndef HAVE_STRLCAT ++CWD_API size_t php_strlcat(char *dst, const char *src, size_t siz); ++#undef strlcat ++#define strlcat php_strlcat ++#endif ++ ++ ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved); ++#endif + CWD_API void virtual_cwd_startup(void); + CWD_API void virtual_cwd_shutdown(void); + CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC); +diff -Naur php-4.3.11/Zend/zend_alloc.c hardening-patch-4.3.11-0.3.2/Zend/zend_alloc.c +--- php-4.3.11/Zend/zend_alloc.c 2004-08-27 18:51:25.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_alloc.c 2005-07-09 08:53:02.512356728 +0200 +@@ -56,6 +56,11 @@ + # define END_MAGIC_SIZE 0 + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++# define CANARY_SIZE sizeof(unsigned int) ++#else ++# define CANARY_SIZE 0 ++#endif + + # if MEMORY_LIMIT + # if ZEND_DEBUG +@@ -95,9 +100,17 @@ + if (p==AG(head)) { \ + AG(head) = p->pNext; \ + } else { \ ++ if (p != p->pLast->pNext) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pLast->pNext = p->pNext; \ + } \ + if (p->pNext) { \ ++ if (p != p->pNext->pLast) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pNext->pLast = p->pLast; \ + } + +@@ -129,6 +142,12 @@ + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (size > LONG_MAX - sizeof(zend_mem_header) - MEM_HEADER_PADDING - END_MAGIC_SIZE - CANARY_SIZE) { ++ zend_security_log(S_MEMORY, "emalloc() - requested size would result in integer overflow"); ++ exit(1); ++ } ++#endif + CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size); + + if (!ZEND_DISABLE_MEMORY_CACHE && (CACHE_INDEX < MAX_CACHED_MEMORY) && (AG(cache_count)[CACHE_INDEX] > 0)) { +@@ -146,6 +165,10 @@ + AG(cache_stats)[CACHE_INDEX][1]++; + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->cached = 0; + p->size = size; + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); +@@ -161,7 +184,7 @@ + AG(allocated_memory_peak) = AG(allocated_memory); + } + #endif +- p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE + CANARY_SIZE); + } + + HANDLE_BLOCK_INTERRUPTIONS(); +@@ -191,7 +214,10 @@ + # endif + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif +- ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); + } +@@ -218,17 +244,33 @@ + return emalloc_rel(lval + offset); + } + } +- ++ ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by safe_emalloc()"); ++#endif + zend_error(E_ERROR, "Possible integer overflow in memory allocation (%ld * %ld + %ld)", nmemb, size, offset); + return 0; + } + + ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int *canary_2; ++#endif + zend_mem_header *p = (zend_mem_header *) ((char *)ptr - sizeof(zend_mem_header) - MEM_HEADER_PADDING); + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENING_PATCH_MM_PROTECT ++ canary_2 = (unsigned int *)(((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE); ++ if (p->canary != HG(canary_1) || *canary_2 != HG(canary_2)) { ++ zend_security_log(S_MEMORY, "canary mismatch on efree() - heap overflow or double efree detected"); ++ exit(1); ++ } ++ /* to catch double efree()s */ ++ *canary_2 = p->canary = 0; ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + tsrm_error(TSRM_ERROR_LEVEL_ERROR, "Memory block allocated at %s:(%d) on thread %x freed at %s:(%d) on thread %x, ignoring", +@@ -273,6 +315,9 @@ + size_t _size = nmemb * size; + + if (nmemb && (_size/nmemb!=size)) { ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by ecalloc()"); ++#endif + fprintf(stderr,"FATAL: ecalloc(): Unable to allocate %ld * %ld bytes\n", (long) nmemb, (long) size); + #if ZEND_DEBUG && HAVE_KILL && HAVE_GETPID + kill(getpid(), SIGSEGV); +@@ -292,6 +337,9 @@ + + ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p; + zend_mem_header *orig; + DECLARE_CACHE_VARS(); +@@ -303,6 +351,14 @@ + + p = orig = (zend_mem_header *) ((char *)ptr-sizeof(zend_mem_header)-MEM_HEADER_PADDING); + ++#if HARDENING_PATCH_MM_PROTECT ++ canary_2 = *(unsigned int *)(((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE); ++ if (p->canary != HG(canary_1) || canary_2 != HG(canary_2)) { ++ zend_security_log(S_MEMORY, "canary mismatch on erealloc() - heap overflow detected"); ++ exit(1); ++ } ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + void *new_p; +@@ -326,7 +382,7 @@ + } + #endif + REMOVE_POINTER_FROM_LIST(p); +- p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE+CANARY_SIZE); + if (!p) { + if (!allow_failure) { + fprintf(stderr,"FATAL: erealloc(): Unable to allocate %ld bytes\n", (long) size); +@@ -348,6 +404,9 @@ + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->size = size; + + HANDLE_UNBLOCK_INTERRUPTIONS(); +@@ -423,6 +482,10 @@ + { + AG(head) = NULL; + ++#if HARDENING_PATCH_MM_PROTECT ++ HG(canary_1) = zend_canary(); ++ HG(canary_2) = zend_canary(); ++#endif + #if MEMORY_LIMIT + AG(memory_limit) = 1<<30; /* ridiculous limit, effectively no limit */ + AG(allocated_memory) = 0; +diff -Naur php-4.3.11/Zend/zend_alloc.h hardening-patch-4.3.11-0.3.2/Zend/zend_alloc.h +--- php-4.3.11/Zend/zend_alloc.h 2004-08-11 08:10:46.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_alloc.h 2005-07-09 08:53:02.513356576 +0200 +@@ -32,6 +32,9 @@ + #define MEM_BLOCK_CACHED_MAGIC 0xFB8277DCL + + typedef struct _zend_mem_header { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary; ++#endif + #if ZEND_DEBUG + long magic; + char *filename; +diff -Naur php-4.3.11/Zend/zend_builtin_functions.c hardening-patch-4.3.11-0.3.2/Zend/zend_builtin_functions.c +--- php-4.3.11/Zend/zend_builtin_functions.c 2004-12-27 20:28:35.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_builtin_functions.c 2005-07-09 08:53:02.514356424 +0200 +@@ -49,6 +49,9 @@ + static ZEND_FUNCTION(crash); + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++static ZEND_FUNCTION(heap_overflow); ++#endif + static ZEND_FUNCTION(get_included_files); + static ZEND_FUNCTION(is_subclass_of); + static ZEND_FUNCTION(is_a); +@@ -101,6 +104,9 @@ + ZEND_FE(crash, NULL) + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ ZEND_FE(heap_overflow, NULL) ++#endif + ZEND_FE(get_included_files, NULL) + ZEND_FALIAS(get_required_files, get_included_files, NULL) + ZEND_FE(is_subclass_of, NULL) +@@ -805,6 +811,19 @@ + + #endif /* ZEND_DEBUG */ + ++ ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ZEND_FUNCTION(heap_overflow) ++{ ++ char *nowhere = emalloc(10); ++ ++ memcpy(nowhere, "something1234567890", sizeof("something1234567890")); ++ ++ efree(nowhere); ++} ++#endif ++ ++ + /* {{{ proto array get_included_files(void) + Returns an array with the file names that were include_once()'d */ + ZEND_FUNCTION(get_included_files) +diff -Naur php-4.3.11/Zend/zend.c hardening-patch-4.3.11-0.3.2/Zend/zend.c +--- php-4.3.11/Zend/zend.c 2005-01-22 21:36:34.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend.c 2005-07-09 08:53:02.514356424 +0200 +@@ -53,6 +53,12 @@ + ZEND_API void (*zend_unblock_interruptions)(void); + ZEND_API void (*zend_ticks_function)(int ticks); + ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); ++#if HARDENING_PATCH ++ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + + void (*zend_on_timeout)(int seconds TSRMLS_DC); + +@@ -70,9 +76,80 @@ + return SUCCESS; + } + ++#if HARDENING_PATCH ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog) = S_ALL & ~S_SQL | S_MEMORY; ++ } else { ++ EG(hphp_log_syslog) = atoi(new_value) | S_MEMORY; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_facility) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_facility) = LOG_USER; ++ } else { ++ EG(hphp_log_syslog_facility) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_priority) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_priority) = LOG_ALERT; ++ } else { ++ EG(hphp_log_syslog_priority) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_sapi) ++{ ++ if (!new_value) { ++ EG(hphp_log_sapi) = S_ALL & ~S_SQL; ++ } else { ++ EG(hphp_log_sapi) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_script) ++{ ++ if (!new_value) { ++ EG(hphp_log_script) = S_ALL & ~S_MEMORY; ++ } else { ++ EG(hphp_log_script) = atoi(new_value) & ~S_MEMORY; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_scriptname) ++{ ++ if (!new_value) { ++ EG(hphp_log_scriptname) = NULL; ++ } else { ++ if (EG(hphp_log_scriptname)) { ++ pefree(EG(hphp_log_scriptname),1); ++ } ++ EG(hphp_log_scriptname) = pestrdup(new_value,1); ++ } ++ return SUCCESS; ++} ++#endif + + ZEND_INI_BEGIN() + ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) ++#if HARDENING_PATCH ++ ZEND_INI_ENTRY("hphp.log.syslog", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog) ++ ZEND_INI_ENTRY("hphp.log.syslog.facility", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_facility) ++ ZEND_INI_ENTRY("hphp.log.syslog.priority", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_priority) ++ ZEND_INI_ENTRY("hphp.log.sapi", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_sapi) ++ ZEND_INI_ENTRY("hphp.log.script", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_script) ++ ZEND_INI_ENTRY("hphp.log.script.name", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_scriptname) ++ STD_ZEND_INI_BOOLEAN("hphp.log.use-x-forwarded-for", "0", ZEND_INI_SYSTEM, OnUpdateBool, hphp_log_use_x_forwarded_for, zend_executor_globals, executor_globals) ++ STD_ZEND_INI_ENTRY("hphp.executor.max_depth", "0", ZEND_INI_PERDIR, OnUpdateLong, hphp_executor_max_depth, zend_executor_globals, executor_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.sql.bailout_on_error", "0", ZEND_INI_PERDIR, OnUpdateBool, hphp_sql_bailout_on_error, hardened_globals_struct, hardened_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.multiheader", "0", ZEND_INI_PERDIR, OnUpdateBool, hphp_multiheader, hardened_globals_struct, hardened_globals) ++#endif + ZEND_INI_END() + + +@@ -354,6 +431,7 @@ + zend_init_rsrc_plist(TSRMLS_C); + EG(lambda_count)=0; + EG(user_error_handler) = NULL; ++ EG(in_code_type) = 0; + EG(in_execution) = 0; + EG(current_execute_data) = NULL; + } +@@ -420,6 +498,14 @@ + extern zend_scanner_globals language_scanner_globals; + #endif + ++ /* Set up Hardening-Patch utility functions first */ ++#if HARDENING_PATCH ++ zend_security_log = utility_functions->security_log_function; ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ zend_is_valid_include = utility_functions->is_valid_include; ++#endif ++ + #ifdef ZTS + ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); + #else +@@ -623,6 +709,7 @@ + } + CG(unclean_shutdown) = 1; + CG(in_compilation) = EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(current_execute_data) = NULL; + longjmp(EG(bailout), FAILURE); + } +diff -Naur php-4.3.11/Zend/zend_canary.c hardening-patch-4.3.11-0.3.2/Zend/zend_canary.c +--- php-4.3.11/Zend/zend_canary.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_canary.c 2005-07-09 08:53:02.515356272 +0200 +@@ -0,0 +1,58 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: zend_canary.c,v 1.1 2004/11/26 12:45:41 ionic Exp $ */ ++ ++#include "zend.h" ++ ++#include ++#include ++ ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++ZEND_API unsigned int zend_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Naur php-4.3.11/Zend/zend_compile.h hardening-patch-4.3.11-0.3.2/Zend/zend_compile.h +--- php-4.3.11/Zend/zend_compile.h 2004-09-24 15:15:14.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_compile.h 2005-07-09 08:53:02.515356272 +0200 +@@ -546,6 +546,7 @@ + #define ZEND_USER_FUNCTION 2 + #define ZEND_OVERLOADED_FUNCTION 3 + #define ZEND_EVAL_CODE 4 ++#define ZEND_SANDBOX_CODE 6 + + #define ZEND_INTERNAL_CLASS 1 + #define ZEND_USER_CLASS 2 +diff -Naur php-4.3.11/Zend/zend_constants.c hardening-patch-4.3.11-0.3.2/Zend/zend_constants.c +--- php-4.3.11/Zend/zend_constants.c 2004-07-13 21:29:45.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_constants.c 2005-07-09 08:53:02.516356120 +0200 +@@ -111,6 +111,72 @@ + REGISTER_MAIN_LONG_CONSTANT("E_USER_NOTICE", E_USER_NOTICE, CONST_PERSISTENT | CONST_CS); + + REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("S_MEMORY", S_MEMORY, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_VARS", S_VARS, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_FILES", S_VARS, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INCLUDE", S_INCLUDE, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_SQL", S_SQL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_EXECUTOR", S_EXECUTOR, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_MISC", S_MISC, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_ALL", S_ALL, CONST_PERSISTENT | CONST_CS); ++ ++ /* error levels */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRIT", LOG_CRIT, CONST_CS | CONST_PERSISTENT); /* critical conditions */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ERR", LOG_ERR, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_WARNING", LOG_WARNING, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOTICE", LOG_NOTICE, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_INFO", LOG_INFO, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DEBUG", LOG_DEBUG, CONST_CS | CONST_PERSISTENT); ++ /* facility: type of program logging the message */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_KERN", LOG_KERN, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_USER", LOG_USER, CONST_CS | CONST_PERSISTENT); /* generic user level */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_MAIL", LOG_MAIL, CONST_CS | CONST_PERSISTENT); /* log to email */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DAEMON", LOG_DAEMON, CONST_CS | CONST_PERSISTENT); /* other system daemons */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTH", LOG_AUTH, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_SYSLOG", LOG_SYSLOG, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LPR", LOG_LPR, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NEWS ++ /* No LOG_NEWS on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NEWS", LOG_NEWS, CONST_CS | CONST_PERSISTENT); /* usenet new */ ++#endif ++#ifdef LOG_UUCP ++ /* No LOG_UUCP on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_UUCP", LOG_UUCP, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_CRON ++ /* apparently some systems don't have this one */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRON", LOG_CRON, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_AUTHPRIV ++ /* AIX doesn't have LOG_AUTHPRIV */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTHPRIV", LOG_AUTHPRIV, CONST_CS | CONST_PERSISTENT); ++#endif ++#if !defined(PHP_WIN32) && !defined(NETWARE) ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL0", LOG_LOCAL0, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL1", LOG_LOCAL1, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL2", LOG_LOCAL2, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL3", LOG_LOCAL3, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL4", LOG_LOCAL4, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL5", LOG_LOCAL5, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL6", LOG_LOCAL6, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL7", LOG_LOCAL7, CONST_CS | CONST_PERSISTENT); ++#endif ++ /* options */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PID", LOG_PID, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CONS", LOG_CONS, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ODELAY", LOG_ODELAY, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NDELAY", LOG_NDELAY, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NOWAIT ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOWAIT", LOG_NOWAIT, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_PERROR ++ /* AIX doesn't have LOG_PERROR */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ ++#endif ++#endif + + /* true/false constants */ + { +diff -Naur php-4.3.11/Zend/zend_errors.h hardening-patch-4.3.11-0.3.2/Zend/zend_errors.h +--- php-4.3.11/Zend/zend_errors.h 2002-12-31 17:22:59.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_errors.h 2005-07-09 08:53:02.516356120 +0200 +@@ -36,5 +36,16 @@ + #define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE) + #define E_CORE (E_CORE_ERROR | E_CORE_WARNING) + ++#if HARDENING_PATCH ++#define S_MEMORY (1<<0L) ++#define S_VARS (1<<1L) ++#define S_FILES (1<<2L) ++#define S_INCLUDE (1<<3L) ++#define S_SQL (1<<4L) ++#define S_EXECUTOR (1<<5L) ++#define S_MISC (1<<30L) ++#define S_ALL (S_MEMORY | S_VARS | S_INCLUDE | S_FILES | S_MISC | S_SQL | S_EXECUTOR) ++#endif ++ + #endif /* ZEND_ERRORS_H */ + +diff -Naur php-4.3.11/Zend/zend_execute_API.c hardening-patch-4.3.11-0.3.2/Zend/zend_execute_API.c +--- php-4.3.11/Zend/zend_execute_API.c 2004-11-04 00:15:05.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_execute_API.c 2005-07-09 08:53:02.517355968 +0200 +@@ -142,6 +142,7 @@ + EG(class_table) = CG(class_table); + + EG(in_execution) = 0; ++ EG(in_code_type) = 0; + + zend_ptr_stack_init(&EG(argument_stack)); + +@@ -431,12 +432,14 @@ + zend_execute_data execute_data; + + /* Initialize execute_data */ ++ memset(&execute_data, 0, sizeof(execute_data)); + EX(fbc) = NULL; + EX(object).ptr = NULL; + EX(ce) = NULL; + EX(Ts) = NULL; + EX(op_array) = NULL; + EX(opline) = NULL; ++ EX(execute_depth) = 0; + + *retval_ptr_ptr = NULL; + +@@ -601,8 +604,7 @@ + return SUCCESS; + } + +- +-ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) ++ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int type TSRMLS_DC) + { + zval pv; + zend_op_array *new_op_array; +@@ -635,6 +637,7 @@ + zval **original_return_value_ptr_ptr = EG(return_value_ptr_ptr); + zend_op **original_opline_ptr = EG(opline_ptr); + ++ new_op_array->type = type; + EG(return_value_ptr_ptr) = &local_retval_ptr; + EG(active_op_array) = new_op_array; + EG(no_extensions)=1; +@@ -668,6 +671,10 @@ + return retval; + } + ++ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) ++{ ++ return (zend_eval_string_ex(str, retval_ptr, string_name, ZEND_EVAL_CODE TSRMLS_CC)); ++} + + void execute_new_code(TSRMLS_D) + { +diff -Naur php-4.3.11/Zend/zend_execute.c hardening-patch-4.3.11-0.3.2/Zend/zend_execute.c +--- php-4.3.11/Zend/zend_execute.c 2005-02-21 13:38:54.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_execute.c 2005-07-09 08:53:02.519355664 +0200 +@@ -1042,6 +1042,7 @@ + zend_execute_data execute_data; + + /* Initialize execute_data */ ++ memset(&execute_data, 0, sizeof(execute_data)); + EX(fbc) = NULL; + EX(ce) = NULL; + EX(object).ptr = NULL; +@@ -1053,9 +1054,21 @@ + } + EX(prev_execute_data) = EG(current_execute_data); + EX(original_in_execution)=EG(in_execution); ++ EX(original_in_code_type)=EG(in_code_type); + + EG(current_execute_data) = &execute_data; + ++#if HARDENING_PATCH ++ EX(execute_depth) = 0; ++ ++ if (op_array->type == ZEND_EVAL_CODE && EG(in_code_type) != ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } else if (op_array->type == ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_SANDBOX_CODE; ++ op_array->type = ZEND_EVAL_CODE; ++ } ++#endif ++ + EG(in_execution) = 1; + if (op_array->start_op) { + EX(opline) = op_array->start_op; +@@ -1087,6 +1100,19 @@ + } + } + ++#if HARDENING_PATCH ++ if (EX(prev_execute_data) == NULL) { ++ EX(execute_depth) = 0; ++ } else { ++ EX(execute_depth) = EX(prev_execute_data)->execute_depth + 1; ++ } ++ ++ if (EG(hphp_executor_max_depth) > 0 && EX(execute_depth) > EG(hphp_executor_max_depth)) { ++ zend_security_log(S_EXECUTOR, "Maximum execution depth of %u violated", EG(hphp_executor_max_depth)); ++ zend_bailout(); ++ } ++#endif ++ + while (1) { + #ifdef ZEND_WIN32 + if (EG(timed_out)) { +@@ -1782,6 +1808,7 @@ + efree(EX(Ts)); + } + EG(in_execution) = EX(original_in_execution); ++ EG(in_code_type) = EX(original_in_code_type); + EG(current_execute_data) = EX(prev_execute_data); + return; + } +@@ -2161,7 +2188,12 @@ + int dummy = 1; + zend_file_handle file_handle = {0}; + ++#if HARDENING_PATCH_INC_PROTECT ++ if (zend_is_valid_include(inc_filename) ++ && zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#else + if (zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#endif + && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) { + + file_handle.filename = inc_filename->value.str.val; +@@ -2190,6 +2222,11 @@ + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: ++#if HARDENING_PATCH_INC_PROTECT ++ if (!zend_is_valid_include(inc_filename)) { ++ break; ++ } ++#endif + new_op_array = compile_filename(EX(opline)->op2.u.constant.value.lval, inc_filename TSRMLS_CC); + break; + case ZEND_EVAL: { +diff -Naur php-4.3.11/Zend/zend_execute_globals.h hardening-patch-4.3.11-0.3.2/Zend/zend_execute_globals.h +--- php-4.3.11/Zend/zend_execute_globals.h 2002-12-31 17:23:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_execute_globals.h 2005-07-09 08:53:02.519355664 +0200 +@@ -59,6 +59,8 @@ + object_info object; + temp_variable *Ts; + zend_bool original_in_execution; ++ zend_uint original_in_code_type; ++ zend_uint execute_depth; + zend_op_array *op_array; + struct _zend_execute_data *prev_execute_data; + } zend_execute_data; +diff -Naur php-4.3.11/Zend/zend_extensions.h hardening-patch-4.3.11-0.3.2/Zend/zend_extensions.h +--- php-4.3.11/Zend/zend_extensions.h 2002-12-31 17:23:02.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_extensions.h 2005-07-09 08:53:02.520355512 +0200 +@@ -23,7 +23,9 @@ + + #include "zend_compile.h" + +-#define ZEND_EXTENSION_API_NO 20021010 ++/* Create own API version number for Hardening-Patch */ ++ ++#define ZEND_EXTENSION_API_NO 1020050626 + + typedef struct _zend_extension_version_info { + int zend_extension_api_no; +diff -Naur php-4.3.11/Zend/zend_globals.h hardening-patch-4.3.11-0.3.2/Zend/zend_globals.h +--- php-4.3.11/Zend/zend_globals.h 2004-11-04 00:15:05.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_globals.h 2005-07-09 08:53:02.520355512 +0200 +@@ -163,6 +163,16 @@ + + int error_reporting; + int orig_error_reporting; ++#if HARDENING_PATCH ++ int hphp_log_syslog; ++ int hphp_log_syslog_facility; ++ int hphp_log_syslog_priority; ++ int hphp_log_sapi; ++ int hphp_log_script; ++ char *hphp_log_scriptname; ++ zend_bool hphp_log_use_x_forwarded_for; ++ long hphp_executor_max_depth; ++#endif + int exit_status; + + zend_op_array *active_op_array; +@@ -176,6 +186,7 @@ + int ticks_count; + + zend_bool in_execution; ++ zend_uint in_code_type; + zend_bool bailout_set; + zend_bool full_tables_cleanup; + +diff -Naur php-4.3.11/Zend/zend.h hardening-patch-4.3.11-0.3.2/Zend/zend.h +--- php-4.3.11/Zend/zend.h 2005-01-25 14:08:41.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend.h 2005-07-09 08:53:02.521355360 +0200 +@@ -275,9 +275,10 @@ + struct _zval_struct { + /* Variable information */ + zvalue_value value; /* value */ ++ zend_uint refcount; ++ zend_ushort flags; + zend_uchar type; /* active type */ + zend_uchar is_ref; +- zend_ushort refcount; + }; + + +@@ -338,6 +339,12 @@ + void (*ticks_function)(int ticks); + void (*on_timeout)(int seconds TSRMLS_DC); + zend_bool (*open_function)(const char *filename, struct _zend_file_handle *); ++#if HARDENING_PATCH ++ void (*security_log_function)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ int (*is_valid_include)(zval *z); ++#endif + } zend_utility_functions; + + +@@ -469,7 +476,16 @@ + extern ZEND_API void (*zend_ticks_function)(int ticks); + extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); + extern void (*zend_on_timeout)(int seconds TSRMLS_DC); ++#if HARDENING_PATCH ++extern ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++extern ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ZEND_API unsigned int zend_canary(void); ++#endif + + ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 2, 3); + +@@ -576,6 +592,11 @@ + + #define ZEND_MAX_RESERVED_RESOURCES 4 + ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#include "php_syslog.h" ++#endif ++ + #endif /* ZEND_H */ + + /* +diff -Naur php-4.3.11/Zend/zend_hash.c hardening-patch-4.3.11-0.3.2/Zend/zend_hash.c +--- php-4.3.11/Zend/zend_hash.c 2004-07-12 23:26:46.000000000 +0200 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_hash.c 2005-07-09 08:53:02.522355208 +0200 +@@ -26,6 +26,17 @@ + # include + #endif + ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int zend_hash_canary = 0x1234567; ++ zend_bool zend_hash_canary_inited = 0; ++#endif ++ ++#define CHECK_HASH_CANARY(hash) \ ++ if (zend_hash_canary != (hash)->canary) { \ ++ zend_security_log(S_MEMORY, "Zend HashTable canary was overwritten"); \ ++ exit(1); \ ++ } ++ + #define HANDLE_NUMERIC(key, length, func) { \ + register char *tmp=key; \ + \ +@@ -175,6 +186,9 @@ + { + uint i = 3; + Bucket **tmp; ++#if HARDENING_PATCH_HASH_PROTECT ++ TSRMLS_FETCH(); ++#endif + + SET_INCONSISTENT(HT_OK); + +@@ -184,6 +198,13 @@ + + ht->nTableSize = 1 << i; + ht->nTableMask = ht->nTableSize - 1; ++#if HARDENING_PATCH_HASH_PROTECT ++ if (zend_hash_canary_inited==0) { ++ zend_hash_canary = zend_canary(); ++ zend_hash_canary_inited = 1; ++ } ++ ht->canary = zend_hash_canary; ++#endif + ht->pDestructor = pDestructor; + ht->pListHead = NULL; + ht->pListTail = NULL; +@@ -259,6 +280,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -327,6 +351,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -402,6 +429,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -450,7 +480,7 @@ + IS_CONSISTENT(ht); + + if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */ +- t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); ++ t = (Bucket **) perealloc(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); + if (t) { + HANDLE_BLOCK_INTERRUPTIONS(); + ht->arBuckets = t; +@@ -460,6 +490,7 @@ + HANDLE_UNBLOCK_INTERRUPTIONS(); + return SUCCESS; + } ++ zend_error(E_ERROR, "zend_hash_do_resize - out of memory"); + return FAILURE; + } + return SUCCESS; +@@ -524,6 +555,9 @@ + ht->pInternalPointer = p->pListNext; + } + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +@@ -553,6 +587,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -579,6 +616,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -608,6 +648,9 @@ + HANDLE_BLOCK_INTERRUPTIONS(); + + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +diff -Naur php-4.3.11/Zend/zend_hash.h hardening-patch-4.3.11-0.3.2/Zend/zend_hash.h +--- php-4.3.11/Zend/zend_hash.h 2002-12-31 17:23:03.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_hash.h 2005-07-09 08:53:02.522355208 +0200 +@@ -54,6 +54,9 @@ + } Bucket; + + typedef struct _hashtable { ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int canary; ++#endif + uint nTableSize; + uint nTableMask; + uint nNumOfElements; +diff -Naur php-4.3.11/Zend/zend_ini.h hardening-patch-4.3.11-0.3.2/Zend/zend_ini.h +--- php-4.3.11/Zend/zend_ini.h 2005-01-09 18:00:16.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_ini.h 2005-07-09 08:53:02.522355208 +0200 +@@ -174,6 +174,7 @@ + /* Standard message handlers */ + BEGIN_EXTERN_C() + ZEND_API ZEND_INI_MH(OnUpdateBool); ++#define OnUpdateLong OnUpdateInt + ZEND_API ZEND_INI_MH(OnUpdateInt); + ZEND_API ZEND_INI_MH(OnUpdateReal); + ZEND_API ZEND_INI_MH(OnUpdateString); +diff -Naur php-4.3.11/Zend/zend_llist.c hardening-patch-4.3.11-0.3.2/Zend/zend_llist.c +--- php-4.3.11/Zend/zend_llist.c 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_llist.c 2005-07-09 08:53:02.523355056 +0200 +@@ -21,9 +21,34 @@ + #include "zend.h" + #include "zend_llist.h" + #include "zend_qsort.h" ++#include "zend_globals.h" ++ ++#define CHECK_LIST_CANARY(list) \ ++ if (HG(canary_3) != (list)->canary_h || HG(canary_4) != (list)->canary_t) { \ ++ zend_security_log(S_MEMORY, "linked list canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++#define CHECK_LISTELEMENT_CANARY(elem) \ ++ if (HG(canary_3) != (elem)->canary) { \ ++ zend_security_log(S_MEMORY, "linked list element canary was overwritten"); \ ++ exit(1); \ ++ } ++ + + ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ ++ if (!HG(ll_canary_inited)) { ++ HG(canary_3) = zend_canary(); ++ HG(canary_4) = zend_canary(); ++ HG(ll_canary_inited) = 1; ++ } ++ l->canary_h = HG(canary_3); ++ l->canary_t = HG(canary_4); ++#endif + l->head = NULL; + l->tail = NULL; + l->count = 0; +@@ -37,6 +62,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->prev = l->tail; + tmp->next = NULL; + if (l->tail) { +@@ -55,6 +85,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->next = l->head; + tmp->prev = NULL; + if (l->head) { +@@ -91,10 +126,20 @@ + zend_llist_element *current=l->head; + zend_llist_element *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (compare(current->data, element)) { + DEL_LLIST_ELEMENT(current, l); ++#if HARDENING_PATCH_LL_PROTECT ++ current->canary = 0; ++#endif + break; + } + current = next; +@@ -106,7 +151,14 @@ + { + zend_llist_element *current=l->head, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (l->dtor) { + l->dtor(current->data); +@@ -131,7 +183,14 @@ + zend_llist_element *old_tail; + void *data; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if ((old_tail = l->tail)) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(old_tail) ++#endif + if (l->tail->prev) { + l->tail->prev->next = NULL; + } +@@ -157,9 +216,16 @@ + { + zend_llist_element *ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(src) ++#endif + zend_llist_init(dst, src->size, src->dtor, src->persistent); + ptr = src->head; + while (ptr) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(ptr) ++#endif + zend_llist_add_element(dst, ptr->data); + ptr = ptr->next; + } +@@ -170,11 +236,21 @@ + { + zend_llist_element *element, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + element=l->head; + while (element) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + next = element->next; + if (func(element->data)) { + DEL_LLIST_ELEMENT(element, l); ++#if HARDENING_PATCH_LL_PROTECT ++ element->canary = 0; ++#endif + } + element = next; + } +@@ -185,7 +261,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data TSRMLS_CC); + } + } +@@ -197,6 +279,9 @@ + zend_llist_element **elements; + zend_llist_element *element, **ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + if (l->count <= 0) { + return; + } +@@ -206,6 +291,9 @@ + ptr = &elements[0]; + + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + *ptr++ = element; + } + +@@ -228,7 +316,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, arg TSRMLS_CC); + } + } +@@ -239,8 +333,14 @@ + zend_llist_element *element; + va_list args; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + va_start(args, num_args); + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, num_args, args TSRMLS_CC); + } + va_end(args); +@@ -249,6 +349,10 @@ + + ZEND_API int zend_llist_count(zend_llist *l) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + return l->count; + } + +@@ -256,8 +360,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->head; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -269,8 +380,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->tail; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -282,9 +400,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->next; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +@@ -296,9 +424,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->prev; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +diff -Naur php-4.3.11/Zend/zend_llist.h hardening-patch-4.3.11-0.3.2/Zend/zend_llist.h +--- php-4.3.11/Zend/zend_llist.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_llist.h 2005-07-09 08:53:02.524354904 +0200 +@@ -24,6 +24,9 @@ + #include + + typedef struct _zend_llist_element { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary; ++#endif + struct _zend_llist_element *next; + struct _zend_llist_element *prev; + char data[1]; /* Needs to always be last in the struct */ +@@ -36,6 +39,9 @@ + typedef void (*llist_apply_func_t)(void * TSRMLS_DC); + + typedef struct _zend_llist { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_h; /* head */ ++#endif + zend_llist_element *head; + zend_llist_element *tail; + size_t size; +@@ -43,6 +49,9 @@ + llist_dtor_func_t dtor; + unsigned char persistent; + zend_llist_element *traverse_ptr; ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_t; /* tail */ ++#endif + } zend_llist; + + typedef zend_llist_element* zend_llist_position; +diff -Naur php-4.3.11/Zend/zend_modules.h hardening-patch-4.3.11-0.3.2/Zend/zend_modules.h +--- php-4.3.11/Zend/zend_modules.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.3.2/Zend/zend_modules.h 2005-07-09 08:53:02.524354904 +0200 +@@ -34,7 +34,7 @@ + ZEND_API extern unsigned char second_arg_force_ref[]; + ZEND_API extern unsigned char third_arg_force_ref[]; + +-#define ZEND_MODULE_API_NO 20020429 ++#define ZEND_MODULE_API_NO 1020050626 + #ifdef ZTS + #define USING_ZTS 1 + #else diff --git a/0.3.2/hardening-patch-4.4.0RC2-0.3.2.patch b/0.3.2/hardening-patch-4.4.0RC2-0.3.2.patch new file mode 100644 index 0000000..3cae163 --- /dev/null +++ b/0.3.2/hardening-patch-4.4.0RC2-0.3.2.patch @@ -0,0 +1,4959 @@ +diff -Naur php-4.4.0RC2/acinclude.m4 hardening-patch-4.4.0RC2-0.3.2/acinclude.m4 +--- php-4.4.0RC2/acinclude.m4 2005-04-30 11:31:09.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/acinclude.m4 2005-07-09 08:53:20.597607352 +0200 +@@ -1173,6 +1173,36 @@ + fi + ]) + ++dnl ++dnl Check for broken realpath() ++dnl ++dnl realpath("/etc/hosts/../passwd",XXX) should not return ++dnl "/etc/passwd" ++dnl ++AC_DEFUN([PHP_AC_BROKEN_REALPATH],[ ++ AC_CACHE_CHECK(whether realpath is broken, ac_cv_broken_realpath,[ ++ AC_TRY_RUN([ ++main() { ++ char buf[4096+1]; ++ buf[0] = 0; ++ realpath("/etc/hosts/../passwd", buf); ++ exit(strcmp(buf, "/etc/passwd")==0); ++} ++ ],[ ++ ac_cv_broken_realpath=no ++ ],[ ++ ac_cv_broken_realpath=yes ++ ],[ ++ ac_cv_broken_realpath=no ++ ]) ++ ]) ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ AC_DEFINE(PHP_BROKEN_REALPATH, 1, [Whether realpath is broken]) ++ else ++ AC_DEFINE(PHP_BROKEN_REALPATH, 0, [Whether realpath is broken]) ++ fi ++]) ++ + dnl PHP_SHARED_MODULE(module-name, object-var, build-dir, cxx) + dnl + dnl Basically sets up the link-stage for building module-name +diff -Naur php-4.4.0RC2/configure hardening-patch-4.4.0RC2-0.3.2/configure +--- php-4.4.0RC2/configure 2005-07-01 12:07:55.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/configure 2005-07-09 08:53:20.634601728 +0200 +@@ -394,6 +394,16 @@ + ac_default_prefix=/usr/local + # Any additions from configure.in: + ac_help="$ac_help ++ --disable-hardening-patch-mm-protect Disable the Memory Manager protection." ++ac_help="$ac_help ++ --disable-hardening-patch-ll-protect Disable the Linked List protection." ++ac_help="$ac_help ++ --disable-hardening-patch-inc-protect Disable include/require protection." ++ac_help="$ac_help ++ --disable-hardening-patch-fmt-protect Disable format string protection." ++ac_help="$ac_help ++ --disable-hardening-patch-hash-protect Disable Zend HashTable DTOR protection." ++ac_help="$ac_help + + SAPI modules: + " +@@ -846,6 +856,8 @@ + ac_help="$ac_help + --disable-tokenizer Disable tokenizer support" + ac_help="$ac_help ++ --disable-varfilter Disable Hardening-Patch's variable filter" ++ac_help="$ac_help + --enable-wddx Enable WDDX support." + ac_help="$ac_help + --disable-xml Disable XML support using bundled expat lib" +@@ -2682,6 +2694,157 @@ + + + ++# Check whether --enable-hardening-patch-mm-protect or --disable-hardening-patch-mm-protect was given. ++if test "${enable_hardening_patch_mm_protect+set}" = set; then ++ enableval="$enable_hardening_patch_mm_protect" ++ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-ll-protect or --disable-hardening-patch-ll-protect was given. ++if test "${enable_hardening_patch_ll_protect+set}" = set; then ++ enableval="$enable_hardening_patch_ll_protect" ++ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-inc-protect or --disable-hardening-patch-inc-protect was given. ++if test "${enable_hardening_patch_inc_protect+set}" = set; then ++ enableval="$enable_hardening_patch_inc_protect" ++ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-fmt-protect or --disable-hardening-patch-fmt-protect was given. ++if test "${enable_hardening_patch_fmt_protect+set}" = set; then ++ enableval="$enable_hardening_patch_fmt_protect" ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-hash-protect or --disable-hardening-patch-hash-protect was given. ++if test "${enable_hardening_patch_hash_protect+set}" = set; then ++ enableval="$enable_hardening_patch_hash_protect" ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++ ++fi ++ ++ ++echo $ac_n "checking whether to protect the Zend Memory Manager""... $ac_c" 1>&6 ++echo "configure:2725: checking whether to protect the Zend Memory Manager" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_MM_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend Linked Lists""... $ac_c" 1>&6 ++echo "configure:2729: checking whether to protect the Zend Linked Lists" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_LL_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect include/require statements""... $ac_c" 1>&6 ++echo "configure:2733: checking whether to protect include/require statements" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_INC_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect PHP Format String functions""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect PHP Format String functions" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_FMT_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend HashTable Destructors""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect the Zend HashTable Destructors" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_HASH_PROTECT" 1>&6 ++ ++ ++cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH 1 ++EOF ++ ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 0 ++EOF ++ ++fi + + + +@@ -15733,6 +15896,62 @@ + fi + + ++ echo $ac_n "checking whether realpath is broken""... $ac_c" 1>&6 ++echo "configure:14928: checking whether realpath is broken" >&5 ++if eval "test \"`echo '$''{'ac_cv_broken_realpath'+set}'`\" = set"; then ++ echo $ac_n "(cached) $ac_c" 1>&6 ++else ++ ++ if test "$cross_compiling" = yes; then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null ++then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ echo "configure: failed program was:" >&5 ++ cat conftest.$ac_ext >&5 ++ rm -fr conftest* ++ ++ ac_cv_broken_realpath=yes ++ ++fi ++rm -fr conftest* ++fi ++ ++ ++fi ++ ++echo "$ac_t""$ac_cv_broken_realpath" 1>&6 ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 1 ++EOF ++ ++ else ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 0 ++EOF ++ ++ fi ++ ++ + echo $ac_n "checking for declared timezone""... $ac_c" 1>&6 + echo "configure:15738: checking for declared timezone" >&5 + if eval "test \"`echo '$''{'ac_cv_declared_timezone'+set}'`\" = set"; then +@@ -87305,6 +87524,265 @@ + fi + + ++echo $ac_n "checking whether to enable Hardening-Patch's variable filter""... $ac_c" 1>&6 ++echo "configure:82041: checking whether to enable Hardening-Patch's variable filter" >&5 ++# Check whether --enable-varfilter or --disable-varfilter was given. ++if test "${enable_varfilter+set}" = set; then ++ enableval="$enable_varfilter" ++ PHP_VARFILTER=$enableval ++else ++ ++ PHP_VARFILTER=yes ++ ++ if test "$PHP_ENABLE_ALL" && test "yes" = "yes"; then ++ PHP_VARFILTER=$PHP_ENABLE_ALL ++ fi ++ ++fi ++ ++ ++ ++ext_output="yes, shared" ++ext_shared=yes ++case $PHP_VARFILTER in ++shared,*) ++ PHP_VARFILTER=`echo "$PHP_VARFILTER"|sed 's/^shared,//'` ++ ;; ++shared) ++ PHP_VARFILTER=yes ++ ;; ++no) ++ ext_output=no ++ ext_shared=no ++ ;; ++*) ++ ext_output=yes ++ ext_shared=no ++ ;; ++esac ++ ++ ++ ++echo "$ac_t""$ext_output" 1>&6 ++ ++ ++ ++ ++if test "$PHP_VARFILTER" != "no"; then ++ cat >> confdefs.h <<\EOF ++#define HAVE_VARFILTER 1 ++EOF ++ ++ ++ ext_builddir=ext/varfilter ++ ext_srcdir=$abs_srcdir/ext/varfilter ++ ++ ac_extra= ++ ++ if test "$ext_shared" != "shared" && test "$ext_shared" != "yes" && test "" != "cli"; then ++ ++ ++ ++ case ext/varfilter in ++ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;; ++ /*) ac_srcdir=`echo "ext/varfilter"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;; ++ *) ac_srcdir="$abs_srcdir/ext/varfilter/"; ac_bdir="ext/varfilter/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;; ++ esac ++ ++ ++ ++ b_c_pre=$php_c_pre ++ b_cxx_pre=$php_cxx_pre ++ b_c_meta=$php_c_meta ++ b_cxx_meta=$php_cxx_meta ++ b_c_post=$php_c_post ++ b_cxx_post=$php_cxx_post ++ b_lo=$php_lo ++ ++ ++ old_IFS=$IFS ++ for ac_src in varfilter.c; do ++ ++ IFS=. ++ set $ac_src ++ ac_obj=$1 ++ IFS=$old_IFS ++ ++ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo" ++ ++ case $ac_src in ++ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;; ++ *.cpp) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;; ++ esac ++ ++ cat >>Makefile.objects<>Makefile.objects<>Makefile.objects<> confdefs.h <>Makefile.objects<>Makefile.objects<&6 +@@ -99988,7 +100466,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c; do ++ output.c memory_streams.c user_streams.c hardening_patch.c; do + + IFS=. + set $ac_src +@@ -100161,7 +100639,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c; do ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c; do + + IFS=. + set $ac_src +diff -Naur php-4.4.0RC2/configure.in hardening-patch-4.4.0RC2-0.3.2/configure.in +--- php-4.4.0RC2/configure.in 2005-07-01 11:53:57.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/configure.in 2005-07-09 08:53:20.636601424 +0200 +@@ -238,7 +238,7 @@ + sinclude(Zend/acinclude.m4) + sinclude(Zend/Zend.m4) + sinclude(TSRM/tsrm.m4) +- ++sinclude(main/hardening_patch.m4) + + + divert(2) +@@ -612,6 +612,7 @@ + AC_FUNC_ALLOCA + dnl PHP_AC_BROKEN_SPRINTF + dnl PHP_AC_BROKEN_SNPRINTF ++PHP_AC_BROKEN_REALPATH + PHP_DECLARED_TIMEZONE + PHP_TIME_R_TYPE + PHP_READDIR_R_TYPE +@@ -1241,7 +1242,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c) ++ output.c memory_streams.c user_streams.c hardening_patch.c) + PHP_ADD_SOURCES(/main, internal_functions.c,, sapi) + PHP_ADD_SOURCES(/main, internal_functions_cli.c,, cli) + +@@ -1254,7 +1255,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c) ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c ) + + if test -r "$abs_srcdir/Zend/zend_objects.c"; then + PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_mm.c) +diff -Naur php-4.4.0RC2/ext/fbsql/php_fbsql.c hardening-patch-4.4.0RC2-0.3.2/ext/fbsql/php_fbsql.c +--- php-4.4.0RC2/ext/fbsql/php_fbsql.c 2005-02-09 20:33:32.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/fbsql/php_fbsql.c 2005-07-09 08:53:20.637601272 +0200 +@@ -1797,8 +1797,24 @@ + } + else if (fbcmdErrorsFound(md)) + { ++#if HARDENING_PATCH ++ char* query_copy; ++ int i; ++#endif + FBCErrorMetaData* emd = fbcdcErrorMetaData(c, md); + char* emg = fbcemdAllErrorMessages(emd); ++#if HARDENING_PATCH ++ query_copy=estrdup(query_copy); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "fbsql error: %s - query: %s", emg, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ free(emg); ++ fbcemdRelease(emd); ++ result = 0; ++ zend_bailout(); ++ } ++#endif + if (FB_SQL_G(generateWarnings)) + { + if (emg) +diff -Naur php-4.4.0RC2/ext/mbstring/mbstring.c hardening-patch-4.4.0RC2-0.3.2/ext/mbstring/mbstring.c +--- php-4.4.0RC2/ext/mbstring/mbstring.c 2005-02-21 09:03:47.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/mbstring/mbstring.c 2005-07-09 08:53:20.639600968 +0200 +@@ -1487,6 +1487,7 @@ + char *strtok_buf = NULL, **val_list; + zval *array_ptr = (zval *) arg; + int n, num, val_len, *len_list; ++ unsigned int new_val_len; + enum mbfl_no_encoding from_encoding; + mbfl_string string, resvar, resval; + mbfl_encoding_detector *identd = NULL; +@@ -1609,8 +1610,14 @@ + val_len = len_list[n]; + } + n++; +- /* add variable to symbol table */ +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ /* we need val to be emalloc()ed */ ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(info->data_type, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ /* add variable to symbol table */ ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); ++ + if (convd != NULL){ + mbfl_string_clear(&resvar); + mbfl_string_clear(&resval); +diff -Naur php-4.4.0RC2/ext/mysql/php_mysql.c hardening-patch-4.4.0RC2-0.3.2/ext/mysql/php_mysql.c +--- php-4.4.0RC2/ext/mysql/php_mysql.c 2005-04-08 00:23:01.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/mysql/php_mysql.c 2005-07-09 08:53:20.641600664 +0200 +@@ -1218,6 +1218,8 @@ + { + php_mysql_conn *mysql; + MYSQL_RES *mysql_result; ++ char *copy_query; ++ int i; + + ZEND_FETCH_RESOURCE2(mysql, php_mysql_conn *, mysql_link, link_id, "MySQL-Link", le_link, le_plink); + +@@ -1268,6 +1270,13 @@ + php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #else +@@ -1275,12 +1284,20 @@ + /* check possible error */ + if (MySG(trace_mode)){ + if (mysql_errno(&mysql->conn)){ +- php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, mysql_error(&mysql->conn)); ++ php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #endif ++ + if(use_store == MYSQL_USE_RESULT) { + mysql_result=mysql_use_result(&mysql->conn); + } else { +diff -Naur php-4.4.0RC2/ext/pgsql/pgsql.c hardening-patch-4.4.0RC2-0.3.2/ext/pgsql/pgsql.c +--- php-4.4.0RC2/ext/pgsql/pgsql.c 2005-05-11 01:15:06.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/pgsql/pgsql.c 2005-07-09 08:53:20.643600360 +0200 +@@ -1001,10 +1001,28 @@ + case PGRES_EMPTY_QUERY: + case PGRES_BAD_RESPONSE: + case PGRES_NONFATAL_ERROR: +- case PGRES_FATAL_ERROR: +- PHP_PQ_ERROR("Query failed: %s", pgsql); +- PQclear(pgsql_result); +- RETURN_FALSE; ++ case PGRES_FATAL_ERROR: ++ { ++#if HARDENING_PATCH ++ int i; ++ char *query_copy; ++#endif ++ char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); ++ PQclear(pgsql_result); ++#if HARDENING_PATCH ++ query_copy = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "PgSQL error: %s - query: %s", msgbuf, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ efree(msgbuf); ++ zend_bailout(); ++ } ++#endif ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Query failed: %s", msgbuf); ++ efree(msgbuf); ++ RETURN_FALSE; ++ } + break; + case PGRES_COMMAND_OK: /* successful command that did not return rows */ + default: +diff -Naur php-4.4.0RC2/ext/standard/array.c hardening-patch-4.4.0RC2-0.3.2/ext/standard/array.c +--- php-4.4.0RC2/ext/standard/array.c 2005-06-21 14:11:19.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/standard/array.c 2005-07-09 08:53:20.645600056 +0200 +@@ -1162,6 +1162,32 @@ + } + } + } ++ ++ if (var_name[0] == 'H') { ++ if ((strcmp(var_name, "HTTP_GET_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_FILES")==0)|| ++ (strcmp(var_name, "HTTP_ENV_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(var_name, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(var_name, "HTTP_RAW_POST_DATA")==0)) { ++ return 0; ++ } ++ } else if (var_name[0] == '_') { ++ if ((strcmp(var_name, "_COOKIE")==0)|| ++ (strcmp(var_name, "_ENV")==0)|| ++ (strcmp(var_name, "_FILES")==0)|| ++ (strcmp(var_name, "_GET")==0)|| ++ (strcmp(var_name, "_POST")==0)|| ++ (strcmp(var_name, "_REQUEST")==0)|| ++ (strcmp(var_name, "_SESSION")==0)|| ++ (strcmp(var_name, "_SERVER")==0)) { ++ return 0; ++ } ++ } else if (strcmp(var_name, "GLOBALS")==0) { ++ return 0; ++ } + + return 1; + } +diff -Naur php-4.4.0RC2/ext/standard/basic_functions.c hardening-patch-4.4.0RC2-0.3.2/ext/standard/basic_functions.c +--- php-4.4.0RC2/ext/standard/basic_functions.c 2005-05-16 10:55:31.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/standard/basic_functions.c 2005-07-09 08:53:20.646599904 +0200 +@@ -687,7 +687,7 @@ + PHP_FALIAS(socket_get_status, stream_get_meta_data, NULL) + + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +- PHP_FE(realpath, NULL) ++ PHP_STATIC_FE("realpath", zif_real_path, NULL) + #endif + + #ifdef HAVE_FNMATCH +@@ -3044,6 +3044,35 @@ + memcpy(new_key, prefix, prefix_len); + memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + ++ if (new_key[0] == 'H') { ++ if ((strcmp(new_key, "HTTP_GET_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_FILES")==0)|| ++ (strcmp(new_key, "HTTP_ENV_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(new_key, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(new_key, "HTTP_RAW_POST_DATA")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (new_key[0] == '_') { ++ if ((strcmp(new_key, "_COOKIE")==0)|| ++ (strcmp(new_key, "_ENV")==0)|| ++ (strcmp(new_key, "_FILES")==0)|| ++ (strcmp(new_key, "_GET")==0)|| ++ (strcmp(new_key, "_POST")==0)|| ++ (strcmp(new_key, "_REQUEST")==0)|| ++ (strcmp(new_key, "_SESSION")==0)|| ++ (strcmp(new_key, "_SERVER")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (strcmp(new_key, "GLOBALS")==0) { ++ efree(new_key); ++ return 0; ++ } ++ + zend_hash_del(&EG(symbol_table), new_key, new_key_len); + ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, (*var)->refcount+1, 0); + +diff -Naur php-4.4.0RC2/ext/standard/file.c hardening-patch-4.4.0RC2-0.3.2/ext/standard/file.c +--- php-4.4.0RC2/ext/standard/file.c 2005-03-27 17:53:59.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/standard/file.c 2005-07-09 08:53:20.648599600 +0200 +@@ -2469,7 +2469,7 @@ + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) + /* {{{ proto string realpath(string path) + Return the resolved path */ +-PHP_FUNCTION(realpath) ++PHP_FUNCTION(real_path) + { + zval **path; + char resolved_path_buff[MAXPATHLEN]; +diff -Naur php-4.4.0RC2/ext/standard/file.h hardening-patch-4.4.0RC2-0.3.2/ext/standard/file.h +--- php-4.4.0RC2/ext/standard/file.h 2004-06-21 21:33:47.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/standard/file.h 2005-07-09 08:53:20.648599600 +0200 +@@ -64,7 +64,7 @@ + PHP_FUNCTION(fd_set); + PHP_FUNCTION(fd_isset); + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +-PHP_FUNCTION(realpath); ++PHP_FUNCTION(real_path); + #endif + #ifdef HAVE_FNMATCH + PHP_FUNCTION(fnmatch); +diff -Naur php-4.4.0RC2/ext/standard/head.c hardening-patch-4.4.0RC2-0.3.2/ext/standard/head.c +--- php-4.4.0RC2/ext/standard/head.c 2005-01-07 22:14:23.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/standard/head.c 2005-07-09 08:53:20.649599448 +0200 +@@ -45,10 +45,31 @@ + { + zend_bool rep = 1; + sapi_header_line ctr = {0}; ++#if HARDENING_PATCH ++ int i; ++#endif + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &ctr.line, + &ctr.line_len, &rep, &ctr.response_code) == FAILURE) + return; ++ ++#if HARDENING_PATCH ++ if (!HG(hphp_multiheader)) { ++ for (i=0; i0 && (iPHP Version %s with Hardening-Patch %s\n", PHP_VERSION, HARDENING_PATCH_VERSION); ++ } else { ++ char temp_ver[40]; ++ ++ snprintf(temp_ver, sizeof(temp_ver), "%s/%s", PHP_VERSION, HARDENING_PATCH_VERSION); ++ php_info_print_table_row(2, "PHP/Hardening-Patch Version", temp_ver); ++ } ++#else + if (!sapi_module.phpinfo_as_text) { + php_printf("

PHP Version %s

\n", PHP_VERSION); + } else { + php_info_print_table_row(2, "PHP Version", PHP_VERSION); + } ++#endif + php_info_print_box_end(); + php_info_print_table_start(); + php_info_print_table_row(2, "System", php_uname ); +diff -Naur php-4.4.0RC2/ext/standard/syslog.c hardening-patch-4.4.0RC2-0.3.2/ext/standard/syslog.c +--- php-4.4.0RC2/ext/standard/syslog.c 2004-07-30 16:38:29.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/standard/syslog.c 2005-07-09 08:53:20.650599296 +0200 +@@ -42,6 +42,8 @@ + */ + PHP_MINIT_FUNCTION(syslog) + { ++ ++#if !HARDENING_PATCH + /* error levels */ + REGISTER_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ + REGISTER_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ +@@ -97,7 +99,7 @@ + /* AIX doesn't have LOG_PERROR */ + REGISTER_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ + #endif +- ++#endif + return SUCCESS; + } + /* }}} */ +diff -Naur php-4.4.0RC2/ext/varfilter/config.m4 hardening-patch-4.4.0RC2-0.3.2/ext/varfilter/config.m4 +--- php-4.4.0RC2/ext/varfilter/config.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/varfilter/config.m4 2005-07-09 08:53:20.650599296 +0200 +@@ -0,0 +1,11 @@ ++dnl ++dnl $Id: config.m4,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++dnl ++ ++PHP_ARG_ENABLE(varfilter, whether to enable Hardening-Patch's variable filter, ++[ --disable-varfilter Disable Hardening-Patch's variable filter], yes) ++ ++if test "$PHP_VARFILTER" != "no"; then ++ AC_DEFINE(HAVE_VARFILTER, 1, [ ]) ++ PHP_NEW_EXTENSION(varfilter, varfilter.c, $ext_shared) ++fi +diff -Naur php-4.4.0RC2/ext/varfilter/CREDITS hardening-patch-4.4.0RC2-0.3.2/ext/varfilter/CREDITS +--- php-4.4.0RC2/ext/varfilter/CREDITS 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/varfilter/CREDITS 2005-07-09 08:53:20.650599296 +0200 +@@ -0,0 +1,2 @@ ++varfilter ++Stefan Esser +\ Kein Zeilenumbruch am Dateiende. +diff -Naur php-4.4.0RC2/ext/varfilter/php_varfilter.h hardening-patch-4.4.0RC2-0.3.2/ext/varfilter/php_varfilter.h +--- php-4.4.0RC2/ext/varfilter/php_varfilter.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/varfilter/php_varfilter.h 2005-07-09 08:53:20.651599144 +0200 +@@ -0,0 +1,111 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: php_varfilter.h,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifndef PHP_VARFILTER_H ++#define PHP_VARFILTER_H ++ ++extern zend_module_entry varfilter_module_entry; ++#define phpext_varfilter_ptr &varfilter_module_entry ++ ++#ifdef PHP_WIN32 ++#define PHP_VARFILTER_API __declspec(dllexport) ++#else ++#define PHP_VARFILTER_API ++#endif ++ ++#ifdef ZTS ++#include "TSRM.h" ++#endif ++ ++#include "SAPI.h" ++ ++#include "php_variables.h" ++ ++ ++PHP_MINIT_FUNCTION(varfilter); ++PHP_MSHUTDOWN_FUNCTION(varfilter); ++PHP_RINIT_FUNCTION(varfilter); ++PHP_RSHUTDOWN_FUNCTION(varfilter); ++PHP_MINFO_FUNCTION(varfilter); ++ ++ ++ZEND_BEGIN_MODULE_GLOBALS(varfilter) ++// request variables ++ long max_request_variables; ++ long cur_request_variables; ++ long max_varname_length; ++ long max_totalname_length; ++ long max_value_length; ++ long max_array_depth; ++ long max_array_index_length; ++// cookie variables ++ long max_cookie_vars; ++ long cur_cookie_vars; ++ long max_cookie_name_length; ++ long max_cookie_totalname_length; ++ long max_cookie_value_length; ++ long max_cookie_array_depth; ++ long max_cookie_array_index_length; ++// get variables ++ long max_get_vars; ++ long cur_get_vars; ++ long max_get_name_length; ++ long max_get_totalname_length; ++ long max_get_value_length; ++ long max_get_array_depth; ++ long max_get_array_index_length; ++// post variables ++ long max_post_vars; ++ long cur_post_vars; ++ long max_post_name_length; ++ long max_post_totalname_length; ++ long max_post_value_length; ++ long max_post_array_depth; ++ long max_post_array_index_length; ++// fileupload ++ long max_uploads; ++ long cur_uploads; ++ zend_bool disallow_elf_files; ++ char *verification_script; ++ ++ZEND_END_MODULE_GLOBALS(varfilter) ++ ++ ++#ifdef ZTS ++#define VARFILTER_G(v) TSRMG(varfilter_globals_id, zend_varfilter_globals *, v) ++#else ++#define VARFILTER_G(v) (varfilter_globals.v) ++#endif ++ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter); ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter); ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter); ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter); ++ ++#endif /* PHP_VARFILTER_H */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * indent-tabs-mode: t ++ * End: ++ */ +diff -Naur php-4.4.0RC2/ext/varfilter/varfilter.c hardening-patch-4.4.0RC2-0.3.2/ext/varfilter/varfilter.c +--- php-4.4.0RC2/ext/varfilter/varfilter.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/ext/varfilter/varfilter.c 2005-07-09 08:58:18.504318648 +0200 +@@ -0,0 +1,604 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: varfilter.c,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "php.h" ++#include "php_ini.h" ++#include "ext/standard/info.h" ++#include "php_varfilter.h" ++#include "hardening_patch.h" ++ ++ZEND_DECLARE_MODULE_GLOBALS(varfilter) ++ ++/* True global resources - no need for thread safety here */ ++static int le_varfilter; ++ ++/* {{{ varfilter_module_entry ++ */ ++zend_module_entry varfilter_module_entry = { ++#if ZEND_MODULE_API_NO >= 20010901 ++ STANDARD_MODULE_HEADER, ++#endif ++ "varfilter", ++ NULL, ++ PHP_MINIT(varfilter), ++ PHP_MSHUTDOWN(varfilter), ++ PHP_RINIT(varfilter), /* Replace with NULL if there's nothing to do at request start */ ++ PHP_RSHUTDOWN(varfilter), /* Replace with NULL if there's nothing to do at request end */ ++ PHP_MINFO(varfilter), ++#if ZEND_MODULE_API_NO >= 20010901 ++ "0.3.2", /* Replace with version number for your extension */ ++#endif ++ STANDARD_MODULE_PROPERTIES ++}; ++/* }}} */ ++ ++#ifdef COMPILE_DL_VARFILTER ++ZEND_GET_MODULE(varfilter) ++#endif ++ ++/* {{{ PHP_INI ++ */ ++PHP_INI_BEGIN() ++ /* for backward compatibility */ ++ STD_PHP_INI_ENTRY("varfilter.max_request_variables", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.request.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.cookie.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_cookie_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_value_length", "10000", PHP_INI_PERDIR, OnUpdateLong, max_cookie_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.get.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_get_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_get_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_value_length", "512", PHP_INI_PERDIR, OnUpdateLong, max_get_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_depth", "50", PHP_INI_PERDIR, OnUpdateLong, max_get_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.post.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_post_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_post_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_post_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_post_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.upload.max_uploads", "25", PHP_INI_PERDIR, OnUpdateLong, max_uploads, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.disallow_elf_files", "1", PHP_INI_SYSTEM, OnUpdateBool, disallow_elf_files, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.verification_script", NULL, PHP_INI_SYSTEM, OnUpdateString, verification_script, zend_varfilter_globals, varfilter_globals) ++ ++ ++PHP_INI_END() ++/* }}} */ ++ ++/* {{{ php_varfilter_init_globals ++ */ ++static void php_varfilter_init_globals(zend_varfilter_globals *varfilter_globals) ++{ ++ varfilter_globals->max_request_variables = 200; ++ varfilter_globals->max_varname_length = 64; ++ varfilter_globals->max_value_length = 10000; ++ varfilter_globals->max_array_depth = 100; ++ varfilter_globals->max_totalname_length = 256; ++ varfilter_globals->max_array_index_length = 64; ++ ++ varfilter_globals->max_cookie_vars = 100; ++ varfilter_globals->max_cookie_name_length = 64; ++ varfilter_globals->max_cookie_totalname_length = 256; ++ varfilter_globals->max_cookie_value_length = 10000; ++ varfilter_globals->max_cookie_array_depth = 100; ++ varfilter_globals->max_cookie_array_index_length = 64; ++ ++ varfilter_globals->max_get_vars = 100; ++ varfilter_globals->max_get_name_length = 64; ++ varfilter_globals->max_get_totalname_length = 256; ++ varfilter_globals->max_get_value_length = 512; ++ varfilter_globals->max_get_array_depth = 50; ++ varfilter_globals->max_get_array_index_length = 64; ++ ++ varfilter_globals->max_post_vars = 200; ++ varfilter_globals->max_post_name_length = 64; ++ varfilter_globals->max_post_totalname_length = 256; ++ varfilter_globals->max_post_value_length = 65000; ++ varfilter_globals->max_post_array_depth = 100; ++ varfilter_globals->max_post_array_index_length = 64; ++ ++ varfilter_globals->max_uploads = 25; ++ varfilter_globals->disallow_elf_files = 1; ++ varfilter_globals->verification_script = NULL; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINIT_FUNCTION ++ */ ++PHP_MINIT_FUNCTION(varfilter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(varfilter, php_varfilter_init_globals, NULL); ++ REGISTER_INI_ENTRIES(); ++ ++ sapi_register_input_filter(varfilter_input_filter); ++ sapi_register_pre_upload_filter(varfilter_pre_upload_filter); ++ sapi_register_upload_content_filter(varfilter_upload_content_filter); ++ sapi_register_post_upload_filter(varfilter_post_upload_filter); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MSHUTDOWN_FUNCTION ++ */ ++PHP_MSHUTDOWN_FUNCTION(varfilter) ++{ ++// zend_hash_apply_with_arguments(&HG(lists.functionlists), (apply_func_args_t) show_stuff, 0); ++ ++ UNREGISTER_INI_ENTRIES(); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request start */ ++/* {{{ PHP_RINIT_FUNCTION ++ */ ++PHP_RINIT_FUNCTION(varfilter) ++{ ++ VARFILTER_G(cur_request_variables) = 0; ++ VARFILTER_G(cur_get_vars) = 0; ++ VARFILTER_G(cur_post_vars) = 0; ++ VARFILTER_G(cur_cookie_vars) = 0; ++ ++ VARFILTER_G(cur_uploads) = 0; ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request end */ ++/* {{{ PHP_RSHUTDOWN_FUNCTION ++ */ ++PHP_RSHUTDOWN_FUNCTION(varfilter) ++{ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINFO_FUNCTION ++ */ ++PHP_MINFO_FUNCTION(varfilter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_header(2, "Hardening-Patch's variable filter support", "enabled"); ++ php_info_print_table_end(); ++ ++ DISPLAY_INI_ENTRIES(); ++} ++/* }}} */ ++ ++/* {{{ normalize_varname ++ */ ++static void normalize_varname(char *varname) ++{ ++ char *s=varname, *index=NULL, *indexend=NULL, *p; ++ ++ /* overjump leading space */ ++ while (*s == ' ') { ++ s++; ++ } ++ ++ /* and remove it */ ++ if (s != varname) { ++ memmove(varname, s, strlen(s)+1); ++ } ++ ++ for (p=varname; *p && *p != '['; p++) { ++ switch(*p) { ++ case ' ': ++ case '.': ++ *p='_'; ++ break; ++ } ++ } ++ ++ /* find index */ ++ index = strchr(varname, '['); ++ if (index) { ++ index++; ++ s=index; ++ } else { ++ return; ++ } ++ ++ /* done? */ ++ while (index) { ++ ++ while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') { ++ index++; ++ } ++ indexend = strchr(index, ']'); ++ indexend = indexend ? indexend + 1 : index + strlen(index); ++ ++ if (s != index) { ++ memmove(s, index, strlen(index)+1); ++ s += indexend-index; ++ } else { ++ s = indexend; ++ } ++ ++ if (*s == '[') { ++ s++; ++ index = s; ++ } else { ++ index = NULL; ++ } ++ } ++ *s++='\0'; ++} ++/* }}} */ ++ ++/* {{{ SAPI_PRE_UPLOAD_FILTER_FUNC ++ */ ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter) ++{ ++ /* Drop this fileupload if the limit is reached */ ++ if (VARFILTER_G(max_uploads) && VARFILTER_G(max_uploads) <= VARFILTER_G(cur_uploads)) { ++ php_security_log(S_FILES, "configured fileupload limit exceeded - file dropped"); ++ return FAILURE; ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_UPLOAD_CONTENT_FILTER_FUNC ++ */ ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter) ++{ ++ ++ if (VARFILTER_G(disallow_elf_files)) { ++ ++ if (offset == 0 && buffer_len > 10) { ++ ++ if (buffer[0] == 0x7F && buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F') { ++ php_security_log(S_FILES, "uploaded file is an ELF executable - file dropped"); ++ return FAILURE; ++ } ++ } ++ ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_POST_UPLOAD_FILTER_FUNC ++ */ ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter) ++{ ++ int retval = SUCCESS; ++ ++ if (VARFILTER_G(verification_script)) { ++ char cmd[8192]; ++ FILE *in; ++ int first=1; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s", VARFILTER_G(verification_script), tmpfilename); ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_FILES, "unable to execute fileupload verification script - file dropped"); ++ return FAILURE; ++ } ++ ++ retval = FAILURE; ++ ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ if (first) { ++ retval = atoi(cmd) == 1 ? SUCCESS : FAILURE; ++ first = 0; ++ } ++ } ++ pclose(in); ++ } ++ ++ if (retval != SUCCESS) { ++ php_security_log(S_FILES, "fileupload verification script disallows file - file dropped"); ++ return FAILURE; ++ } ++ ++ VARFILTER_G(cur_uploads)++; ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_INPUT_FILTER_FUNC ++ */ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter) ++{ ++ char *index, *prev_index = NULL, *copy_var; ++ unsigned int var_len, total_len, depth = 0, rv; ++ ++ /* Drop this variable if the limit is reached */ ++ if (VARFILTER_G(max_request_variables) && VARFILTER_G(max_request_variables) <= VARFILTER_G(cur_request_variables)) { ++ php_security_log(S_VARS, "configured request variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_vars) && VARFILTER_G(max_get_vars) <= VARFILTER_G(cur_get_vars)) { ++ php_security_log(S_VARS, "configured GET variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_vars) && VARFILTER_G(max_cookie_vars) <= VARFILTER_G(cur_cookie_vars)) { ++ php_security_log(S_VARS, "configured COOKIE variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_vars) && VARFILTER_G(max_post_vars) <= VARFILTER_G(cur_post_vars)) { ++ php_security_log(S_VARS, "configured POST variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ ++ /* Drop this variable if it exceeds the value length limit */ ++ if (VARFILTER_G(max_value_length) && VARFILTER_G(max_value_length) < val_len) { ++ php_security_log(S_VARS, "configured request variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_value_length) && VARFILTER_G(max_get_value_length) < val_len) { ++ php_security_log(S_VARS, "configured GET variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_value_length) && VARFILTER_G(max_cookie_value_length) < val_len) { ++ php_security_log(S_VARS, "configured COOKIE variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_value_length) && VARFILTER_G(max_post_value_length) < val_len) { ++ php_security_log(S_VARS, "configured POST variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Normalize the variable name */ ++ normalize_varname(var); ++ ++ /* Find length of variable name */ ++ index = strchr(var, '['); ++ total_len = strlen(var); ++ var_len = index ? index-var : total_len; ++ ++ /* Drop this variable if it exceeds the varname/total length limit */ ++ if (VARFILTER_G(max_varname_length) && VARFILTER_G(max_varname_length) < var_len) { ++ php_security_log(S_VARS, "configured request variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_totalname_length) && VARFILTER_G(max_totalname_length) < total_len) { ++ php_security_log(S_VARS, "configured request variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_name_length) && VARFILTER_G(max_get_name_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_get_totalname_length) && VARFILTER_G(max_get_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_name_length) && VARFILTER_G(max_cookie_name_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_cookie_totalname_length) && VARFILTER_G(max_cookie_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_name_length) && VARFILTER_G(max_post_name_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_post_totalname_length) && VARFILTER_G(max_post_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Find out array depth */ ++ while (index) { ++ unsigned int index_length; ++ ++ depth++; ++ index = strchr(index+1, '['); ++ ++ if (prev_index) { ++ index_length = index ? index - 1 - prev_index - 1: strlen(prev_index); ++ ++ if (VARFILTER_G(max_array_index_length) && VARFILTER_G(max_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured request variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_index_length) && VARFILTER_G(max_get_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured GET variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_index_length) && VARFILTER_G(max_cookie_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured COOKIE variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_index_length) && VARFILTER_G(max_post_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured POST variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ prev_index = index; ++ } ++ ++ } ++ ++ /* Drop this variable if it exceeds the array depth limit */ ++ if (VARFILTER_G(max_array_depth) && VARFILTER_G(max_array_depth) < depth) { ++ php_security_log(S_VARS, "configured request variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_depth) && VARFILTER_G(max_get_array_depth) < depth) { ++ php_security_log(S_VARS, "configured GET variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_depth) && VARFILTER_G(max_cookie_array_depth) < depth) { ++ php_security_log(S_VARS, "configured COOKIE variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_depth) && VARFILTER_G(max_post_array_depth) < depth) { ++ php_security_log(S_VARS, "configured POST variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Drop this variable if it is one of GLOBALS, _GET, _POST, ... */ ++ /* This is to protect several silly scripts that do globalizing themself */ ++ ++ switch (var_len) { ++ case 18: ++ if (memcmp(var, "HTTP_RAW_POST_DATA", 18)==0) goto protected_varname; ++ break; ++ case 17: ++ if (memcmp(var, "HTTP_SESSION_VARS", 17)==0) goto protected_varname; ++ break; ++ case 16: ++ if (memcmp(var, "HTTP_SERVER_VARS", 16)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_COOKIE_VARS", 16)==0) goto protected_varname; ++ break; ++ case 15: ++ if (memcmp(var, "HTTP_POST_FILES", 15)==0) goto protected_varname; ++ break; ++ case 14: ++ if (memcmp(var, "HTTP_POST_VARS", 14)==0) goto protected_varname; ++ break; ++ case 13: ++ if (memcmp(var, "HTTP_GET_VARS", 13)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_ENV_VARS", 13)==0) goto protected_varname; ++ break; ++ case 8: ++ if (memcmp(var, "_SESSION", 8)==0) goto protected_varname; ++ if (memcmp(var, "_REQUEST", 8)==0) goto protected_varname; ++ break; ++ case 7: ++ if (memcmp(var, "GLOBALS", 7)==0) goto protected_varname; ++ if (memcmp(var, "_COOKIE", 7)==0) goto protected_varname; ++ if (memcmp(var, "_SERVER", 7)==0) goto protected_varname; ++ break; ++ case 6: ++ if (memcmp(var, "_FILES", 6)==0) goto protected_varname; ++ break; ++ case 5: ++ if (memcmp(var, "_POST", 5)==0) goto protected_varname; ++ break; ++ case 4: ++ if (memcmp(var, "_ENV", 4)==0) goto protected_varname; ++ if (memcmp(var, "_GET", 4)==0) goto protected_varname; ++ break; ++ } ++ ++ /* Okay let PHP register this variable */ ++ VARFILTER_G(cur_request_variables)++; ++ switch (arg) { ++ case PARSE_GET: ++ VARFILTER_G(cur_get_vars)++; ++ break; ++ case PARSE_COOKIE: ++ VARFILTER_G(cur_cookie_vars)++; ++ break; ++ case PARSE_POST: ++ VARFILTER_G(cur_post_vars)++; ++ break; ++ } ++ ++ if (new_val_len) { ++ *new_val_len = val_len; ++ } ++ ++ return 1; ++protected_varname: ++ php_security_log(S_VARS, "tried to register forbidden variable '%s' through %s variables", var, arg == PARSE_GET ? "GET" : arg == PARSE_POST ? "POST" : "COOKIE"); ++ return 0; ++} ++/* }}} */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: noet sw=4 ts=4 fdm=marker ++ * vim<600: noet sw=4 ts=4 ++ */ ++ ++ +diff -Naur php-4.4.0RC2/main/fopen_wrappers.c hardening-patch-4.4.0RC2-0.3.2/main/fopen_wrappers.c +--- php-4.4.0RC2/main/fopen_wrappers.c 2005-02-03 00:44:07.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/main/fopen_wrappers.c 2005-07-09 08:53:20.652598992 +0200 +@@ -166,6 +166,21 @@ + char *pathbuf; + char *ptr; + char *end; ++ char path_copy[MAXPATHLEN]; ++ int path_len; ++ ++ /* Special case path ends with a trailing slash */ ++ path_len = strlen(path); ++ if (path_len >= MAXPATHLEN) { ++ errno = EPERM; /* we deny permission to open it */ ++ return -1; ++ } ++ if (path_len > 0 && path[path_len-1] == PHP_DIR_SEPARATOR) { ++ memcpy(path_copy, path, path_len+1); ++ while (path_len > 0 && path_copy[path_len-1] == PHP_DIR_SEPARATOR) path_len--; ++ path_copy[path_len] = '\0'; ++ path = (const char *)&path_copy; ++ } + + pathbuf = estrdup(PG(open_basedir)); + +diff -Naur php-4.4.0RC2/main/hardened_globals.h hardening-patch-4.4.0RC2-0.3.2/main/hardened_globals.h +--- php-4.4.0RC2/main/hardened_globals.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/main/hardened_globals.h 2005-07-09 08:53:20.653598840 +0200 +@@ -0,0 +1,56 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_GLOBALS_H ++#define HARDENED_GLOBALS_H ++ ++typedef struct _hardened_globals hardened_globals_struct; ++ ++#ifdef ZTS ++# define HG(v) TSRMG(hardened_globals_id, hardened_globals_struct *, v) ++extern int hardened_globals_id; ++#else ++# define HG(v) (hardened_globals.v) ++extern struct _hardened_globals hardened_globals; ++#endif ++ ++ ++struct _hardened_globals { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_1; ++ unsigned int canary_2; ++#endif ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_3; ++ unsigned int canary_4; ++ unsigned int ll_canary_inited; ++#endif ++ zend_bool hphp_sql_bailout_on_error; ++ zend_bool hphp_multiheader; ++ unsigned int dummy; ++}; ++ ++ ++#endif /* HARDENED_GLOBALS_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Naur php-4.4.0RC2/main/hardening_patch.c hardening-patch-4.4.0RC2-0.3.2/main/hardening_patch.c +--- php-4.4.0RC2/main/hardening_patch.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/main/hardening_patch.c 2005-07-09 08:53:20.653598840 +0200 +@@ -0,0 +1,322 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: hardening_patch.c,v 1.2 2004/11/21 09:38:52 ionic Exp $ */ ++ ++#include "php.h" ++ ++#include ++#include ++ ++#if HAVE_UNISTD_H ++#include ++#endif ++#include "SAPI.h" ++#include "php_globals.h" ++ ++#if HARDENING_PATCH ++ ++#ifdef HAVE_SYS_SOCKET_H ++#include ++#endif ++ ++#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE) ++#undef AF_UNIX ++#endif ++ ++#if defined(AF_UNIX) ++#include ++#endif ++ ++#define SYSLOG_PATH "/dev/log" ++ ++#include "snprintf.h" ++ ++#include "hardening_patch.h" ++ ++#ifdef ZTS ++#include "hardened_globals.h" ++int hardened_globals_id; ++#else ++struct _hardened_globals hardened_globals; ++#endif ++ ++static void hardened_globals_ctor(hardened_globals_struct *hardened_globals TSRMLS_DC) ++{ ++ memset(hardened_globals, 0, sizeof(*hardened_globals)); ++} ++ ++ ++PHPAPI void hardened_startup() ++{ ++#ifdef ZTS ++ ts_allocate_id(&hardened_globals_id, sizeof(hardened_globals_struct), (ts_allocate_ctor) hardened_globals_ctor, NULL); ++#else ++ hardened_globals_ctor(&hardened_globals TSRMLS_CC); ++#endif ++} ++ ++char *loglevel2string(int loglevel) ++{ ++ switch (loglevel) { ++ case S_FILES: ++ return "FILES"; ++ case S_INCLUDE: ++ return "INCLUDE"; ++ case S_MEMORY: ++ return "MEMORY"; ++ case S_MISC: ++ return "MISC"; ++ case S_SQL: ++ return "SQL"; ++ case S_EXECUTOR: ++ return "EXECUTOR"; ++ case S_VARS: ++ return "VARS"; ++ default: ++ return "UNKNOWN"; ++ } ++} ++ ++PHPAPI void php_security_log(int loglevel, char *fmt, ...) ++{ ++#if defined(AF_UNIX) ++ int s, r, i=0; ++ struct sockaddr_un saun; ++ char buf[4096+64]; ++ char error[4096+100]; ++ char *ip_address; ++ char *fname; ++ int lineno; ++ va_list ap; ++ TSRMLS_FETCH(); ++ ++ if (EG(hphp_log_use_x_forwarded_for)) { ++ ip_address = sapi_getenv("HTTP_X_FORWARDED_FOR", 20 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "X-FORWARDED-FOR not set"; ++ } ++ } else { ++ ip_address = sapi_getenv("REMOTE_ADDR", 11 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "REMOTE_ADDR not set"; ++ } ++ } ++ ++ ++ va_start(ap, fmt); ++ ap_php_vsnprintf(error, sizeof(error), fmt, ap); ++ va_end(ap); ++ while (error[i]) { ++ if (error[i] < 32) error[i] = '.'; ++ i++; ++ } ++ ++ if (zend_is_executing(TSRMLS_C)) { ++ lineno = zend_get_executed_lineno(TSRMLS_C); ++ fname = zend_get_executed_filename(TSRMLS_C); ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s', line %u)", error, ip_address, fname, lineno); ++ } else { ++ fname = sapi_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC); ++ if (fname==NULL) { ++ fname = "unknown"; ++ } ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s')", error, ip_address, fname); ++ } ++ ++ /* Syslog-Logging disabled? */ ++ if ((EG(hphp_log_syslog) & loglevel)==0) { ++ goto log_sapi; ++ } ++ ++ ap_php_snprintf(error, sizeof(error), "<%u>hphp[%u]: %s\n", EG(hphp_log_syslog_facility)|EG(hphp_log_syslog_priority),getpid(),buf); ++ ++ s = socket(AF_UNIX, SOCK_DGRAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ s = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ goto log_sapi; ++ } ++ } ++ send(s, error, strlen(error), 0); ++ ++ close(s); ++ ++log_sapi: ++ /* SAPI Logging activated? */ ++ if ((EG(hphp_log_syslog) & loglevel)!=0) { ++ sapi_module.log_message(buf); ++ } ++ ++log_script: ++ /* script logging activaed? */ ++ if (((EG(hphp_log_script) & loglevel)!=0) && EG(hphp_log_scriptname)!=NULL) { ++ char cmd[8192], *cmdpos, *bufpos; ++ FILE *in; ++ int space; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s \'", EG(hphp_log_scriptname), loglevel2string(loglevel)); ++ space = sizeof(cmd) - strlen(cmd); ++ cmdpos = cmd + strlen(cmd); ++ bufpos = buf; ++ if (space <= 1) return; ++ while (space > 2 && *bufpos) { ++ if (*bufpos == '\'') { ++ if (space<=5) break; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\\'; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\''; ++ bufpos++; ++ space-=4; ++ } else { ++ *cmdpos++ = *bufpos++; ++ space--; ++ } ++ } ++ *cmdpos++ = '\''; ++ *cmdpos = 0; ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ return; ++ } ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ } ++ pclose(in); ++ } ++ ++#endif ++} ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++PHPAPI unsigned int php_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++ ++PHPAPI int php_is_valid_include(zval *z) ++{ ++ char *filename; ++ int len, i; ++ TSRMLS_FETCH(); ++ ++ /* must be of type string */ ++ if (z->type != IS_STRING || z->value.str.val == NULL) { ++ return (0); ++ } ++ ++ /* short cut */ ++ filename = z->value.str.val; ++ len = z->value.str.len; ++ ++ /* 1. must be shorter than MAXPATHLEN */ ++ if (len > MAXPATHLEN) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') longer than MAXPATHLEN chars", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 2. must not be cutted */ ++ if (len != strlen(filename)) { ++ char *fname = estrndup(filename, len); ++ for (i=0; fname[i]; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename truncated by a \\0 after '%s'", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 3. must not be a URL */ ++ if (strstr(filename, "://")) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') is an URL", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 4. must not be an uploaded file */ ++ if (SG(rfc1867_uploaded_files)) { ++ if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, len+1)) { ++ php_security_log(S_INCLUDE, "Include filename is an uploaded file"); ++ return (0); ++ } ++ } ++ ++ /* passed all tests */ ++ return (1); ++} ++ ++#endif ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Naur php-4.4.0RC2/main/hardening_patch.h hardening-patch-4.4.0RC2-0.3.2/main/hardening_patch.h +--- php-4.4.0RC2/main/hardening_patch.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/main/hardening_patch.h 2005-07-09 08:58:18.505318496 +0200 +@@ -0,0 +1,46 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENING_PATCH_H ++#define HARDENING_PATCH_H ++ ++#include "zend.h" ++ ++#if HARDENING_PATCH ++PHPAPI void php_security_log(int loglevel, char *fmt, ...); ++PHPAPI void hardened_startup(); ++#define HARDENING_PATCH_VERSION "0.3.2" ++ ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++PHPAPI unsigned int php_canary(); ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++PHPAPI int php_is_valid_include(zval *z); ++#endif ++ ++#endif /* HARDENING_PATCH_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Naur php-4.4.0RC2/main/hardening_patch.m4 hardening-patch-4.4.0RC2-0.3.2/main/hardening_patch.m4 +--- php-4.4.0RC2/main/hardening_patch.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/main/hardening_patch.m4 2005-07-09 08:53:20.654598688 +0200 +@@ -0,0 +1,95 @@ ++dnl ++dnl $Id: hardening_patch.m4,v 1.1 2004/11/14 13:24:24 ionic Exp $ ++dnl ++dnl This file contains Hardening Patch for PHP specific autoconf functions. ++dnl ++ ++AC_ARG_ENABLE(hardening-patch-mm-protect, ++[ --disable-hardening-patch-mm-protect Disable the Memory Manager protection.],[ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-ll-protect, ++[ --disable-hardening-patch-ll-protect Disable the Linked List protection.],[ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-inc-protect, ++[ --disable-hardening-patch-inc-protect Disable include/require protection.],[ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-fmt-protect, ++[ --disable-hardening-patch-fmt-protect Disable format string protection.],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-hash-protect, ++[ --disable-hardening-patch-hash-protect Disable HashTable destructor protection.],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++]) ++ ++AC_MSG_CHECKING(whether to protect the Zend Memory Manager) ++AC_MSG_RESULT($DO_HARDENING_PATCH_MM_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the Zend Linked Lists) ++AC_MSG_RESULT($DO_HARDENING_PATCH_LL_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect include/require statements) ++AC_MSG_RESULT($DO_HARDENING_PATCH_INC_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect PHP Format String functions) ++AC_MSG_RESULT($DO_HARDENING_PATCH_FMT_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the destructor of Zend HashTables) ++AC_MSG_RESULT($DO_HARDENING_PATCH_HASH_PROTECT) ++ ++ ++AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 1, [Memory Manager Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 0, [Memory Manager Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 1, [Linked List Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 0, [Linked List Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 1, [Include/Require Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 0, [Include/Require Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 1, [Fmt String Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 0, [Fmt String Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 1, [HashTable DTOR Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 0, [HashTable DTOR Protection]) ++fi ++ +diff -Naur php-4.4.0RC2/main/main.c hardening-patch-4.4.0RC2-0.3.2/main/main.c +--- php-4.4.0RC2/main/main.c 2005-06-20 21:59:43.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/main/main.c 2005-07-09 08:53:20.655598536 +0200 +@@ -100,6 +100,10 @@ + PHPAPI int core_globals_id; + #endif + ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#endif ++ + #define ERROR_BUF_LEN 1024 + + typedef struct { +@@ -150,10 +154,33 @@ + */ + static PHP_INI_MH(OnChangeMemoryLimit) + { ++#if HARDENING_PATCH ++ long orig_memory_limit; ++ ++ if (entry->modified) { ++ orig_memory_limit = zend_atoi(entry->orig_value, entry->orig_value_length); ++ } else { ++ orig_memory_limit = 1<<30; ++ } ++ if (orig_memory_limit < 0 || orig_memory_limit > (1<<30)) { ++ orig_memory_limit = 1<<30; ++ } ++#endif + if (new_value) { + PG(memory_limit) = zend_atoi(new_value, new_value_length); ++#if HARDENING_PATCH ++ if (PG(memory_limit) > orig_memory_limit) { ++ PG(memory_limit) = orig_memory_limit; ++ php_security_log(S_MISC, "script tried to increase memory_limit above allowed value"); ++ return FAILURE; ++ } ++#endif + } else { ++#if HARDENING_PATCH ++ PG(memory_limit) = orig_memory_limit; ++#else + PG(memory_limit) = 1<<30; /* effectively, no limit */ ++#endif + } + return zend_set_memory_limit(PG(memory_limit)); + } +@@ -1096,6 +1123,10 @@ + tsrm_ls = ts_resource(0); + #endif + ++#if HARDENING_PATCH ++ hardened_startup(); ++#endif ++ + sapi_initialize_empty_request(TSRMLS_C); + sapi_activate(TSRMLS_C); + +@@ -1108,6 +1139,12 @@ + php_output_startup(); + php_output_activate(TSRMLS_C); + ++#if HARDENING_PATCH_INC_PROTECT ++ zuf.is_valid_include = php_is_valid_include; ++#endif ++#if HARDENING_PATCH ++ zuf.security_log_function = php_security_log; ++#endif + zuf.error_function = php_error_cb; + zuf.printf_function = php_printf; + zuf.write_function = php_body_write_wrapper; +@@ -1209,6 +1246,10 @@ + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, sizeof(PHP_CONFIG_FILE_PATH)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("HARDENING_PATCH", 1, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_STRINGL_CONSTANT("HARDENING_PATCH_VERSION", HARDENING_PATCH_VERSION, sizeof(HARDENING_PATCH_VERSION)-1, CONST_PERSISTENT | CONST_CS); ++#endif + REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("PHP_INT_MAX", LONG_MAX, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", sizeof(long), CONST_PERSISTENT | CONST_CS); +@@ -1316,7 +1357,7 @@ + */ + static inline void php_register_server_variables(TSRMLS_D) + { +- zval *array_ptr=NULL; ++ zval *array_ptr=NULL, *vptr; + + ALLOC_ZVAL(array_ptr); + array_init(array_ptr); +@@ -1326,6 +1367,16 @@ + /* Server variables */ + if (sapi_module.register_server_variables) { + sapi_module.register_server_variables(array_ptr TSRMLS_CC); ++ if (zend_hash_find(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA"), (void **)&vptr)==SUCCESS) { ++ char *str; ++ if (vptr->type != IS_STRING) { ++ str = "Array"; ++ } else { ++ str = vptr->value.str.val; ++ } ++ php_security_log(S_VARS, "Attacker tried to overwrite HTTP_RAW_POST_DATA with '%s' through a HTTP header", str); ++ zend_hash_del(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA")); ++ } + } + + /* PHP Authentication support */ +diff -Naur php-4.4.0RC2/main/php_config.h.in hardening-patch-4.4.0RC2-0.3.2/main/php_config.h.in +--- php-4.4.0RC2/main/php_config.h.in 2005-07-01 12:08:17.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/main/php_config.h.in 2005-07-09 08:53:20.656598384 +0200 +@@ -860,6 +860,39 @@ + /* Enabling BIND8 compatibility for Panther */ + #undef BIND_8_COMPAT + ++/* Hardening-Patch */ ++#undef HARDENING_PATCH ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ + /* Whether you have AOLserver */ + #undef HAVE_AOLSERVER + +@@ -1143,6 +1176,12 @@ + /* Define if you have the getaddrinfo function */ + #undef HAVE_GETADDRINFO + ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ + /* Whether system headers declare timezone */ + #undef HAVE_DECLARED_TIMEZONE + +diff -Naur php-4.4.0RC2/main/php_content_types.c hardening-patch-4.4.0RC2-0.3.2/main/php_content_types.c +--- php-4.4.0RC2/main/php_content_types.c 2002-12-31 17:26:14.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/main/php_content_types.c 2005-07-09 08:53:20.657598232 +0200 +@@ -77,6 +77,7 @@ + sapi_register_post_entries(php_post_entries); + sapi_register_default_post_reader(php_default_post_reader); + sapi_register_treat_data(php_default_treat_data); ++ sapi_register_input_filter(php_default_input_filter); + return SUCCESS; + } + /* }}} */ +diff -Naur php-4.4.0RC2/main/php.h hardening-patch-4.4.0RC2-0.3.2/main/php.h +--- php-4.4.0RC2/main/php.h 2005-04-17 15:37:29.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/main/php.h 2005-07-09 08:53:20.657598232 +0200 +@@ -26,7 +26,7 @@ + #include + #endif + +-#define PHP_API_VERSION 20020918 ++#define PHP_API_VERSION 1020050626 + #define PHP_HAVE_STREAMS + #define YYDEBUG 0 + +@@ -35,11 +35,19 @@ + #include "zend_qsort.h" + #include "php_compat.h" + ++ + #include "zend_API.h" + + #undef sprintf + #define sprintf php_sprintf + ++#if HARDENING_PATCH ++#if HAVE_REALPATH ++#undef realpath ++#define realpath php_realpath ++#endif ++#endif ++ + /* PHP's DEBUG value must match Zend's ZEND_DEBUG value */ + #undef PHP_DEBUG + #define PHP_DEBUG ZEND_DEBUG +@@ -435,6 +443,10 @@ + #endif + #endif /* !XtOffsetOf */ + ++#if HARDENING_PATCH ++#include "hardening_patch.h" ++#endif ++ + #endif + + /* +diff -Naur php-4.4.0RC2/main/php_variables.c hardening-patch-4.4.0RC2-0.3.2/main/php_variables.c +--- php-4.4.0RC2/main/php_variables.c 2005-05-17 20:42:35.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/main/php_variables.c 2005-07-09 08:53:20.658598080 +0200 +@@ -225,17 +225,28 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(PARSE_POST, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, "&", &strtok_buf); + } + } + ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter) ++{ ++ /* TODO: check .ini setting here and apply user-defined input filter */ ++ *new_val_len = val_len; ++ return 1; ++} ++ + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) + { + char *res = NULL, *var, *val, *separator=NULL; +@@ -313,15 +324,26 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } else { ++ unsigned int val_len, new_val_len; ++ + php_url_decode(var, strlen(var)); +- php_register_variable_safe(var, "", 0, array_ptr TSRMLS_CC); ++ val_len = 0; ++ val = estrndup("", 0); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, separator, &strtok_buf); + } +diff -Naur php-4.4.0RC2/main/rfc1867.c hardening-patch-4.4.0RC2-0.3.2/main/rfc1867.c +--- php-4.4.0RC2/main/rfc1867.c 2005-04-04 16:59:58.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/main/rfc1867.c 2005-07-09 08:53:20.659597928 +0200 +@@ -127,6 +127,7 @@ + #define UPLOAD_ERROR_C 3 /* Partially uploaded */ + #define UPLOAD_ERROR_D 4 /* No file uploaded */ + #define UPLOAD_ERROR_E 6 /* Missing /tmp or similar directory */ ++#define UPLOAD_ERROR_F 7 /* Filter forbids upload */ + + void php_rfc1867_register_constants(TSRMLS_D) + { +@@ -136,6 +137,7 @@ + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL", UPLOAD_ERROR_C, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE", UPLOAD_ERROR_D, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FILTER", UPLOAD_ERROR_F, CONST_CS | CONST_PERSISTENT); + } + + static void normalize_protected_variable(char *varname TSRMLS_DC) +@@ -844,6 +846,7 @@ + char buff[FILLUNIT]; + char *cd=NULL,*param=NULL,*filename=NULL, *tmp=NULL; + int blen=0, wlen=0; ++ unsigned long offset; + + zend_llist_clean(&header); + +@@ -891,21 +894,24 @@ + if (!filename && param) { + + char *value = multipart_buffer_read_body(mbuff TSRMLS_CC); ++ unsigned int new_val_len; /* Dummy variable */ + + if (!value) { + value = estrdup(""); + } + ++ if (sapi_module.input_filter(PARSE_POST, param, &value, strlen(value), &new_val_len TSRMLS_CC)) { + #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) +- if (php_mb_encoding_translation(TSRMLS_C)) { +- php_mb_gpc_stack_variable(param, value, &val_list, &len_list, +- &num_vars, &num_vars_max TSRMLS_CC); +- } else { +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); +- } ++ if (php_mb_encoding_translation(TSRMLS_C)) { ++ php_mb_gpc_stack_variable(param, value, &val_list, &len_list, ++ &num_vars, &num_vars_max TSRMLS_CC); ++ } else { ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ } + #else +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); + #endif ++ } + if (!strcasecmp(param, "MAX_FILE_SIZE")) { + max_file_size = atol(value); + } +@@ -981,6 +987,11 @@ + cancel_upload = UPLOAD_ERROR_D; + } + ++ if (sapi_module.pre_upload_filter && sapi_module.pre_upload_filter(param, filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ ++ offset = 0; + while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff) TSRMLS_CC))) + { + if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize)) { +@@ -990,6 +1001,11 @@ + sapi_module.sapi_error(E_WARNING, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename); + cancel_upload = UPLOAD_ERROR_B; + } else if (blen > 0) { ++ ++ if (sapi_module.upload_content_filter && sapi_module.upload_content_filter(offset, buff, blen, &blen TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ + wlen = write(fd, buff, blen); + + if (wlen < blen) { +@@ -997,6 +1013,7 @@ + cancel_upload = UPLOAD_ERROR_C; + } else { + total_bytes += wlen; ++ offset += wlen; + } + } + } +@@ -1011,6 +1028,10 @@ + } + #endif + ++ if (!cancel_upload && sapi_module.post_upload_filter && sapi_module.post_upload_filter(temp_filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ + if (cancel_upload) { + if (temp_filename) { + if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */ +diff -Naur php-4.4.0RC2/main/SAPI.c hardening-patch-4.4.0RC2-0.3.2/main/SAPI.c +--- php-4.4.0RC2/main/SAPI.c 2005-02-22 15:46:24.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/main/SAPI.c 2005-07-09 08:53:20.659597928 +0200 +@@ -831,6 +831,31 @@ + return SUCCESS; + } + ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) ++{ ++ sapi_module.input_filter = input_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)) ++{ ++ sapi_module.pre_upload_filter = pre_upload_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)) ++{ ++ sapi_module.upload_content_filter = upload_content_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)) ++{ ++ sapi_module.post_upload_filter = post_upload_filter; ++ return SUCCESS; ++} ++ ++ + + SAPI_API int sapi_flush(TSRMLS_D) + { +diff -Naur php-4.4.0RC2/main/SAPI.h hardening-patch-4.4.0RC2-0.3.2/main/SAPI.h +--- php-4.4.0RC2/main/SAPI.h 2003-04-09 22:27:55.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/main/SAPI.h 2005-07-09 08:53:20.660597776 +0200 +@@ -101,9 +101,10 @@ + char *current_user; + int current_user_length; + +- /* this is necessary for CLI module */ +- int argc; +- char **argv; ++ /* this is necessary for CLI module */ ++ int argc; ++ char **argv; ++ + } sapi_request_info; + + +@@ -177,6 +178,10 @@ + SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry); + SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D)); + SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC)); ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)); ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)); ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)); ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)); + + SAPI_API int sapi_flush(TSRMLS_D); + SAPI_API struct stat *sapi_get_stat(TSRMLS_D); +@@ -238,8 +243,15 @@ + int (*get_target_uid)(uid_t * TSRMLS_DC); + int (*get_target_gid)(gid_t * TSRMLS_DC); + ++ unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); ++ ++ unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC); ++ unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC); ++ unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC); ++ + void (*ini_defaults)(HashTable *configuration_hash); + int phpinfo_as_text; ++ + }; + + +@@ -262,16 +274,26 @@ + + #define SAPI_DEFAULT_MIMETYPE "text/html" + #define SAPI_DEFAULT_CHARSET "" ++ ++#if HARDENING_PATCH ++#define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION " with Hardening-Patch" ++#else + #define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION ++#endif + + #define SAPI_POST_READER_FUNC(post_reader) void post_reader(TSRMLS_D) + #define SAPI_POST_HANDLER_FUNC(post_handler) void post_handler(char *content_type_dup, void *arg TSRMLS_DC) + + #define SAPI_TREAT_DATA_FUNC(treat_data) void treat_data(int arg, char *str, zval* destArray TSRMLS_DC) ++#define SAPI_INPUT_FILTER_FUNC(input_filter) unsigned int input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) ++#define SAPI_PRE_UPLOAD_FILTER_FUNC(pre_upload_filter) unsigned int pre_upload_filter(char *varname, char *filename TSRMLS_DC) ++#define SAPI_UPLOAD_CONTENT_FILTER_FUNC(upload_content_filter) unsigned int upload_content_filter(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC) ++#define SAPI_POST_UPLOAD_FILTER_FUNC(post_upload_filter) unsigned int post_upload_filter(char *tmpfilename TSRMLS_DC) + + SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data); + SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader); + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data); ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter); + + #define STANDARD_SAPI_MODULE_PROPERTIES + +diff -Naur php-4.4.0RC2/main/snprintf.c hardening-patch-4.4.0RC2-0.3.2/main/snprintf.c +--- php-4.4.0RC2/main/snprintf.c 2005-04-08 07:44:53.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/main/snprintf.c 2005-07-09 08:53:20.661597624 +0200 +@@ -1013,7 +1013,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Naur php-4.4.0RC2/main/spprintf.c hardening-patch-4.4.0RC2-0.3.2/main/spprintf.c +--- php-4.4.0RC2/main/spprintf.c 2005-04-08 07:44:53.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/main/spprintf.c 2005-07-09 08:53:20.661597624 +0200 +@@ -630,7 +630,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = xbuf->len; ++#endif + break; + + /* +diff -Naur php-4.4.0RC2/php.ini-dist hardening-patch-4.4.0RC2-0.3.2/php.ini-dist +--- php-4.4.0RC2/php.ini-dist 2005-04-28 15:14:45.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/php.ini-dist 2005-07-09 08:53:20.662597472 +0200 +@@ -1112,6 +1112,177 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Naur php-4.4.0RC2/php.ini-recommended hardening-patch-4.4.0RC2-0.3.2/php.ini-recommended +--- php-4.4.0RC2/php.ini-recommended 2005-04-28 15:14:46.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/php.ini-recommended 2005-07-09 08:53:20.663597320 +0200 +@@ -1110,6 +1110,177 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Naur php-4.4.0RC2/README.input_filter hardening-patch-4.4.0RC2-0.3.2/README.input_filter +--- php-4.4.0RC2/README.input_filter 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/README.input_filter 2005-07-09 08:53:20.664597168 +0200 +@@ -0,0 +1,193 @@ ++Input Filter Support ported from PHP 5 ++-------------------------------------- ++ ++XSS (Cross Site Scripting) hacks are becoming more and more prevalent, ++and can be quite difficult to prevent. Whenever you accept user data ++and somehow display this data back to users, you are likely vulnerable ++to XSS hacks. ++ ++The Input Filter support in PHP 5 is aimed at providing the framework ++through which a company-wide or site-wide security policy can be ++enforced. It is implemented as a SAPI hook and is called from the ++treat_data and post handler functions. To implement your own security ++policy you will need to write a standard PHP extension. ++ ++A simple implementation might look like the following. This stores the ++original raw user data and adds a my_get_raw() function while the normal ++$_POST, $_GET and $_COOKIE arrays are only populated with stripped ++data. In this simple example all I am doing is calling strip_tags() on ++the data. If register_globals is turned on, the default globals that ++are created will be stripped ($foo) while a $RAW_foo is created with the ++original user input. ++ ++ZEND_BEGIN_MODULE_GLOBALS(my_input_filter) ++ zval *post_array; ++ zval *get_array; ++ zval *cookie_array; ++ZEND_END_MODULE_GLOBALS(my_input_filter) ++ ++#ifdef ZTS ++#define IF_G(v) TSRMG(my_input_filter_globals_id, zend_my_input_filter_globals *, v) ++#else ++#define IF_G(v) (my_input_filter_globals.v) ++#endif ++ ++ZEND_DECLARE_MODULE_GLOBALS(my_input_filter) ++ ++function_entry my_input_filter_functions[] = { ++ PHP_FE(my_get_raw, NULL) ++ {NULL, NULL, NULL} ++}; ++ ++zend_module_entry my_input_filter_module_entry = { ++ STANDARD_MODULE_HEADER, ++ "my_input_filter", ++ my_input_filter_functions, ++ PHP_MINIT(my_input_filter), ++ PHP_MSHUTDOWN(my_input_filter), ++ NULL, ++ PHP_RSHUTDOWN(my_input_filter), ++ PHP_MINFO(my_input_filter), ++ "0.1", ++ STANDARD_MODULE_PROPERTIES ++}; ++ ++PHP_MINIT_FUNCTION(my_input_filter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(my_input_filter, php_my_input_filter_init_globals, NULL); ++ ++ REGISTER_LONG_CONSTANT("POST", PARSE_POST, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("GET", PARSE_GET, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("COOKIE", PARSE_COOKIE, CONST_CS | CONST_PERSISTENT); ++ ++ sapi_register_input_filter(my_sapi_input_filter); ++ return SUCCESS; ++} ++ ++PHP_RSHUTDOWN_FUNCTION(my_input_filter) ++{ ++ if(IF_G(get_array)) { ++ zval_ptr_dtor(&IF_G(get_array)); ++ IF_G(get_array) = NULL; ++ } ++ if(IF_G(post_array)) { ++ zval_ptr_dtor(&IF_G(post_array)); ++ IF_G(post_array) = NULL; ++ } ++ if(IF_G(cookie_array)) { ++ zval_ptr_dtor(&IF_G(cookie_array)); ++ IF_G(cookie_array) = NULL; ++ } ++ return SUCCESS; ++} ++ ++PHP_MINFO_FUNCTION(my_input_filter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_row( 2, "My Input Filter Support", "enabled" ); ++ php_info_print_table_row( 2, "Revision", "$Revision: 1.1 $"); ++ php_info_print_table_end(); ++} ++ ++/* The filter handler. If you return 1 from it, then PHP also registers the ++ * (modified) variable. Returning 0 prevents PHP from registering the variable; ++ * you can use this if your filter already registers the variable under a ++ * different name, or if you just don't want the variable registered at all. */ ++SAPI_INPUT_FILTER_FUNC(my_sapi_input_filter) ++{ ++ zval new_var; ++ zval *array_ptr = NULL; ++ char *raw_var; ++ int var_len; ++ ++ assert(*val != NULL); ++ ++ switch(arg) { ++ case PARSE_GET: ++ if(!IF_G(get_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(get_array) = array_ptr; ++ break; ++ case PARSE_POST: ++ if(!IF_G(post_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(post_array) = array_ptr; ++ break; ++ case PARSE_COOKIE: ++ if(!IF_G(cookie_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(cookie_array) = array_ptr; ++ break; ++ } ++ Z_STRLEN(new_var) = val_len; ++ Z_STRVAL(new_var) = estrndup(*val, val_len); ++ Z_TYPE(new_var) = IS_STRING; ++ ++ var_len = strlen(var); ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ ++ php_register_variable_ex(raw_var, &new_var, array_ptr TSRMLS_DC); ++ ++ php_strip_tags(*val, val_len, NULL, NULL, 0); ++ ++ *new_val_len = strlen(*val); ++ return 1; ++} ++ ++PHP_FUNCTION(my_get_raw) ++{ ++ long arg; ++ char *var; ++ int var_len; ++ zval **tmp; ++ zval *array_ptr = NULL; ++ HashTable *hash_ptr; ++ char *raw_var; ++ ++ if(zend_parse_parameters(2 TSRMLS_CC, "ls", &arg, &var, &var_len) == FAILURE) { ++ return; ++ } ++ ++ switch(arg) { ++ case PARSE_GET: ++ array_ptr = IF_G(get_array); ++ break; ++ case PARSE_POST: ++ array_ptr = IF_G(post_array); ++ break; ++ case PARSE_COOKIE: ++ array_ptr = IF_G(post_array); ++ break; ++ } ++ ++ if(!array_ptr) RETURN_FALSE; ++ ++ /* ++ * I'm changing the variable name here because when running with register_globals on, ++ * the variable will end up in the global symbol table ++ */ ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ hash_ptr = HASH_OF(array_ptr); ++ ++ if(zend_hash_find(hash_ptr, raw_var, var_len+5, (void **)&tmp) == SUCCESS) { ++ *return_value = **tmp; ++ zval_copy_ctor(return_value); ++ } else { ++ RETVAL_FALSE; ++ } ++ efree(raw_var); ++} ++ +diff -Naur php-4.4.0RC2/sapi/apache/mod_php4.c hardening-patch-4.4.0RC2-0.3.2/sapi/apache/mod_php4.c +--- php-4.4.0RC2/sapi/apache/mod_php4.c 2005-05-19 18:14:46.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/sapi/apache/mod_php4.c 2005-07-09 08:53:20.665597016 +0200 +@@ -452,7 +452,7 @@ + sapi_apache_get_fd, + sapi_apache_force_http_10, + sapi_apache_get_target_uid, +- sapi_apache_get_target_gid ++ sapi_apache_get_target_gid, + }; + /* }}} */ + +@@ -898,7 +898,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component("PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component("PHP/" PHP_VERSION); ++#endif + } + } + #endif +diff -Naur php-4.4.0RC2/sapi/apache2filter/sapi_apache2.c hardening-patch-4.4.0RC2-0.3.2/sapi/apache2filter/sapi_apache2.c +--- php-4.4.0RC2/sapi/apache2filter/sapi_apache2.c 2005-04-08 22:35:02.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/sapi/apache2filter/sapi_apache2.c 2005-07-09 08:53:20.665597016 +0200 +@@ -556,7 +556,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Naur php-4.4.0RC2/sapi/apache2handler/sapi_apache2.c hardening-patch-4.4.0RC2-0.3.2/sapi/apache2handler/sapi_apache2.c +--- php-4.4.0RC2/sapi/apache2handler/sapi_apache2.c 2005-04-08 22:35:02.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/sapi/apache2handler/sapi_apache2.c 2005-07-09 08:53:20.666596864 +0200 +@@ -340,7 +340,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Naur php-4.4.0RC2/sapi/cgi/cgi_main.c hardening-patch-4.4.0RC2-0.3.2/sapi/cgi/cgi_main.c +--- php-4.4.0RC2/sapi/cgi/cgi_main.c 2005-04-28 16:24:47.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/sapi/cgi/cgi_main.c 2005-07-09 08:53:20.667596712 +0200 +@@ -1440,11 +1440,19 @@ + SG(headers_sent) = 1; + SG(request_info).no_headers = 1; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit(1); + break; +diff -Naur php-4.4.0RC2/sapi/cli/php_cli.c hardening-patch-4.4.0RC2-0.3.2/sapi/cli/php_cli.c +--- php-4.4.0RC2/sapi/cli/php_cli.c 2005-03-22 16:09:36.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/sapi/cli/php_cli.c 2005-07-09 08:53:20.667596712 +0200 +@@ -652,11 +652,19 @@ + if (php_request_startup(TSRMLS_C)==FAILURE) { + goto err; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit_status=1; + goto out; +diff -Naur php-4.4.0RC2/TSRM/TSRM.h hardening-patch-4.4.0RC2-0.3.2/TSRM/TSRM.h +--- php-4.4.0RC2/TSRM/TSRM.h 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/TSRM/TSRM.h 2005-07-09 08:53:20.668596560 +0200 +@@ -33,6 +33,13 @@ + # define TSRM_API + #endif + ++#if HARDENING_PATCH ++# if HAVE_REALPATH ++# undef realpath ++# define realpath php_realpath ++# endif ++#endif ++ + /* Only compile multi-threading functions if we're in ZTS mode */ + #ifdef ZTS + +@@ -90,6 +97,7 @@ + + #define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts + ++ + #ifdef __cplusplus + extern "C" { + #endif +diff -Naur php-4.4.0RC2/TSRM/tsrm_virtual_cwd.c hardening-patch-4.4.0RC2-0.3.2/TSRM/tsrm_virtual_cwd.c +--- php-4.4.0RC2/TSRM/tsrm_virtual_cwd.c 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/TSRM/tsrm_virtual_cwd.c 2005-07-09 08:53:20.669596408 +0200 +@@ -192,6 +192,165 @@ + return p; + } + ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved) ++{ ++ struct stat sb; ++ char *p, *q, *s; ++ size_t left_len, resolved_len; ++ unsigned symlinks; ++ int serrno, slen; ++ int is_dir = 1; ++ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; ++ ++ serrno = errno; ++ symlinks = 0; ++ if (path[0] == '/') { ++ resolved[0] = '/'; ++ resolved[1] = '\0'; ++ if (path[1] == '\0') ++ return (resolved); ++ resolved_len = 1; ++ left_len = strlcpy(left, path + 1, sizeof(left)); ++ } else { ++ if (getcwd(resolved, PATH_MAX) == NULL) { ++ strlcpy(resolved, ".", PATH_MAX); ++ return (NULL); ++ } ++ resolved_len = strlen(resolved); ++ left_len = strlcpy(left, path, sizeof(left)); ++ } ++ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ ++ /* ++ * Iterate over path components in `left'. ++ */ ++ while (left_len != 0) { ++ /* ++ * Extract the next path component and adjust `left' ++ * and its length. ++ */ ++ p = strchr(left, '/'); ++ s = p ? p : left + left_len; ++ if (s - left >= sizeof(next_token)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ memcpy(next_token, left, s - left); ++ next_token[s - left] = '\0'; ++ left_len -= s - left; ++ if (p != NULL) ++ memmove(left, s + 1, left_len + 1); ++ if (resolved[resolved_len - 1] != '/') { ++ if (resolved_len + 1 >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ resolved[resolved_len++] = '/'; ++ resolved[resolved_len] = '\0'; ++ } ++ if (next_token[0] == '\0') ++ continue; ++ else if (strcmp(next_token, ".") == 0) ++ continue; ++ else if (strcmp(next_token, "..") == 0) { ++ /* ++ * Strip the last path component except when we have ++ * single "/" ++ */ ++ if (!is_dir) { ++ errno = ENOENT; ++ return (NULL); ++ } ++ if (resolved_len > 1) { ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ continue; ++ } ++ ++ /* ++ * Append the next path component and lstat() it. If ++ * lstat() fails we still can return successfully if ++ * there are no more path components left. ++ */ ++ resolved_len = strlcat(resolved, next_token, PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ if (lstat(resolved, &sb) != 0) { ++ if (errno == ENOENT && p == NULL) { ++ errno = serrno; ++ return (resolved); ++ } ++ return (NULL); ++ } ++ if (S_ISLNK(sb.st_mode)) { ++ if (symlinks++ > MAXSYMLINKS) { ++ errno = ELOOP; ++ return (NULL); ++ } ++ slen = readlink(resolved, symlink, sizeof(symlink) - 1); ++ if (slen < 0) ++ return (NULL); ++ symlink[slen] = '\0'; ++ if (symlink[0] == '/') { ++ resolved[1] = 0; ++ resolved_len = 1; ++ } else if (resolved_len > 1) { ++ /* Strip the last path component. */ ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ ++ /* ++ * If there are any path components left, then ++ * append them to symlink. The result is placed ++ * in `left'. ++ */ ++ if (p != NULL) { ++ if (symlink[slen - 1] != '/') { ++ if (slen + 1 >= sizeof(symlink)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ symlink[slen] = '/'; ++ symlink[slen + 1] = 0; ++ } ++ left_len = strlcat(symlink, left, sizeof(left)); ++ if (left_len >= sizeof(left)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ } ++ left_len = strlcpy(left, symlink, sizeof(left)); ++ } else { ++ if (S_ISDIR(sb.st_mode)) { ++ is_dir = 1; ++ } else { ++ is_dir = 0; ++ } ++ } ++ } ++ ++ /* ++ * Remove trailing slash except when the resolved pathname ++ * is a single "/". ++ */ ++ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') ++ resolved[resolved_len - 1] = '\0'; ++ return (resolved); ++} ++#endif ++ + CWD_API void virtual_cwd_startup(void) + { + char cwd[MAXPATHLEN]; +@@ -314,8 +473,7 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now +- return 1; */ ++ return 1; + } + } + } else { /* Concat current directory with relative path and then run realpath() on it */ +@@ -341,9 +499,8 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now + free(tmp); +- return 1; */ ++ return 1; + } + } + free(tmp); +diff -Naur php-4.4.0RC2/TSRM/tsrm_virtual_cwd.h hardening-patch-4.4.0RC2-0.3.2/TSRM/tsrm_virtual_cwd.h +--- php-4.4.0RC2/TSRM/tsrm_virtual_cwd.h 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/TSRM/tsrm_virtual_cwd.h 2005-07-09 08:53:20.669596408 +0200 +@@ -128,6 +128,22 @@ + + typedef int (*verify_path_func)(const cwd_state *); + ++#ifndef HAVE_STRLCPY ++CWD_API size_t php_strlcpy(char *dst, const char *src, size_t siz); ++#undef strlcpy ++#define strlcpy php_strlcpy ++#endif ++ ++#ifndef HAVE_STRLCAT ++CWD_API size_t php_strlcat(char *dst, const char *src, size_t siz); ++#undef strlcat ++#define strlcat php_strlcat ++#endif ++ ++ ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved); ++#endif + CWD_API void virtual_cwd_startup(void); + CWD_API void virtual_cwd_shutdown(void); + CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC); +diff -Naur php-4.4.0RC2/Zend/zend_alloc.c hardening-patch-4.4.0RC2-0.3.2/Zend/zend_alloc.c +--- php-4.4.0RC2/Zend/zend_alloc.c 2005-04-07 22:54:33.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_alloc.c 2005-07-09 08:53:20.670596256 +0200 +@@ -56,6 +56,11 @@ + # define END_MAGIC_SIZE 0 + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++# define CANARY_SIZE sizeof(unsigned int) ++#else ++# define CANARY_SIZE 0 ++#endif + + # if MEMORY_LIMIT + # if ZEND_DEBUG +@@ -95,9 +100,17 @@ + if (p==AG(head)) { \ + AG(head) = p->pNext; \ + } else { \ ++ if (p != p->pLast->pNext) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pLast->pNext = p->pNext; \ + } \ + if (p->pNext) { \ ++ if (p != p->pNext->pLast) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pNext->pLast = p->pLast; \ + } + +@@ -129,6 +142,12 @@ + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (size > LONG_MAX - sizeof(zend_mem_header) - MEM_HEADER_PADDING - END_MAGIC_SIZE - CANARY_SIZE) { ++ zend_security_log(S_MEMORY, "emalloc() - requested size would result in integer overflow"); ++ exit(1); ++ } ++#endif + CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size); + + if (!ZEND_DISABLE_MEMORY_CACHE && (CACHE_INDEX < MAX_CACHED_MEMORY) && (AG(cache_count)[CACHE_INDEX] > 0)) { +@@ -146,6 +165,10 @@ + AG(cache_stats)[CACHE_INDEX][1]++; + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->cached = 0; + p->size = size; + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); +@@ -161,7 +184,7 @@ + AG(allocated_memory_peak) = AG(allocated_memory); + } + #endif +- p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE + CANARY_SIZE); + } + + HANDLE_BLOCK_INTERRUPTIONS(); +@@ -191,7 +214,10 @@ + # endif + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif +- ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); + } +@@ -218,17 +244,33 @@ + return emalloc_rel(lval + offset); + } + } +- ++ ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by safe_emalloc()"); ++#endif + zend_error(E_ERROR, "Possible integer overflow in memory allocation (%ld * %ld + %ld)", nmemb, size, offset); + return 0; + } + + ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int *canary_2; ++#endif + zend_mem_header *p = (zend_mem_header *) ((char *)ptr - sizeof(zend_mem_header) - MEM_HEADER_PADDING); + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENING_PATCH_MM_PROTECT ++ canary_2 = (unsigned int *)(((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE); ++ if (p->canary != HG(canary_1) || *canary_2 != HG(canary_2)) { ++ zend_security_log(S_MEMORY, "canary mismatch on efree() - heap overflow or double efree detected"); ++ exit(1); ++ } ++ /* to catch double efree()s */ ++ *canary_2 = p->canary = 0; ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + tsrm_error(TSRM_ERROR_LEVEL_ERROR, "Memory block allocated at %s:(%d) on thread %x freed at %s:(%d) on thread %x, ignoring", +@@ -273,6 +315,9 @@ + size_t _size = nmemb * size; + + if (nmemb && (_size/nmemb!=size)) { ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by ecalloc()"); ++#endif + fprintf(stderr,"FATAL: ecalloc(): Unable to allocate %ld * %ld bytes\n", (long) nmemb, (long) size); + #if ZEND_DEBUG && HAVE_KILL && HAVE_GETPID + kill(getpid(), SIGSEGV); +@@ -292,6 +337,9 @@ + + ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p; + zend_mem_header *orig; + DECLARE_CACHE_VARS(); +@@ -303,6 +351,14 @@ + + p = orig = (zend_mem_header *) ((char *)ptr-sizeof(zend_mem_header)-MEM_HEADER_PADDING); + ++#if HARDENING_PATCH_MM_PROTECT ++ canary_2 = *(unsigned int *)(((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE); ++ if (p->canary != HG(canary_1) || canary_2 != HG(canary_2)) { ++ zend_security_log(S_MEMORY, "canary mismatch on erealloc() - heap overflow detected"); ++ exit(1); ++ } ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + void *new_p; +@@ -326,7 +382,7 @@ + } + #endif + REMOVE_POINTER_FROM_LIST(p); +- p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE+CANARY_SIZE); + if (!p) { + if (!allow_failure) { + fprintf(stderr,"FATAL: erealloc(): Unable to allocate %ld bytes\n", (long) size); +@@ -348,6 +404,9 @@ + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->size = size; + + HANDLE_UNBLOCK_INTERRUPTIONS(); +@@ -422,6 +481,10 @@ + { + AG(head) = NULL; + ++#if HARDENING_PATCH_MM_PROTECT ++ HG(canary_1) = zend_canary(); ++ HG(canary_2) = zend_canary(); ++#endif + #if MEMORY_LIMIT + AG(memory_limit) = 1<<30; /* ridiculous limit, effectively no limit */ + AG(allocated_memory) = 0; +diff -Naur php-4.4.0RC2/Zend/zend_alloc.h hardening-patch-4.4.0RC2-0.3.2/Zend/zend_alloc.h +--- php-4.4.0RC2/Zend/zend_alloc.h 2005-06-07 15:37:33.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_alloc.h 2005-07-09 08:53:20.671596104 +0200 +@@ -32,6 +32,9 @@ + #define MEM_BLOCK_CACHED_MAGIC 0xFB8277DCL + + typedef struct _zend_mem_header { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary; ++#endif + #if ZEND_DEBUG + long magic; + char *filename; +diff -Naur php-4.4.0RC2/Zend/zend_builtin_functions.c hardening-patch-4.4.0RC2-0.3.2/Zend/zend_builtin_functions.c +--- php-4.4.0RC2/Zend/zend_builtin_functions.c 2005-06-23 14:20:47.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_builtin_functions.c 2005-07-09 08:53:20.671596104 +0200 +@@ -49,6 +49,9 @@ + static ZEND_FUNCTION(crash); + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++static ZEND_FUNCTION(heap_overflow); ++#endif + static ZEND_FUNCTION(get_included_files); + static ZEND_FUNCTION(is_subclass_of); + static ZEND_FUNCTION(is_a); +@@ -101,6 +104,9 @@ + ZEND_FE(crash, NULL) + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ ZEND_FE(heap_overflow, NULL) ++#endif + ZEND_FE(get_included_files, NULL) + ZEND_FALIAS(get_required_files, get_included_files, NULL) + ZEND_FE(is_subclass_of, NULL) +@@ -805,6 +811,19 @@ + + #endif /* ZEND_DEBUG */ + ++ ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ZEND_FUNCTION(heap_overflow) ++{ ++ char *nowhere = emalloc(10); ++ ++ memcpy(nowhere, "something1234567890", sizeof("something1234567890")); ++ ++ efree(nowhere); ++} ++#endif ++ ++ + /* {{{ proto array get_included_files(void) + Returns an array with the file names that were include_once()'d */ + ZEND_FUNCTION(get_included_files) +diff -Naur php-4.4.0RC2/Zend/zend.c hardening-patch-4.4.0RC2-0.3.2/Zend/zend.c +--- php-4.4.0RC2/Zend/zend.c 2005-06-09 12:14:25.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend.c 2005-07-09 08:53:20.672595952 +0200 +@@ -53,6 +53,12 @@ + ZEND_API void (*zend_unblock_interruptions)(void); + ZEND_API void (*zend_ticks_function)(int ticks); + ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); ++#if HARDENING_PATCH ++ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + + void (*zend_on_timeout)(int seconds TSRMLS_DC); + +@@ -70,9 +76,80 @@ + return SUCCESS; + } + ++#if HARDENING_PATCH ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog) = S_ALL & ~S_SQL | S_MEMORY; ++ } else { ++ EG(hphp_log_syslog) = atoi(new_value) | S_MEMORY; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_facility) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_facility) = LOG_USER; ++ } else { ++ EG(hphp_log_syslog_facility) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_priority) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_priority) = LOG_ALERT; ++ } else { ++ EG(hphp_log_syslog_priority) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_sapi) ++{ ++ if (!new_value) { ++ EG(hphp_log_sapi) = S_ALL & ~S_SQL; ++ } else { ++ EG(hphp_log_sapi) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_script) ++{ ++ if (!new_value) { ++ EG(hphp_log_script) = S_ALL & ~S_MEMORY; ++ } else { ++ EG(hphp_log_script) = atoi(new_value) & ~S_MEMORY; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_scriptname) ++{ ++ if (!new_value) { ++ EG(hphp_log_scriptname) = NULL; ++ } else { ++ if (EG(hphp_log_scriptname)) { ++ pefree(EG(hphp_log_scriptname),1); ++ } ++ EG(hphp_log_scriptname) = pestrdup(new_value,1); ++ } ++ return SUCCESS; ++} ++#endif + + ZEND_INI_BEGIN() + ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) ++#if HARDENING_PATCH ++ ZEND_INI_ENTRY("hphp.log.syslog", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog) ++ ZEND_INI_ENTRY("hphp.log.syslog.facility", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_facility) ++ ZEND_INI_ENTRY("hphp.log.syslog.priority", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_priority) ++ ZEND_INI_ENTRY("hphp.log.sapi", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_sapi) ++ ZEND_INI_ENTRY("hphp.log.script", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_script) ++ ZEND_INI_ENTRY("hphp.log.script.name", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_scriptname) ++ STD_ZEND_INI_BOOLEAN("hphp.log.use-x-forwarded-for", "0", ZEND_INI_SYSTEM, OnUpdateBool, hphp_log_use_x_forwarded_for, zend_executor_globals, executor_globals) ++ STD_ZEND_INI_ENTRY("hphp.executor.max_depth", "0", ZEND_INI_PERDIR, OnUpdateLong, hphp_executor_max_depth, zend_executor_globals, executor_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.sql.bailout_on_error", "0", ZEND_INI_PERDIR, OnUpdateBool, hphp_sql_bailout_on_error, hardened_globals_struct, hardened_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.multiheader", "0", ZEND_INI_PERDIR, OnUpdateBool, hphp_multiheader, hardened_globals_struct, hardened_globals) ++#endif + ZEND_INI_END() + + +@@ -354,6 +431,7 @@ + zend_init_rsrc_plist(TSRMLS_C); + EG(lambda_count)=0; + EG(user_error_handler) = NULL; ++ EG(in_code_type) = 0; + EG(in_execution) = 0; + EG(current_execute_data) = NULL; + } +@@ -420,6 +498,14 @@ + extern zend_scanner_globals language_scanner_globals; + #endif + ++ /* Set up Hardening-Patch utility functions first */ ++#if HARDENING_PATCH ++ zend_security_log = utility_functions->security_log_function; ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ zend_is_valid_include = utility_functions->is_valid_include; ++#endif ++ + #ifdef ZTS + ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); + #else +@@ -623,6 +709,7 @@ + } + CG(unclean_shutdown) = 1; + CG(in_compilation) = EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(current_execute_data) = NULL; + longjmp(EG(bailout), FAILURE); + } +diff -Naur php-4.4.0RC2/Zend/zend_canary.c hardening-patch-4.4.0RC2-0.3.2/Zend/zend_canary.c +--- php-4.4.0RC2/Zend/zend_canary.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_canary.c 2005-07-09 08:53:20.673595800 +0200 +@@ -0,0 +1,58 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: zend_canary.c,v 1.1 2004/11/26 12:45:41 ionic Exp $ */ ++ ++#include "zend.h" ++ ++#include ++#include ++ ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++ZEND_API unsigned int zend_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Naur php-4.4.0RC2/Zend/zend_compile.h hardening-patch-4.4.0RC2-0.3.2/Zend/zend_compile.h +--- php-4.4.0RC2/Zend/zend_compile.h 2005-06-06 11:30:09.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_compile.h 2005-07-09 08:53:20.673595800 +0200 +@@ -549,6 +549,7 @@ + #define ZEND_USER_FUNCTION 2 + #define ZEND_OVERLOADED_FUNCTION 3 + #define ZEND_EVAL_CODE 4 ++#define ZEND_SANDBOX_CODE 6 + + #define ZEND_INTERNAL_CLASS 1 + #define ZEND_USER_CLASS 2 +diff -Naur php-4.4.0RC2/Zend/zend_constants.c hardening-patch-4.4.0RC2-0.3.2/Zend/zend_constants.c +--- php-4.4.0RC2/Zend/zend_constants.c 2004-07-13 21:29:45.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_constants.c 2005-07-09 08:53:20.674595648 +0200 +@@ -111,6 +111,72 @@ + REGISTER_MAIN_LONG_CONSTANT("E_USER_NOTICE", E_USER_NOTICE, CONST_PERSISTENT | CONST_CS); + + REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("S_MEMORY", S_MEMORY, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_VARS", S_VARS, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_FILES", S_VARS, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INCLUDE", S_INCLUDE, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_SQL", S_SQL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_EXECUTOR", S_EXECUTOR, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_MISC", S_MISC, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_ALL", S_ALL, CONST_PERSISTENT | CONST_CS); ++ ++ /* error levels */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRIT", LOG_CRIT, CONST_CS | CONST_PERSISTENT); /* critical conditions */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ERR", LOG_ERR, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_WARNING", LOG_WARNING, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOTICE", LOG_NOTICE, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_INFO", LOG_INFO, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DEBUG", LOG_DEBUG, CONST_CS | CONST_PERSISTENT); ++ /* facility: type of program logging the message */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_KERN", LOG_KERN, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_USER", LOG_USER, CONST_CS | CONST_PERSISTENT); /* generic user level */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_MAIL", LOG_MAIL, CONST_CS | CONST_PERSISTENT); /* log to email */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DAEMON", LOG_DAEMON, CONST_CS | CONST_PERSISTENT); /* other system daemons */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTH", LOG_AUTH, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_SYSLOG", LOG_SYSLOG, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LPR", LOG_LPR, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NEWS ++ /* No LOG_NEWS on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NEWS", LOG_NEWS, CONST_CS | CONST_PERSISTENT); /* usenet new */ ++#endif ++#ifdef LOG_UUCP ++ /* No LOG_UUCP on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_UUCP", LOG_UUCP, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_CRON ++ /* apparently some systems don't have this one */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRON", LOG_CRON, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_AUTHPRIV ++ /* AIX doesn't have LOG_AUTHPRIV */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTHPRIV", LOG_AUTHPRIV, CONST_CS | CONST_PERSISTENT); ++#endif ++#if !defined(PHP_WIN32) && !defined(NETWARE) ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL0", LOG_LOCAL0, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL1", LOG_LOCAL1, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL2", LOG_LOCAL2, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL3", LOG_LOCAL3, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL4", LOG_LOCAL4, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL5", LOG_LOCAL5, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL6", LOG_LOCAL6, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL7", LOG_LOCAL7, CONST_CS | CONST_PERSISTENT); ++#endif ++ /* options */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PID", LOG_PID, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CONS", LOG_CONS, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ODELAY", LOG_ODELAY, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NDELAY", LOG_NDELAY, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NOWAIT ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOWAIT", LOG_NOWAIT, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_PERROR ++ /* AIX doesn't have LOG_PERROR */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ ++#endif ++#endif + + /* true/false constants */ + { +diff -Naur php-4.4.0RC2/Zend/zend_errors.h hardening-patch-4.4.0RC2-0.3.2/Zend/zend_errors.h +--- php-4.4.0RC2/Zend/zend_errors.h 2002-12-31 17:22:59.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_errors.h 2005-07-09 08:53:20.674595648 +0200 +@@ -36,5 +36,16 @@ + #define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE) + #define E_CORE (E_CORE_ERROR | E_CORE_WARNING) + ++#if HARDENING_PATCH ++#define S_MEMORY (1<<0L) ++#define S_VARS (1<<1L) ++#define S_FILES (1<<2L) ++#define S_INCLUDE (1<<3L) ++#define S_SQL (1<<4L) ++#define S_EXECUTOR (1<<5L) ++#define S_MISC (1<<30L) ++#define S_ALL (S_MEMORY | S_VARS | S_INCLUDE | S_FILES | S_MISC | S_SQL | S_EXECUTOR) ++#endif ++ + #endif /* ZEND_ERRORS_H */ + +diff -Naur php-4.4.0RC2/Zend/zend_execute_API.c hardening-patch-4.4.0RC2-0.3.2/Zend/zend_execute_API.c +--- php-4.4.0RC2/Zend/zend_execute_API.c 2005-05-18 19:58:09.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_execute_API.c 2005-07-09 08:53:20.675595496 +0200 +@@ -142,6 +142,7 @@ + EG(class_table) = CG(class_table); + + EG(in_execution) = 0; ++ EG(in_code_type) = 0; + + zend_ptr_stack_init(&EG(argument_stack)); + +@@ -431,12 +432,14 @@ + zend_execute_data execute_data; + + /* Initialize execute_data */ ++ memset(&execute_data, 0, sizeof(execute_data)); + EX(fbc) = NULL; + EX(object).ptr = NULL; + EX(ce) = NULL; + EX(Ts) = NULL; + EX(op_array) = NULL; + EX(opline) = NULL; ++ EX(execute_depth) = 0; + + *retval_ptr_ptr = NULL; + +@@ -606,8 +609,7 @@ + return SUCCESS; + } + +- +-ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) ++ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int type TSRMLS_DC) + { + zval pv; + zend_op_array *new_op_array; +@@ -640,6 +642,7 @@ + zval **original_return_value_ptr_ptr = EG(return_value_ptr_ptr); + zend_op **original_opline_ptr = EG(opline_ptr); + ++ new_op_array->type = type; + EG(return_value_ptr_ptr) = &local_retval_ptr; + EG(active_op_array) = new_op_array; + EG(no_extensions)=1; +@@ -673,6 +676,10 @@ + return retval; + } + ++ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) ++{ ++ return (zend_eval_string_ex(str, retval_ptr, string_name, ZEND_EVAL_CODE TSRMLS_CC)); ++} + + void execute_new_code(TSRMLS_D) + { +diff -Naur php-4.4.0RC2/Zend/zend_execute.c hardening-patch-4.4.0RC2-0.3.2/Zend/zend_execute.c +--- php-4.4.0RC2/Zend/zend_execute.c 2005-06-27 08:15:48.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_execute.c 2005-07-09 08:53:20.676595344 +0200 +@@ -1042,6 +1042,7 @@ + zend_execute_data execute_data; + + /* Initialize execute_data */ ++ memset(&execute_data, 0, sizeof(execute_data)); + EX(fbc) = NULL; + EX(ce) = NULL; + EX(object).ptr = NULL; +@@ -1053,9 +1054,21 @@ + } + EX(prev_execute_data) = EG(current_execute_data); + EX(original_in_execution)=EG(in_execution); ++ EX(original_in_code_type)=EG(in_code_type); + + EG(current_execute_data) = &execute_data; + ++#if HARDENING_PATCH ++ EX(execute_depth) = 0; ++ ++ if (op_array->type == ZEND_EVAL_CODE && EG(in_code_type) != ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } else if (op_array->type == ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_SANDBOX_CODE; ++ op_array->type = ZEND_EVAL_CODE; ++ } ++#endif ++ + EG(in_execution) = 1; + if (op_array->start_op) { + EX(opline) = op_array->start_op; +@@ -1087,6 +1100,19 @@ + } + } + ++#if HARDENING_PATCH ++ if (EX(prev_execute_data) == NULL) { ++ EX(execute_depth) = 0; ++ } else { ++ EX(execute_depth) = EX(prev_execute_data)->execute_depth + 1; ++ } ++ ++ if (EG(hphp_executor_max_depth) > 0 && EX(execute_depth) > EG(hphp_executor_max_depth)) { ++ zend_security_log(S_EXECUTOR, "Maximum execution depth of %u violated", EG(hphp_executor_max_depth)); ++ zend_bailout(); ++ } ++#endif ++ + while (1) { + #ifdef ZEND_WIN32 + if (EG(timed_out)) { +@@ -1816,6 +1842,7 @@ + efree(EX(Ts)); + } + EG(in_execution) = EX(original_in_execution); ++ EG(in_code_type) = EX(original_in_code_type); + EG(current_execute_data) = EX(prev_execute_data); + return; + } +@@ -2195,7 +2222,12 @@ + int dummy = 1; + zend_file_handle file_handle = {0}; + ++#if HARDENING_PATCH_INC_PROTECT ++ if (zend_is_valid_include(inc_filename) ++ && zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#else + if (zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#endif + && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) { + + file_handle.filename = inc_filename->value.str.val; +@@ -2224,6 +2256,11 @@ + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: ++#if HARDENING_PATCH_INC_PROTECT ++ if (!zend_is_valid_include(inc_filename)) { ++ break; ++ } ++#endif + new_op_array = compile_filename(EX(opline)->op2.u.constant.value.lval, inc_filename TSRMLS_CC); + break; + case ZEND_EVAL: { +diff -Naur php-4.4.0RC2/Zend/zend_execute_globals.h hardening-patch-4.4.0RC2-0.3.2/Zend/zend_execute_globals.h +--- php-4.4.0RC2/Zend/zend_execute_globals.h 2005-06-06 11:30:09.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_execute_globals.h 2005-07-09 08:53:20.677595192 +0200 +@@ -60,6 +60,8 @@ + object_info object; + temp_variable *Ts; + zend_bool original_in_execution; ++ zend_uint original_in_code_type; ++ zend_uint execute_depth; + zend_op_array *op_array; + struct _zend_execute_data *prev_execute_data; + } zend_execute_data; +diff -Naur php-4.4.0RC2/Zend/zend_extensions.h hardening-patch-4.4.0RC2-0.3.2/Zend/zend_extensions.h +--- php-4.4.0RC2/Zend/zend_extensions.h 2005-06-06 11:44:59.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_extensions.h 2005-07-09 08:53:20.677595192 +0200 +@@ -23,7 +23,9 @@ + + #include "zend_compile.h" + +-#define ZEND_EXTENSION_API_NO 20050606 ++/* Create own API version number for Hardening-Patch */ ++ ++#define ZEND_EXTENSION_API_NO 1020050705 + + typedef struct _zend_extension_version_info { + int zend_extension_api_no; +diff -Naur php-4.4.0RC2/Zend/zend_globals.h hardening-patch-4.4.0RC2-0.3.2/Zend/zend_globals.h +--- php-4.4.0RC2/Zend/zend_globals.h 2004-11-04 00:15:05.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_globals.h 2005-07-09 08:53:20.678595040 +0200 +@@ -163,6 +163,16 @@ + + int error_reporting; + int orig_error_reporting; ++#if HARDENING_PATCH ++ int hphp_log_syslog; ++ int hphp_log_syslog_facility; ++ int hphp_log_syslog_priority; ++ int hphp_log_sapi; ++ int hphp_log_script; ++ char *hphp_log_scriptname; ++ zend_bool hphp_log_use_x_forwarded_for; ++ long hphp_executor_max_depth; ++#endif + int exit_status; + + zend_op_array *active_op_array; +@@ -176,6 +186,7 @@ + int ticks_count; + + zend_bool in_execution; ++ zend_uint in_code_type; + zend_bool bailout_set; + zend_bool full_tables_cleanup; + +diff -Naur php-4.4.0RC2/Zend/zend.h hardening-patch-4.4.0RC2-0.3.2/Zend/zend.h +--- php-4.4.0RC2/Zend/zend.h 2005-01-25 14:08:41.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend.h 2005-07-09 08:53:20.678595040 +0200 +@@ -275,9 +275,10 @@ + struct _zval_struct { + /* Variable information */ + zvalue_value value; /* value */ ++ zend_uint refcount; ++ zend_ushort flags; + zend_uchar type; /* active type */ + zend_uchar is_ref; +- zend_ushort refcount; + }; + + +@@ -338,6 +339,12 @@ + void (*ticks_function)(int ticks); + void (*on_timeout)(int seconds TSRMLS_DC); + zend_bool (*open_function)(const char *filename, struct _zend_file_handle *); ++#if HARDENING_PATCH ++ void (*security_log_function)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ int (*is_valid_include)(zval *z); ++#endif + } zend_utility_functions; + + +@@ -469,7 +476,16 @@ + extern ZEND_API void (*zend_ticks_function)(int ticks); + extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); + extern void (*zend_on_timeout)(int seconds TSRMLS_DC); ++#if HARDENING_PATCH ++extern ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++extern ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ZEND_API unsigned int zend_canary(void); ++#endif + + ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 2, 3); + +@@ -576,6 +592,11 @@ + + #define ZEND_MAX_RESERVED_RESOURCES 4 + ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#include "php_syslog.h" ++#endif ++ + #endif /* ZEND_H */ + + /* +diff -Naur php-4.4.0RC2/Zend/zend_hash.c hardening-patch-4.4.0RC2-0.3.2/Zend/zend_hash.c +--- php-4.4.0RC2/Zend/zend_hash.c 2005-04-28 09:34:32.000000000 +0200 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_hash.c 2005-07-09 08:53:20.679594888 +0200 +@@ -26,6 +26,17 @@ + # include + #endif + ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int zend_hash_canary = 0x1234567; ++ zend_bool zend_hash_canary_inited = 0; ++#endif ++ ++#define CHECK_HASH_CANARY(hash) \ ++ if (zend_hash_canary != (hash)->canary) { \ ++ zend_security_log(S_MEMORY, "Zend HashTable canary was overwritten"); \ ++ exit(1); \ ++ } ++ + #define HANDLE_NUMERIC(key, length, func) { \ + register char *tmp=key; \ + \ +@@ -175,6 +186,9 @@ + { + uint i = 3; + Bucket **tmp; ++#if HARDENING_PATCH_HASH_PROTECT ++ TSRMLS_FETCH(); ++#endif + + SET_INCONSISTENT(HT_OK); + +@@ -184,6 +198,13 @@ + + ht->nTableSize = 1 << i; + ht->nTableMask = ht->nTableSize - 1; ++#if HARDENING_PATCH_HASH_PROTECT ++ if (zend_hash_canary_inited==0) { ++ zend_hash_canary = zend_canary(); ++ zend_hash_canary_inited = 1; ++ } ++ ht->canary = zend_hash_canary; ++#endif + ht->pDestructor = pDestructor; + ht->pListHead = NULL; + ht->pListTail = NULL; +@@ -259,6 +280,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -327,6 +351,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -402,6 +429,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -450,7 +480,7 @@ + IS_CONSISTENT(ht); + + if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */ +- t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); ++ t = (Bucket **) perealloc(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); + if (t) { + HANDLE_BLOCK_INTERRUPTIONS(); + ht->arBuckets = t; +@@ -460,6 +490,7 @@ + HANDLE_UNBLOCK_INTERRUPTIONS(); + return SUCCESS; + } ++ zend_error(E_ERROR, "zend_hash_do_resize - out of memory"); + return FAILURE; + } + return SUCCESS; +@@ -524,6 +555,9 @@ + ht->pInternalPointer = p->pListNext; + } + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +@@ -553,6 +587,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -579,6 +616,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -608,6 +648,9 @@ + HANDLE_BLOCK_INTERRUPTIONS(); + + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +diff -Naur php-4.4.0RC2/Zend/zend_hash.h hardening-patch-4.4.0RC2-0.3.2/Zend/zend_hash.h +--- php-4.4.0RC2/Zend/zend_hash.h 2002-12-31 17:23:03.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_hash.h 2005-07-09 08:53:20.680594736 +0200 +@@ -54,6 +54,9 @@ + } Bucket; + + typedef struct _hashtable { ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int canary; ++#endif + uint nTableSize; + uint nTableMask; + uint nNumOfElements; +diff -Naur php-4.4.0RC2/Zend/zend_ini.h hardening-patch-4.4.0RC2-0.3.2/Zend/zend_ini.h +--- php-4.4.0RC2/Zend/zend_ini.h 2005-01-09 18:00:16.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_ini.h 2005-07-09 08:53:20.680594736 +0200 +@@ -174,6 +174,7 @@ + /* Standard message handlers */ + BEGIN_EXTERN_C() + ZEND_API ZEND_INI_MH(OnUpdateBool); ++#define OnUpdateLong OnUpdateInt + ZEND_API ZEND_INI_MH(OnUpdateInt); + ZEND_API ZEND_INI_MH(OnUpdateReal); + ZEND_API ZEND_INI_MH(OnUpdateString); +diff -Naur php-4.4.0RC2/Zend/zend_llist.c hardening-patch-4.4.0RC2-0.3.2/Zend/zend_llist.c +--- php-4.4.0RC2/Zend/zend_llist.c 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_llist.c 2005-07-09 08:53:20.681594584 +0200 +@@ -21,9 +21,34 @@ + #include "zend.h" + #include "zend_llist.h" + #include "zend_qsort.h" ++#include "zend_globals.h" ++ ++#define CHECK_LIST_CANARY(list) \ ++ if (HG(canary_3) != (list)->canary_h || HG(canary_4) != (list)->canary_t) { \ ++ zend_security_log(S_MEMORY, "linked list canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++#define CHECK_LISTELEMENT_CANARY(elem) \ ++ if (HG(canary_3) != (elem)->canary) { \ ++ zend_security_log(S_MEMORY, "linked list element canary was overwritten"); \ ++ exit(1); \ ++ } ++ + + ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ ++ if (!HG(ll_canary_inited)) { ++ HG(canary_3) = zend_canary(); ++ HG(canary_4) = zend_canary(); ++ HG(ll_canary_inited) = 1; ++ } ++ l->canary_h = HG(canary_3); ++ l->canary_t = HG(canary_4); ++#endif + l->head = NULL; + l->tail = NULL; + l->count = 0; +@@ -37,6 +62,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->prev = l->tail; + tmp->next = NULL; + if (l->tail) { +@@ -55,6 +85,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->next = l->head; + tmp->prev = NULL; + if (l->head) { +@@ -91,10 +126,20 @@ + zend_llist_element *current=l->head; + zend_llist_element *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (compare(current->data, element)) { + DEL_LLIST_ELEMENT(current, l); ++#if HARDENING_PATCH_LL_PROTECT ++ current->canary = 0; ++#endif + break; + } + current = next; +@@ -106,7 +151,14 @@ + { + zend_llist_element *current=l->head, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (l->dtor) { + l->dtor(current->data); +@@ -131,7 +183,14 @@ + zend_llist_element *old_tail; + void *data; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if ((old_tail = l->tail)) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(old_tail) ++#endif + if (l->tail->prev) { + l->tail->prev->next = NULL; + } +@@ -157,9 +216,16 @@ + { + zend_llist_element *ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(src) ++#endif + zend_llist_init(dst, src->size, src->dtor, src->persistent); + ptr = src->head; + while (ptr) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(ptr) ++#endif + zend_llist_add_element(dst, ptr->data); + ptr = ptr->next; + } +@@ -170,11 +236,21 @@ + { + zend_llist_element *element, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + element=l->head; + while (element) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + next = element->next; + if (func(element->data)) { + DEL_LLIST_ELEMENT(element, l); ++#if HARDENING_PATCH_LL_PROTECT ++ element->canary = 0; ++#endif + } + element = next; + } +@@ -185,7 +261,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data TSRMLS_CC); + } + } +@@ -197,6 +279,9 @@ + zend_llist_element **elements; + zend_llist_element *element, **ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + if (l->count <= 0) { + return; + } +@@ -206,6 +291,9 @@ + ptr = &elements[0]; + + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + *ptr++ = element; + } + +@@ -228,7 +316,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, arg TSRMLS_CC); + } + } +@@ -239,8 +333,14 @@ + zend_llist_element *element; + va_list args; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + va_start(args, num_args); + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, num_args, args TSRMLS_CC); + } + va_end(args); +@@ -249,6 +349,10 @@ + + ZEND_API int zend_llist_count(zend_llist *l) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + return l->count; + } + +@@ -256,8 +360,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->head; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -269,8 +380,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->tail; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -282,9 +400,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->next; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +@@ -296,9 +424,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->prev; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +diff -Naur php-4.4.0RC2/Zend/zend_llist.h hardening-patch-4.4.0RC2-0.3.2/Zend/zend_llist.h +--- php-4.4.0RC2/Zend/zend_llist.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_llist.h 2005-07-09 08:53:20.681594584 +0200 +@@ -24,6 +24,9 @@ + #include + + typedef struct _zend_llist_element { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary; ++#endif + struct _zend_llist_element *next; + struct _zend_llist_element *prev; + char data[1]; /* Needs to always be last in the struct */ +@@ -36,6 +39,9 @@ + typedef void (*llist_apply_func_t)(void * TSRMLS_DC); + + typedef struct _zend_llist { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_h; /* head */ ++#endif + zend_llist_element *head; + zend_llist_element *tail; + size_t size; +@@ -43,6 +49,9 @@ + llist_dtor_func_t dtor; + unsigned char persistent; + zend_llist_element *traverse_ptr; ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_t; /* tail */ ++#endif + } zend_llist; + + typedef zend_llist_element* zend_llist_position; +diff -Naur php-4.4.0RC2/Zend/zend_modules.h hardening-patch-4.4.0RC2-0.3.2/Zend/zend_modules.h +--- php-4.4.0RC2/Zend/zend_modules.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.4.0RC2-0.3.2/Zend/zend_modules.h 2005-07-09 08:53:20.682594432 +0200 +@@ -34,7 +34,7 @@ + ZEND_API extern unsigned char second_arg_force_ref[]; + ZEND_API extern unsigned char third_arg_force_ref[]; + +-#define ZEND_MODULE_API_NO 20020429 ++#define ZEND_MODULE_API_NO 1020050626 + #ifdef ZTS + #define USING_ZTS 1 + #else diff --git a/0.3.2/hardening-patch-5.0.4-0.3.2.patch b/0.3.2/hardening-patch-5.0.4-0.3.2.patch new file mode 100644 index 0000000..9880282 --- /dev/null +++ b/0.3.2/hardening-patch-5.0.4-0.3.2.patch @@ -0,0 +1,11892 @@ +diff -Naur php-5.0.4/acinclude.m4 hardening-patch-5.0.4-0.3.2/acinclude.m4 +--- php-5.0.4/acinclude.m4 2005-01-25 14:02:45.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/acinclude.m4 2005-06-26 20:59:20.000000000 +0200 +@@ -1169,6 +1169,36 @@ + fi + ]) + ++dnl ++dnl Check for broken realpath() ++dnl ++dnl realpath("/etc/hosts/../passwd",XXX) should not return ++dnl "/etc/passwd" ++dnl ++AC_DEFUN([PHP_AC_BROKEN_REALPATH],[ ++ AC_CACHE_CHECK(whether realpath is broken, ac_cv_broken_realpath,[ ++ AC_TRY_RUN([ ++main() { ++ char buf[4096+1]; ++ buf[0] = 0; ++ realpath("/etc/hosts/../passwd", buf); ++ exit(strcmp(buf, "/etc/passwd")==0); ++} ++ ],[ ++ ac_cv_broken_realpath=no ++ ],[ ++ ac_cv_broken_realpath=yes ++ ],[ ++ ac_cv_broken_realpath=no ++ ]) ++ ]) ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ AC_DEFINE(PHP_BROKEN_REALPATH, 1, [Whether realpath is broken]) ++ else ++ AC_DEFINE(PHP_BROKEN_REALPATH, 0, [Whether realpath is broken]) ++ fi ++]) ++ + dnl PHP_SHARED_MODULE(module-name, object-var, build-dir, cxx) + dnl + dnl Basically sets up the link-stage for building module-name +diff -Naur php-5.0.4/configure hardening-patch-5.0.4-0.3.2/configure +--- php-5.0.4/configure 2005-04-03 11:42:50.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/configure 2005-06-28 15:47:07.000000000 +0200 +@@ -401,6 +401,16 @@ + ac_default_prefix=/usr/local + # Any additions from configure.in: + ac_help="$ac_help ++ --disable-hardening-patch-mm-protect Disable the Memory Manager protection." ++ac_help="$ac_help ++ --disable-hardening-patch-ll-protect Disable the Linked List protection." ++ac_help="$ac_help ++ --disable-hardening-patch-inc-protect Disable include/require protection." ++ac_help="$ac_help ++ --disable-hardening-patch-fmt-protect Disable format string protection." ++ac_help="$ac_help ++ --disable-hardening-patch-hash-protect Disable Zend HashTable DTOR protection." ++ac_help="$ac_help + + SAPI modules: + " +@@ -857,6 +867,8 @@ + ac_help="$ac_help + --disable-tokenizer Disable tokenizer support" + ac_help="$ac_help ++ --disable-varfilter Disable Hardening-Patch's variable filter" ++ac_help="$ac_help + --enable-wddx Enable WDDX support." + ac_help="$ac_help + --disable-xml Disable XML support." +@@ -2749,6 +2761,157 @@ + + + ++# Check whether --enable-hardening-patch-mm-protect or --disable-hardening-patch-mm-protect was given. ++if test "${enable_hardening_patch_mm_protect+set}" = set; then ++ enableval="$enable_hardening_patch_mm_protect" ++ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-ll-protect or --disable-hardening-patch-ll-protect was given. ++if test "${enable_hardening_patch_ll_protect+set}" = set; then ++ enableval="$enable_hardening_patch_ll_protect" ++ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-inc-protect or --disable-hardening-patch-inc-protect was given. ++if test "${enable_hardening_patch_inc_protect+set}" = set; then ++ enableval="$enable_hardening_patch_inc_protect" ++ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-fmt-protect or --disable-hardening-patch-fmt-protect was given. ++if test "${enable_hardening_patch_fmt_protect+set}" = set; then ++ enableval="$enable_hardening_patch_fmt_protect" ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-hash-protect or --disable-hardening-patch-hash-protect was given. ++if test "${enable_hardening_patch_hash_protect+set}" = set; then ++ enableval="$enable_hardening_patch_hash_protect" ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++ ++fi ++ ++ ++echo $ac_n "checking whether to protect the Zend Memory Manager""... $ac_c" 1>&6 ++echo "configure:2725: checking whether to protect the Zend Memory Manager" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_MM_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend Linked Lists""... $ac_c" 1>&6 ++echo "configure:2729: checking whether to protect the Zend Linked Lists" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_LL_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect include/require statements""... $ac_c" 1>&6 ++echo "configure:2733: checking whether to protect include/require statements" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_INC_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect PHP Format String functions""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect PHP Format String functions" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_FMT_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend HashTable Destructors""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect the Zend HashTable Destructors" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_HASH_PROTECT" 1>&6 ++ ++ ++cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH 1 ++EOF ++ ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 0 ++EOF ++ ++fi + + + +@@ -17390,6 +17553,62 @@ + fi + + ++ echo $ac_n "checking whether realpath is broken""... $ac_c" 1>&6 ++echo "configure:14928: checking whether realpath is broken" >&5 ++if eval "test \"`echo '$''{'ac_cv_broken_realpath'+set}'`\" = set"; then ++ echo $ac_n "(cached) $ac_c" 1>&6 ++else ++ ++ if test "$cross_compiling" = yes; then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null ++then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ echo "configure: failed program was:" >&5 ++ cat conftest.$ac_ext >&5 ++ rm -fr conftest* ++ ++ ac_cv_broken_realpath=yes ++ ++fi ++rm -fr conftest* ++fi ++ ++ ++fi ++ ++echo "$ac_t""$ac_cv_broken_realpath" 1>&6 ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 1 ++EOF ++ ++ else ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 0 ++EOF ++ ++ fi ++ ++ + echo $ac_n "checking for declared timezone""... $ac_c" 1>&6 + echo "configure:17395: checking for declared timezone" >&5 + if eval "test \"`echo '$''{'ac_cv_declared_timezone'+set}'`\" = set"; then +@@ -86878,6 +87097,265 @@ + fi + + ++echo $ac_n "checking whether to enable Hardening-Patch's variable filter""... $ac_c" 1>&6 ++echo "configure:82041: checking whether to enable Hardening-Patch's variable filter" >&5 ++# Check whether --enable-varfilter or --disable-varfilter was given. ++if test "${enable_varfilter+set}" = set; then ++ enableval="$enable_varfilter" ++ PHP_VARFILTER=$enableval ++else ++ ++ PHP_VARFILTER=yes ++ ++ if test "$PHP_ENABLE_ALL" && test "yes" = "yes"; then ++ PHP_VARFILTER=$PHP_ENABLE_ALL ++ fi ++ ++fi ++ ++ ++ ++ext_output="yes, shared" ++ext_shared=yes ++case $PHP_VARFILTER in ++shared,*) ++ PHP_VARFILTER=`echo "$PHP_VARFILTER"|sed 's/^shared,//'` ++ ;; ++shared) ++ PHP_VARFILTER=yes ++ ;; ++no) ++ ext_output=no ++ ext_shared=no ++ ;; ++*) ++ ext_output=yes ++ ext_shared=no ++ ;; ++esac ++ ++ ++ ++echo "$ac_t""$ext_output" 1>&6 ++ ++ ++ ++ ++if test "$PHP_VARFILTER" != "no"; then ++ cat >> confdefs.h <<\EOF ++#define HAVE_VARFILTER 1 ++EOF ++ ++ ++ ext_builddir=ext/varfilter ++ ext_srcdir=$abs_srcdir/ext/varfilter ++ ++ ac_extra= ++ ++ if test "$ext_shared" != "shared" && test "$ext_shared" != "yes" && test "" != "cli"; then ++ ++ ++ ++ case ext/varfilter in ++ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;; ++ /*) ac_srcdir=`echo "ext/varfilter"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;; ++ *) ac_srcdir="$abs_srcdir/ext/varfilter/"; ac_bdir="ext/varfilter/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;; ++ esac ++ ++ ++ ++ b_c_pre=$php_c_pre ++ b_cxx_pre=$php_cxx_pre ++ b_c_meta=$php_c_meta ++ b_cxx_meta=$php_cxx_meta ++ b_c_post=$php_c_post ++ b_cxx_post=$php_cxx_post ++ b_lo=$php_lo ++ ++ ++ old_IFS=$IFS ++ for ac_src in varfilter.c; do ++ ++ IFS=. ++ set $ac_src ++ ac_obj=$1 ++ IFS=$old_IFS ++ ++ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo" ++ ++ case $ac_src in ++ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;; ++ *.cpp) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;; ++ esac ++ ++ cat >>Makefile.objects<>Makefile.objects<>Makefile.objects<> confdefs.h <>Makefile.objects<>Makefile.objects<&6 +@@ -97351,7 +97829,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + network.c php_open_temporary_file.c php_logos.c \ +- output.c ; do ++ output.c hardening_patch.c ; do + + IFS=. + set $ac_src +@@ -97579,7 +98057,7 @@ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ + zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ +- zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c; do ++ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_canary.c; do + + IFS=. + set $ac_src +diff -Naur php-5.0.4/configure.in hardening-patch-5.0.4-0.3.2/configure.in +--- php-5.0.4/configure.in 2005-03-30 23:43:12.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/configure.in 2005-06-26 22:28:34.000000000 +0200 +@@ -235,7 +235,7 @@ + sinclude(Zend/acinclude.m4) + sinclude(Zend/Zend.m4) + sinclude(TSRM/tsrm.m4) +- ++sinclude(main/hardening_patch.m4) + + + divert(2) +@@ -620,6 +620,7 @@ + AC_FUNC_ALLOCA + dnl PHP_AC_BROKEN_SPRINTF + dnl PHP_AC_BROKEN_SNPRINTF ++PHP_AC_BROKEN_REALPATH + PHP_DECLARED_TIMEZONE + PHP_TIME_R_TYPE + PHP_READDIR_R_TYPE +@@ -1262,7 +1263,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + network.c php_open_temporary_file.c php_logos.c \ +- output.c ) ++ output.c hardening_patch.c ) + + PHP_ADD_SOURCES(main/streams, streams.c cast.c memory.c filter.c \ + plain_wrapper.c userspace.c transports.c xp_socket.c mmap.c) +@@ -1280,7 +1281,7 @@ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ + zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ +- zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c) ++ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_canary.c ) + + if test -r "$abs_srcdir/Zend/zend_objects.c"; then + PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_mm.c \ +diff -Naur php-5.0.4/ext/fbsql/php_fbsql.c hardening-patch-5.0.4-0.3.2/ext/fbsql/php_fbsql.c +--- php-5.0.4/ext/fbsql/php_fbsql.c 2005-02-09 20:32:45.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/ext/fbsql/php_fbsql.c 2005-07-03 20:50:08.000000000 +0200 +@@ -1852,8 +1852,24 @@ + } + else if (fbcmdErrorsFound(md)) + { ++#if HARDENING_PATCH ++ char* query_copy; ++ int i; ++#endif + FBCErrorMetaData* emd = fbcdcErrorMetaData(c, md); + char* emg = fbcemdAllErrorMessages(emd); ++#if HARDENING_PATCH ++ query_copy=estrdup(query_copy); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "fbsql error: %s - query: %s", emg, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ free(emg); ++ fbcemdRelease(emd); ++ result = 0; ++ zend_bailout(); ++ } ++#endif + if (FB_SQL_G(generateWarnings)) + { + if (emg) +diff -Naur php-5.0.4/ext/mysql/php_mysql.c hardening-patch-5.0.4-0.3.2/ext/mysql/php_mysql.c +--- php-5.0.4/ext/mysql/php_mysql.c 2005-02-22 15:59:30.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/ext/mysql/php_mysql.c 2005-07-03 11:04:29.000000000 +0200 +@@ -1221,6 +1221,8 @@ + { + php_mysql_conn *mysql; + MYSQL_RES *mysql_result; ++ char *copy_query; ++ int i; + + ZEND_FETCH_RESOURCE2(mysql, php_mysql_conn *, mysql_link, link_id, "MySQL-Link", le_link, le_plink); + +@@ -1271,6 +1273,13 @@ + php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #else +@@ -1281,6 +1290,13 @@ + php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #endif +diff -Naur php-5.0.4/ext/mysqli/mysqli_nonapi.c hardening-patch-5.0.4-0.3.2/ext/mysqli/mysqli_nonapi.c +--- php-5.0.4/ext/mysqli/mysqli_nonapi.c 2005-02-25 00:59:49.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/ext/mysqli/mysqli_nonapi.c 2005-07-09 08:40:55.890819992 +0200 +@@ -228,6 +228,17 @@ + if (mysql_real_query(mysql->mysql, query, query_len)) { + char s_error[MYSQL_ERRMSG_SIZE], s_sqlstate[SQLSTATE_LENGTH+1]; + unsigned int s_errno; ++#if HARDENING_PATCH ++ char *query_copy = estrdup(query); ++ int i; ++ ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "MySQLi error: %s - query: %s", mysql->mysql->net.last_errno, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } ++#endif + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); + + /* we have to save error information, cause +@@ -268,6 +279,17 @@ + MYSQLI_DISABLE_MQ; + + if (mysql_real_query(mysql->mysql, query, query_len)) { ++#if HARDENING_PATCH ++ char *query_copy = estrdup(query); ++ int i; ++ ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "MySQLi error: %s - query: %s", mysql->mysql->net.last_errno, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } ++#endif + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); + RETURN_FALSE; + } +diff -Naur php-5.0.4/ext/pgsql/pgsql.c hardening-patch-5.0.4-0.3.2/ext/pgsql/pgsql.c +--- php-5.0.4/ext/pgsql/pgsql.c 2004-05-12 18:49:47.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/ext/pgsql/pgsql.c 2005-07-03 21:16:44.000000000 +0200 +@@ -1076,10 +1076,28 @@ + case PGRES_EMPTY_QUERY: + case PGRES_BAD_RESPONSE: + case PGRES_NONFATAL_ERROR: +- case PGRES_FATAL_ERROR: +- PHP_PQ_ERROR("Query failed: %s", pgsql); +- PQclear(pgsql_result); +- RETURN_FALSE; ++ case PGRES_FATAL_ERROR: ++ { ++#if HARDENING_PATCH ++ int i; ++ char *query_copy; ++#endif ++ char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); ++ PQclear(pgsql_result); ++#if HARDENING_PATCH ++ query_copy = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "PgSQL error: %s - query: %s", msgbuf, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ efree(msgbuf); ++ zend_bailout(); ++ } ++#endif ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Query failed: %s", msgbuf); ++ efree(msgbuf); ++ RETURN_FALSE; ++ } + break; + case PGRES_COMMAND_OK: /* successful command that did not return rows */ + default: +diff -Naur php-5.0.4/ext/sqlite/sqlite.c hardening-patch-5.0.4-0.3.2/ext/sqlite/sqlite.c +--- php-5.0.4/ext/sqlite/sqlite.c 2004-09-26 03:41:40.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/ext/sqlite/sqlite.c 2005-07-03 20:52:00.000000000 +0200 +@@ -1473,6 +1473,19 @@ + db->last_err_code = ret; + + if (ret != SQLITE_OK) { ++#if HARDENING_PATCH ++ char *query_copy; ++ int i; ++ ++ query_copy = estrdup(sql); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "SQLite error: %s - query: %s", errtext, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ sqlite_freemem(errtext); ++ zend_bailout(); ++ } ++#endif + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext); + sqlite_freemem(errtext); + goto terminate; +diff -Naur php-5.0.4/ext/standard/array.c hardening-patch-5.0.4-0.3.2/ext/standard/array.c +--- php-5.0.4/ext/standard/array.c 2005-03-12 11:12:49.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/ext/standard/array.c 2005-06-27 00:46:39.000000000 +0200 +@@ -1255,6 +1255,32 @@ + } + } + } ++ ++ if (var_name[0] == 'H') { ++ if ((strcmp(var_name, "HTTP_GET_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_FILES")==0)|| ++ (strcmp(var_name, "HTTP_ENV_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(var_name, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(var_name, "HTTP_RAW_POST_DATA")==0)) { ++ return 0; ++ } ++ } else if (var_name[0] == '_') { ++ if ((strcmp(var_name, "_COOKIE")==0)|| ++ (strcmp(var_name, "_ENV")==0)|| ++ (strcmp(var_name, "_FILES")==0)|| ++ (strcmp(var_name, "_GET")==0)|| ++ (strcmp(var_name, "_POST")==0)|| ++ (strcmp(var_name, "_REQUEST")==0)|| ++ (strcmp(var_name, "_SESSION")==0)|| ++ (strcmp(var_name, "_SERVER")==0)) { ++ return 0; ++ } ++ } else if (strcmp(var_name, "GLOBALS")==0) { ++ return 0; ++ } + + return 1; + } +diff -Naur php-5.0.4/ext/standard/basic_functions.c hardening-patch-5.0.4-0.3.2/ext/standard/basic_functions.c +--- php-5.0.4/ext/standard/basic_functions.c 2005-03-10 13:10:57.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/ext/standard/basic_functions.c 2005-06-27 00:47:11.000000000 +0200 +@@ -617,7 +617,7 @@ + PHP_FALIAS(socket_get_status, stream_get_meta_data, NULL) + + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +- PHP_FE(realpath, NULL) ++ PHP_STATIC_FE("realpath", zif_real_path, NULL) + #endif + + #ifdef HAVE_FNMATCH +@@ -3124,6 +3124,35 @@ + memcpy(new_key, prefix, prefix_len); + memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + ++ if (new_key[0] == 'H') { ++ if ((strcmp(new_key, "HTTP_GET_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_FILES")==0)|| ++ (strcmp(new_key, "HTTP_ENV_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(new_key, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(new_key, "HTTP_RAW_POST_DATA")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (new_key[0] == '_') { ++ if ((strcmp(new_key, "_COOKIE")==0)|| ++ (strcmp(new_key, "_ENV")==0)|| ++ (strcmp(new_key, "_FILES")==0)|| ++ (strcmp(new_key, "_GET")==0)|| ++ (strcmp(new_key, "_POST")==0)|| ++ (strcmp(new_key, "_REQUEST")==0)|| ++ (strcmp(new_key, "_SESSION")==0)|| ++ (strcmp(new_key, "_SERVER")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (strcmp(new_key, "GLOBALS")==0) { ++ efree(new_key); ++ return 0; ++ } ++ + zend_hash_del(&EG(symbol_table), new_key, new_key_len); + ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, (*var)->refcount+1, 0); + +diff -Naur php-5.0.4/ext/standard/file.c hardening-patch-5.0.4-0.3.2/ext/standard/file.c +--- php-5.0.4/ext/standard/file.c 2005-03-27 17:53:30.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/ext/standard/file.c 2005-06-26 20:59:20.000000000 +0200 +@@ -2044,7 +2044,7 @@ + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) + /* {{{ proto string realpath(string path) + Return the resolved path */ +-PHP_FUNCTION(realpath) ++PHP_FUNCTION(real_path) + { + zval **path; + char resolved_path_buff[MAXPATHLEN]; +diff -Naur php-5.0.4/ext/standard/file.h hardening-patch-5.0.4-0.3.2/ext/standard/file.h +--- php-5.0.4/ext/standard/file.h 2004-06-21 23:08:05.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/ext/standard/file.h 2005-06-26 20:59:20.000000000 +0200 +@@ -60,7 +60,7 @@ + PHP_FUNCTION(fd_set); + PHP_FUNCTION(fd_isset); + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +-PHP_FUNCTION(realpath); ++PHP_FUNCTION(real_path); + PHP_FUNCTION(fnmatch); + #endif + PHP_NAMED_FUNCTION(php_if_ftruncate); +diff -Naur php-5.0.4/ext/standard/ftp_fopen_wrapper.c hardening-patch-5.0.4-0.3.2/ext/standard/ftp_fopen_wrapper.c +--- php-5.0.4/ext/standard/ftp_fopen_wrapper.c 2005-03-21 09:42:34.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/ext/standard/ftp_fopen_wrapper.c 2005-06-27 10:41:04.000000000 +0200 +@@ -113,7 +113,7 @@ + { + php_stream *stream = NULL, *reuseid = NULL; + php_url *resource = NULL; +- int result, use_ssl, use_ssl_on_data = 0; ++ int result, use_ssl, use_ssl_on_data = 0, tmp_len; + char *scratch; + char tmp_line[512]; + +@@ -206,10 +206,25 @@ + #endif + } + ++#define PHP_FTP_CNTRL_CHK(val, val_len, err_msg) { \ ++ unsigned char *s = val, *e = s + val_len; \ ++ while (s < e) { \ ++ if (iscntrl(*s)) { \ ++ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, err_msg, val); \ ++ goto connect_errexit; \ ++ } \ ++ s++; \ ++ } \ ++} ++ + /* send the user name */ + php_stream_write_string(stream, "USER "); + if (resource->user != NULL) { +- php_raw_url_decode(resource->user, strlen(resource->user)); ++ unsigned char *s, *e; ++ tmp_len = php_raw_url_decode(resource->user, strlen(resource->user)); ++ ++ PHP_FTP_CNTRL_CHK(resource->user, tmp_len, "Invalid login %s") ++ + php_stream_write_string(stream, resource->user); + } else { + php_stream_write_string(stream, "anonymous"); +@@ -225,7 +240,10 @@ + + php_stream_write_string(stream, "PASS "); + if (resource->pass != NULL) { +- php_raw_url_decode(resource->pass, strlen(resource->pass)); ++ tmp_len = php_raw_url_decode(resource->pass, strlen(resource->pass)); ++ ++ PHP_FTP_CNTRL_CHK(resource->pass, tmp_len, "Invalid password %s") ++ + php_stream_write_string(stream, resource->pass); + } else { + /* if the user has configured who they are, +diff -Naur php-5.0.4/ext/standard/head.c hardening-patch-5.0.4-0.3.2/ext/standard/head.c +--- php-5.0.4/ext/standard/head.c 2005-01-07 22:16:00.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/ext/standard/head.c 2005-07-05 18:33:34.000000000 +0200 +@@ -45,10 +45,31 @@ + { + zend_bool rep = 1; + sapi_header_line ctr = {0}; ++#if HARDENING_PATCH ++ int i; ++#endif + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &ctr.line, + &ctr.line_len, &rep, &ctr.response_code) == FAILURE) + return; ++ ++#if HARDENING_PATCH ++ if (!HG(hphp_multiheader)) { ++ for (i=0; i0 && (i"); + } + ++#if HARDENING_PATCH ++ if (!sapi_module.phpinfo_as_text) { ++ php_printf("

PHP Version %s with Hardening-Patch %s

\n", PHP_VERSION, HARDENING_PATCH_VERSION); ++ } else { ++ char temp_ver[40]; ++ ++ snprintf(temp_ver, sizeof(temp_ver), "%s/%s", PHP_VERSION, HARDENING_PATCH_VERSION); ++ php_info_print_table_row(2, "PHP/Hardening-Patch Version", temp_ver); ++ } ++#else + if (!sapi_module.phpinfo_as_text) { + php_printf("

PHP Version %s

\n", PHP_VERSION); + } else { + php_info_print_table_row(2, "PHP Version", PHP_VERSION); +- } ++ } ++#endif + php_info_print_box_end(); + php_info_print_table_start(); + php_info_print_table_row(2, "System", php_uname ); +diff -Naur php-5.0.4/ext/standard/syslog.c hardening-patch-5.0.4-0.3.2/ext/standard/syslog.c +--- php-5.0.4/ext/standard/syslog.c 2004-07-30 16:39:18.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/ext/standard/syslog.c 2005-07-06 13:19:50.000000000 +0200 +@@ -42,6 +42,7 @@ + */ + PHP_MINIT_FUNCTION(syslog) + { ++#if !HARDENING_PATCH + /* error levels */ + REGISTER_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ + REGISTER_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ +@@ -97,7 +98,7 @@ + /* AIX doesn't have LOG_PERROR */ + REGISTER_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ + #endif +- ++#endif + return SUCCESS; + } + /* }}} */ +diff -Naur php-5.0.4/ext/varfilter/config.m4 hardening-patch-5.0.4-0.3.2/ext/varfilter/config.m4 +--- php-5.0.4/ext/varfilter/config.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/ext/varfilter/config.m4 2005-07-06 13:12:40.000000000 +0200 +@@ -0,0 +1,11 @@ ++dnl ++dnl $Id: config.m4,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++dnl ++ ++PHP_ARG_ENABLE(varfilter, whether to enable Hardening-Patch's variable filter, ++[ --disable-varfilter Disable Hardening-Patch's variable filter], yes) ++ ++if test "$PHP_VARFILTER" != "no"; then ++ AC_DEFINE(HAVE_VARFILTER, 1, [ ]) ++ PHP_NEW_EXTENSION(varfilter, varfilter.c, $ext_shared) ++fi +diff -Naur php-5.0.4/ext/varfilter/CREDITS hardening-patch-5.0.4-0.3.2/ext/varfilter/CREDITS +--- php-5.0.4/ext/varfilter/CREDITS 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/ext/varfilter/CREDITS 2005-07-06 13:12:40.000000000 +0200 +@@ -0,0 +1,2 @@ ++varfilter ++Stefan Esser +\ Kein Zeilenumbruch am Dateiende. +diff -Naur php-5.0.4/ext/varfilter/php_varfilter.h hardening-patch-5.0.4-0.3.2/ext/varfilter/php_varfilter.h +--- php-5.0.4/ext/varfilter/php_varfilter.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/ext/varfilter/php_varfilter.h 2005-07-06 13:12:40.000000000 +0200 +@@ -0,0 +1,111 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: php_varfilter.h,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifndef PHP_VARFILTER_H ++#define PHP_VARFILTER_H ++ ++extern zend_module_entry varfilter_module_entry; ++#define phpext_varfilter_ptr &varfilter_module_entry ++ ++#ifdef PHP_WIN32 ++#define PHP_VARFILTER_API __declspec(dllexport) ++#else ++#define PHP_VARFILTER_API ++#endif ++ ++#ifdef ZTS ++#include "TSRM.h" ++#endif ++ ++#include "SAPI.h" ++ ++#include "php_variables.h" ++ ++ ++PHP_MINIT_FUNCTION(varfilter); ++PHP_MSHUTDOWN_FUNCTION(varfilter); ++PHP_RINIT_FUNCTION(varfilter); ++PHP_RSHUTDOWN_FUNCTION(varfilter); ++PHP_MINFO_FUNCTION(varfilter); ++ ++ ++ZEND_BEGIN_MODULE_GLOBALS(varfilter) ++// request variables ++ long max_request_variables; ++ long cur_request_variables; ++ long max_varname_length; ++ long max_totalname_length; ++ long max_value_length; ++ long max_array_depth; ++ long max_array_index_length; ++// cookie variables ++ long max_cookie_vars; ++ long cur_cookie_vars; ++ long max_cookie_name_length; ++ long max_cookie_totalname_length; ++ long max_cookie_value_length; ++ long max_cookie_array_depth; ++ long max_cookie_array_index_length; ++// get variables ++ long max_get_vars; ++ long cur_get_vars; ++ long max_get_name_length; ++ long max_get_totalname_length; ++ long max_get_value_length; ++ long max_get_array_depth; ++ long max_get_array_index_length; ++// post variables ++ long max_post_vars; ++ long cur_post_vars; ++ long max_post_name_length; ++ long max_post_totalname_length; ++ long max_post_value_length; ++ long max_post_array_depth; ++ long max_post_array_index_length; ++// fileupload ++ long max_uploads; ++ long cur_uploads; ++ zend_bool disallow_elf_files; ++ char *verification_script; ++ ++ZEND_END_MODULE_GLOBALS(varfilter) ++ ++ ++#ifdef ZTS ++#define VARFILTER_G(v) TSRMG(varfilter_globals_id, zend_varfilter_globals *, v) ++#else ++#define VARFILTER_G(v) (varfilter_globals.v) ++#endif ++ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter); ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter); ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter); ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter); ++ ++#endif /* PHP_VARFILTER_H */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * indent-tabs-mode: t ++ * End: ++ */ +diff -Naur php-5.0.4/ext/varfilter/varfilter.c hardening-patch-5.0.4-0.3.2/ext/varfilter/varfilter.c +--- php-5.0.4/ext/varfilter/varfilter.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/ext/varfilter/varfilter.c 2005-07-09 08:46:50.126967912 +0200 +@@ -0,0 +1,604 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: varfilter.c,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "php.h" ++#include "php_ini.h" ++#include "ext/standard/info.h" ++#include "php_varfilter.h" ++#include "hardening_patch.h" ++ ++ZEND_DECLARE_MODULE_GLOBALS(varfilter) ++ ++/* True global resources - no need for thread safety here */ ++static int le_varfilter; ++ ++/* {{{ varfilter_module_entry ++ */ ++zend_module_entry varfilter_module_entry = { ++#if ZEND_MODULE_API_NO >= 20010901 ++ STANDARD_MODULE_HEADER, ++#endif ++ "varfilter", ++ NULL, ++ PHP_MINIT(varfilter), ++ PHP_MSHUTDOWN(varfilter), ++ PHP_RINIT(varfilter), /* Replace with NULL if there's nothing to do at request start */ ++ PHP_RSHUTDOWN(varfilter), /* Replace with NULL if there's nothing to do at request end */ ++ PHP_MINFO(varfilter), ++#if ZEND_MODULE_API_NO >= 20010901 ++ "0.3.2", /* Replace with version number for your extension */ ++#endif ++ STANDARD_MODULE_PROPERTIES ++}; ++/* }}} */ ++ ++#ifdef COMPILE_DL_VARFILTER ++ZEND_GET_MODULE(varfilter) ++#endif ++ ++/* {{{ PHP_INI ++ */ ++PHP_INI_BEGIN() ++ /* for backward compatibility */ ++ STD_PHP_INI_ENTRY("varfilter.max_request_variables", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.request.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.cookie.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_cookie_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_value_length", "10000", PHP_INI_PERDIR, OnUpdateLong, max_cookie_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.get.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_get_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_get_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_value_length", "512", PHP_INI_PERDIR, OnUpdateLong, max_get_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_depth", "50", PHP_INI_PERDIR, OnUpdateLong, max_get_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.post.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_post_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_post_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_post_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_post_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.upload.max_uploads", "25", PHP_INI_PERDIR, OnUpdateLong, max_uploads, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.disallow_elf_files", "1", PHP_INI_SYSTEM, OnUpdateBool, disallow_elf_files, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.verification_script", NULL, PHP_INI_SYSTEM, OnUpdateString, verification_script, zend_varfilter_globals, varfilter_globals) ++ ++ ++PHP_INI_END() ++/* }}} */ ++ ++/* {{{ php_varfilter_init_globals ++ */ ++static void php_varfilter_init_globals(zend_varfilter_globals *varfilter_globals) ++{ ++ varfilter_globals->max_request_variables = 200; ++ varfilter_globals->max_varname_length = 64; ++ varfilter_globals->max_value_length = 10000; ++ varfilter_globals->max_array_depth = 100; ++ varfilter_globals->max_totalname_length = 256; ++ varfilter_globals->max_array_index_length = 64; ++ ++ varfilter_globals->max_cookie_vars = 100; ++ varfilter_globals->max_cookie_name_length = 64; ++ varfilter_globals->max_cookie_totalname_length = 256; ++ varfilter_globals->max_cookie_value_length = 10000; ++ varfilter_globals->max_cookie_array_depth = 100; ++ varfilter_globals->max_cookie_array_index_length = 64; ++ ++ varfilter_globals->max_get_vars = 100; ++ varfilter_globals->max_get_name_length = 64; ++ varfilter_globals->max_get_totalname_length = 256; ++ varfilter_globals->max_get_value_length = 512; ++ varfilter_globals->max_get_array_depth = 50; ++ varfilter_globals->max_get_array_index_length = 64; ++ ++ varfilter_globals->max_post_vars = 200; ++ varfilter_globals->max_post_name_length = 64; ++ varfilter_globals->max_post_totalname_length = 256; ++ varfilter_globals->max_post_value_length = 65000; ++ varfilter_globals->max_post_array_depth = 100; ++ varfilter_globals->max_post_array_index_length = 64; ++ ++ varfilter_globals->max_uploads = 25; ++ varfilter_globals->disallow_elf_files = 1; ++ varfilter_globals->verification_script = NULL; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINIT_FUNCTION ++ */ ++PHP_MINIT_FUNCTION(varfilter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(varfilter, php_varfilter_init_globals, NULL); ++ REGISTER_INI_ENTRIES(); ++ ++ sapi_register_input_filter(varfilter_input_filter); ++ sapi_register_pre_upload_filter(varfilter_pre_upload_filter); ++ sapi_register_upload_content_filter(varfilter_upload_content_filter); ++ sapi_register_post_upload_filter(varfilter_post_upload_filter); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MSHUTDOWN_FUNCTION ++ */ ++PHP_MSHUTDOWN_FUNCTION(varfilter) ++{ ++// zend_hash_apply_with_arguments(&HG(lists.functionlists), (apply_func_args_t) show_stuff, 0); ++ ++ UNREGISTER_INI_ENTRIES(); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request start */ ++/* {{{ PHP_RINIT_FUNCTION ++ */ ++PHP_RINIT_FUNCTION(varfilter) ++{ ++ VARFILTER_G(cur_request_variables) = 0; ++ VARFILTER_G(cur_get_vars) = 0; ++ VARFILTER_G(cur_post_vars) = 0; ++ VARFILTER_G(cur_cookie_vars) = 0; ++ ++ VARFILTER_G(cur_uploads) = 0; ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request end */ ++/* {{{ PHP_RSHUTDOWN_FUNCTION ++ */ ++PHP_RSHUTDOWN_FUNCTION(varfilter) ++{ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINFO_FUNCTION ++ */ ++PHP_MINFO_FUNCTION(varfilter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_header(2, "Hardening-Patch's variable filter support", "enabled"); ++ php_info_print_table_end(); ++ ++ DISPLAY_INI_ENTRIES(); ++} ++/* }}} */ ++ ++/* {{{ normalize_varname ++ */ ++static void normalize_varname(char *varname) ++{ ++ char *s=varname, *index=NULL, *indexend=NULL, *p; ++ ++ /* overjump leading space */ ++ while (*s == ' ') { ++ s++; ++ } ++ ++ /* and remove it */ ++ if (s != varname) { ++ memmove(varname, s, strlen(s)+1); ++ } ++ ++ for (p=varname; *p && *p != '['; p++) { ++ switch(*p) { ++ case ' ': ++ case '.': ++ *p='_'; ++ break; ++ } ++ } ++ ++ /* find index */ ++ index = strchr(varname, '['); ++ if (index) { ++ index++; ++ s=index; ++ } else { ++ return; ++ } ++ ++ /* done? */ ++ while (index) { ++ ++ while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') { ++ index++; ++ } ++ indexend = strchr(index, ']'); ++ indexend = indexend ? indexend + 1 : index + strlen(index); ++ ++ if (s != index) { ++ memmove(s, index, strlen(index)+1); ++ s += indexend-index; ++ } else { ++ s = indexend; ++ } ++ ++ if (*s == '[') { ++ s++; ++ index = s; ++ } else { ++ index = NULL; ++ } ++ } ++ *s++='\0'; ++} ++/* }}} */ ++ ++/* {{{ SAPI_PRE_UPLOAD_FILTER_FUNC ++ */ ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter) ++{ ++ /* Drop this fileupload if the limit is reached */ ++ if (VARFILTER_G(max_uploads) && VARFILTER_G(max_uploads) <= VARFILTER_G(cur_uploads)) { ++ php_security_log(S_FILES, "configured fileupload limit exceeded - file dropped"); ++ return FAILURE; ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_UPLOAD_CONTENT_FILTER_FUNC ++ */ ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter) ++{ ++ ++ if (VARFILTER_G(disallow_elf_files)) { ++ ++ if (offset == 0 && buffer_len > 10) { ++ ++ if (buffer[0] == 0x7F && buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F') { ++ php_security_log(S_FILES, "uploaded file is an ELF executable - file dropped"); ++ return FAILURE; ++ } ++ } ++ ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_POST_UPLOAD_FILTER_FUNC ++ */ ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter) ++{ ++ int retval = SUCCESS; ++ ++ if (VARFILTER_G(verification_script)) { ++ char cmd[8192]; ++ FILE *in; ++ int first=1; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s", VARFILTER_G(verification_script), tmpfilename); ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_FILES, "unable to execute fileupload verification script - file dropped"); ++ return FAILURE; ++ } ++ ++ retval = FAILURE; ++ ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ if (first) { ++ retval = atoi(cmd) == 1 ? SUCCESS : FAILURE; ++ first = 0; ++ } ++ } ++ pclose(in); ++ } ++ ++ if (retval != SUCCESS) { ++ php_security_log(S_FILES, "fileupload verification script disallows file - file dropped"); ++ return FAILURE; ++ } ++ ++ VARFILTER_G(cur_uploads)++; ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_INPUT_FILTER_FUNC ++ */ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter) ++{ ++ char *index, *prev_index = NULL, *copy_var; ++ unsigned int var_len, total_len, depth = 0, rv; ++ ++ /* Drop this variable if the limit is reached */ ++ if (VARFILTER_G(max_request_variables) && VARFILTER_G(max_request_variables) <= VARFILTER_G(cur_request_variables)) { ++ php_security_log(S_VARS, "configured request variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_vars) && VARFILTER_G(max_get_vars) <= VARFILTER_G(cur_get_vars)) { ++ php_security_log(S_VARS, "configured GET variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_vars) && VARFILTER_G(max_cookie_vars) <= VARFILTER_G(cur_cookie_vars)) { ++ php_security_log(S_VARS, "configured COOKIE variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_vars) && VARFILTER_G(max_post_vars) <= VARFILTER_G(cur_post_vars)) { ++ php_security_log(S_VARS, "configured POST variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ ++ /* Drop this variable if it exceeds the value length limit */ ++ if (VARFILTER_G(max_value_length) && VARFILTER_G(max_value_length) < val_len) { ++ php_security_log(S_VARS, "configured request variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_value_length) && VARFILTER_G(max_get_value_length) < val_len) { ++ php_security_log(S_VARS, "configured GET variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_value_length) && VARFILTER_G(max_cookie_value_length) < val_len) { ++ php_security_log(S_VARS, "configured COOKIE variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_value_length) && VARFILTER_G(max_post_value_length) < val_len) { ++ php_security_log(S_VARS, "configured POST variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Normalize the variable name */ ++ normalize_varname(var); ++ ++ /* Find length of variable name */ ++ index = strchr(var, '['); ++ total_len = strlen(var); ++ var_len = index ? index-var : total_len; ++ ++ /* Drop this variable if it exceeds the varname/total length limit */ ++ if (VARFILTER_G(max_varname_length) && VARFILTER_G(max_varname_length) < var_len) { ++ php_security_log(S_VARS, "configured request variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_totalname_length) && VARFILTER_G(max_totalname_length) < total_len) { ++ php_security_log(S_VARS, "configured request variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_name_length) && VARFILTER_G(max_get_name_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_get_totalname_length) && VARFILTER_G(max_get_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_name_length) && VARFILTER_G(max_cookie_name_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_cookie_totalname_length) && VARFILTER_G(max_cookie_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_name_length) && VARFILTER_G(max_post_name_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_post_totalname_length) && VARFILTER_G(max_post_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Find out array depth */ ++ while (index) { ++ unsigned int index_length; ++ ++ depth++; ++ index = strchr(index+1, '['); ++ ++ if (prev_index) { ++ index_length = index ? index - 1 - prev_index - 1: strlen(prev_index); ++ ++ if (VARFILTER_G(max_array_index_length) && VARFILTER_G(max_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured request variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_index_length) && VARFILTER_G(max_get_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured GET variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_index_length) && VARFILTER_G(max_cookie_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured COOKIE variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_index_length) && VARFILTER_G(max_post_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured POST variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ prev_index = index; ++ } ++ ++ } ++ ++ /* Drop this variable if it exceeds the array depth limit */ ++ if (VARFILTER_G(max_array_depth) && VARFILTER_G(max_array_depth) < depth) { ++ php_security_log(S_VARS, "configured request variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_depth) && VARFILTER_G(max_get_array_depth) < depth) { ++ php_security_log(S_VARS, "configured GET variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_depth) && VARFILTER_G(max_cookie_array_depth) < depth) { ++ php_security_log(S_VARS, "configured COOKIE variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_depth) && VARFILTER_G(max_post_array_depth) < depth) { ++ php_security_log(S_VARS, "configured POST variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Drop this variable if it is one of GLOBALS, _GET, _POST, ... */ ++ /* This is to protect several silly scripts that do globalizing themself */ ++ ++ switch (var_len) { ++ case 18: ++ if (memcmp(var, "HTTP_RAW_POST_DATA", 18)==0) goto protected_varname; ++ break; ++ case 17: ++ if (memcmp(var, "HTTP_SESSION_VARS", 17)==0) goto protected_varname; ++ break; ++ case 16: ++ if (memcmp(var, "HTTP_SERVER_VARS", 16)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_COOKIE_VARS", 16)==0) goto protected_varname; ++ break; ++ case 15: ++ if (memcmp(var, "HTTP_POST_FILES", 15)==0) goto protected_varname; ++ break; ++ case 14: ++ if (memcmp(var, "HTTP_POST_VARS", 14)==0) goto protected_varname; ++ break; ++ case 13: ++ if (memcmp(var, "HTTP_GET_VARS", 13)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_ENV_VARS", 13)==0) goto protected_varname; ++ break; ++ case 8: ++ if (memcmp(var, "_SESSION", 8)==0) goto protected_varname; ++ if (memcmp(var, "_REQUEST", 8)==0) goto protected_varname; ++ break; ++ case 7: ++ if (memcmp(var, "GLOBALS", 7)==0) goto protected_varname; ++ if (memcmp(var, "_COOKIE", 7)==0) goto protected_varname; ++ if (memcmp(var, "_SERVER", 7)==0) goto protected_varname; ++ break; ++ case 6: ++ if (memcmp(var, "_FILES", 6)==0) goto protected_varname; ++ break; ++ case 5: ++ if (memcmp(var, "_POST", 5)==0) goto protected_varname; ++ break; ++ case 4: ++ if (memcmp(var, "_ENV", 4)==0) goto protected_varname; ++ if (memcmp(var, "_GET", 4)==0) goto protected_varname; ++ break; ++ } ++ ++ /* Okay let PHP register this variable */ ++ VARFILTER_G(cur_request_variables)++; ++ switch (arg) { ++ case PARSE_GET: ++ VARFILTER_G(cur_get_vars)++; ++ break; ++ case PARSE_COOKIE: ++ VARFILTER_G(cur_cookie_vars)++; ++ break; ++ case PARSE_POST: ++ VARFILTER_G(cur_post_vars)++; ++ break; ++ } ++ ++ if (new_val_len) { ++ *new_val_len = val_len; ++ } ++ ++ return 1; ++protected_varname: ++ php_security_log(S_VARS, "tried to register forbidden variable '%s' through %s variables", var, arg == PARSE_GET ? "GET" : arg == PARSE_POST ? "POST" : "COOKIE"); ++ return 0; ++} ++/* }}} */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: noet sw=4 ts=4 fdm=marker ++ * vim<600: noet sw=4 ts=4 ++ */ ++ ++ +diff -Naur php-5.0.4/main/fopen_wrappers.c hardening-patch-5.0.4-0.3.2/main/fopen_wrappers.c +--- php-5.0.4/main/fopen_wrappers.c 2005-03-11 07:55:22.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/main/fopen_wrappers.c 2005-06-26 20:59:20.000000000 +0200 +@@ -163,6 +163,21 @@ + char *pathbuf; + char *ptr; + char *end; ++ char path_copy[MAXPATHLEN]; ++ int path_len; ++ ++ /* Special case path ends with a trailing slash */ ++ path_len = strlen(path); ++ if (path_len >= MAXPATHLEN) { ++ errno = EPERM; /* we deny permission to open it */ ++ return -1; ++ } ++ if (path_len > 0 && path[path_len-1] == PHP_DIR_SEPARATOR) { ++ memcpy(path_copy, path, path_len+1); ++ while (path_len > 0 && path_copy[path_len-1] == PHP_DIR_SEPARATOR) path_len--; ++ path_copy[path_len] = '\0'; ++ path = (const char *)&path_copy; ++ } + + pathbuf = estrdup(PG(open_basedir)); + +diff -Naur php-5.0.4/main/hardened_globals.h hardening-patch-5.0.4-0.3.2/main/hardened_globals.h +--- php-5.0.4/main/hardened_globals.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/main/hardened_globals.h 2005-07-05 18:31:23.000000000 +0200 +@@ -0,0 +1,56 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_GLOBALS_H ++#define HARDENED_GLOBALS_H ++ ++typedef struct _hardened_globals hardened_globals_struct; ++ ++#ifdef ZTS ++# define HG(v) TSRMG(hardened_globals_id, hardened_globals_struct *, v) ++extern int hardened_globals_id; ++#else ++# define HG(v) (hardened_globals.v) ++extern struct _hardened_globals hardened_globals; ++#endif ++ ++ ++struct _hardened_globals { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_1; ++ unsigned int canary_2; ++#endif ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_3; ++ unsigned int canary_4; ++ unsigned int ll_canary_inited; ++#endif ++ zend_bool hphp_sql_bailout_on_error; ++ zend_bool hphp_multiheader; ++ unsigned int dummy; ++}; ++ ++ ++#endif /* HARDENED_GLOBALS_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Naur php-5.0.4/main/hardening_patch.c hardening-patch-5.0.4-0.3.2/main/hardening_patch.c +--- php-5.0.4/main/hardening_patch.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/main/hardening_patch.c 2005-07-03 10:39:30.000000000 +0200 +@@ -0,0 +1,322 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: hardening_patch.c,v 1.2 2004/11/21 09:38:52 ionic Exp $ */ ++ ++#include "php.h" ++ ++#include ++#include ++ ++#if HAVE_UNISTD_H ++#include ++#endif ++#include "SAPI.h" ++#include "php_globals.h" ++ ++#if HARDENING_PATCH ++ ++#ifdef HAVE_SYS_SOCKET_H ++#include ++#endif ++ ++#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE) ++#undef AF_UNIX ++#endif ++ ++#if defined(AF_UNIX) ++#include ++#endif ++ ++#define SYSLOG_PATH "/dev/log" ++ ++#include "snprintf.h" ++ ++#include "hardening_patch.h" ++ ++#ifdef ZTS ++#include "hardened_globals.h" ++int hardened_globals_id; ++#else ++struct _hardened_globals hardened_globals; ++#endif ++ ++static void hardened_globals_ctor(hardened_globals_struct *hardened_globals TSRMLS_DC) ++{ ++ memset(hardened_globals, 0, sizeof(*hardened_globals)); ++} ++ ++ ++PHPAPI void hardened_startup() ++{ ++#ifdef ZTS ++ ts_allocate_id(&hardened_globals_id, sizeof(hardened_globals_struct), (ts_allocate_ctor) hardened_globals_ctor, NULL); ++#else ++ hardened_globals_ctor(&hardened_globals TSRMLS_CC); ++#endif ++} ++ ++char *loglevel2string(int loglevel) ++{ ++ switch (loglevel) { ++ case S_FILES: ++ return "FILES"; ++ case S_INCLUDE: ++ return "INCLUDE"; ++ case S_MEMORY: ++ return "MEMORY"; ++ case S_MISC: ++ return "MISC"; ++ case S_SQL: ++ return "SQL"; ++ case S_EXECUTOR: ++ return "EXECUTOR"; ++ case S_VARS: ++ return "VARS"; ++ default: ++ return "UNKNOWN"; ++ } ++} ++ ++PHPAPI void php_security_log(int loglevel, char *fmt, ...) ++{ ++#if defined(AF_UNIX) ++ int s, r, i=0; ++ struct sockaddr_un saun; ++ char buf[4096+64]; ++ char error[4096+100]; ++ char *ip_address; ++ char *fname; ++ int lineno; ++ va_list ap; ++ TSRMLS_FETCH(); ++ ++ if (EG(hphp_log_use_x_forwarded_for)) { ++ ip_address = sapi_getenv("HTTP_X_FORWARDED_FOR", 20 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "X-FORWARDED-FOR not set"; ++ } ++ } else { ++ ip_address = sapi_getenv("REMOTE_ADDR", 11 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "REMOTE_ADDR not set"; ++ } ++ } ++ ++ ++ va_start(ap, fmt); ++ ap_php_vsnprintf(error, sizeof(error), fmt, ap); ++ va_end(ap); ++ while (error[i]) { ++ if (error[i] < 32) error[i] = '.'; ++ i++; ++ } ++ ++ if (zend_is_executing(TSRMLS_C)) { ++ lineno = zend_get_executed_lineno(TSRMLS_C); ++ fname = zend_get_executed_filename(TSRMLS_C); ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s', line %u)", error, ip_address, fname, lineno); ++ } else { ++ fname = sapi_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC); ++ if (fname==NULL) { ++ fname = "unknown"; ++ } ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s')", error, ip_address, fname); ++ } ++ ++ /* Syslog-Logging disabled? */ ++ if ((EG(hphp_log_syslog) & loglevel)==0) { ++ goto log_sapi; ++ } ++ ++ ap_php_snprintf(error, sizeof(error), "<%u>hphp[%u]: %s\n", EG(hphp_log_syslog_facility)|EG(hphp_log_syslog_priority),getpid(),buf); ++ ++ s = socket(AF_UNIX, SOCK_DGRAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ s = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ goto log_sapi; ++ } ++ } ++ send(s, error, strlen(error), 0); ++ ++ close(s); ++ ++log_sapi: ++ /* SAPI Logging activated? */ ++ if ((EG(hphp_log_syslog) & loglevel)!=0) { ++ sapi_module.log_message(buf); ++ } ++ ++log_script: ++ /* script logging activaed? */ ++ if (((EG(hphp_log_script) & loglevel)!=0) && EG(hphp_log_scriptname)!=NULL) { ++ char cmd[8192], *cmdpos, *bufpos; ++ FILE *in; ++ int space; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s \'", EG(hphp_log_scriptname), loglevel2string(loglevel)); ++ space = sizeof(cmd) - strlen(cmd); ++ cmdpos = cmd + strlen(cmd); ++ bufpos = buf; ++ if (space <= 1) return; ++ while (space > 2 && *bufpos) { ++ if (*bufpos == '\'') { ++ if (space<=5) break; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\\'; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\''; ++ bufpos++; ++ space-=4; ++ } else { ++ *cmdpos++ = *bufpos++; ++ space--; ++ } ++ } ++ *cmdpos++ = '\''; ++ *cmdpos = 0; ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ return; ++ } ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ } ++ pclose(in); ++ } ++ ++#endif ++} ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++PHPAPI unsigned int php_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++ ++PHPAPI int php_is_valid_include(zval *z) ++{ ++ char *filename; ++ int len, i; ++ TSRMLS_FETCH(); ++ ++ /* must be of type string */ ++ if (z->type != IS_STRING || z->value.str.val == NULL) { ++ return (0); ++ } ++ ++ /* short cut */ ++ filename = z->value.str.val; ++ len = z->value.str.len; ++ ++ /* 1. must be shorter than MAXPATHLEN */ ++ if (len > MAXPATHLEN) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') longer than MAXPATHLEN chars", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 2. must not be cutted */ ++ if (len != strlen(filename)) { ++ char *fname = estrndup(filename, len); ++ for (i=0; fname[i]; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename truncated by a \\0 after '%s'", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 3. must not be a URL */ ++ if (strstr(filename, "://")) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') is an URL", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 4. must not be an uploaded file */ ++ if (SG(rfc1867_uploaded_files)) { ++ if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, len+1)) { ++ php_security_log(S_INCLUDE, "Include filename is an uploaded file"); ++ return (0); ++ } ++ } ++ ++ /* passed all tests */ ++ return (1); ++} ++ ++#endif ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Naur php-5.0.4/main/hardening_patch.h hardening-patch-5.0.4-0.3.2/main/hardening_patch.h +--- php-5.0.4/main/hardening_patch.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/main/hardening_patch.h 2005-07-09 08:47:01.529234504 +0200 +@@ -0,0 +1,46 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENING_PATCH_H ++#define HARDENING_PATCH_H ++ ++#include "zend.h" ++ ++#if HARDENING_PATCH ++PHPAPI void php_security_log(int loglevel, char *fmt, ...); ++PHPAPI void hardened_startup(); ++#define HARDENING_PATCH_VERSION "0.3.2" ++ ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++PHPAPI unsigned int php_canary(); ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++PHPAPI int php_is_valid_include(zval *z); ++#endif ++ ++#endif /* HARDENING_PATCH_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Naur php-5.0.4/main/hardening_patch.m4 hardening-patch-5.0.4-0.3.2/main/hardening_patch.m4 +--- php-5.0.4/main/hardening_patch.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/main/hardening_patch.m4 2005-06-26 21:42:36.000000000 +0200 +@@ -0,0 +1,95 @@ ++dnl ++dnl $Id: hardening_patch.m4,v 1.1 2004/11/14 13:24:24 ionic Exp $ ++dnl ++dnl This file contains Hardening Patch for PHP specific autoconf functions. ++dnl ++ ++AC_ARG_ENABLE(hardening-patch-mm-protect, ++[ --disable-hardening-patch-mm-protect Disable the Memory Manager protection.],[ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-ll-protect, ++[ --disable-hardening-patch-ll-protect Disable the Linked List protection.],[ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-inc-protect, ++[ --disable-hardening-patch-inc-protect Disable include/require protection.],[ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-fmt-protect, ++[ --disable-hardening-patch-fmt-protect Disable format string protection.],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-hash-protect, ++[ --disable-hardening-patch-hash-protect Disable HashTable destructor protection.],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++]) ++ ++AC_MSG_CHECKING(whether to protect the Zend Memory Manager) ++AC_MSG_RESULT($DO_HARDENING_PATCH_MM_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the Zend Linked Lists) ++AC_MSG_RESULT($DO_HARDENING_PATCH_LL_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect include/require statements) ++AC_MSG_RESULT($DO_HARDENING_PATCH_INC_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect PHP Format String functions) ++AC_MSG_RESULT($DO_HARDENING_PATCH_FMT_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the destructor of Zend HashTables) ++AC_MSG_RESULT($DO_HARDENING_PATCH_HASH_PROTECT) ++ ++ ++AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 1, [Memory Manager Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 0, [Memory Manager Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 1, [Linked List Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 0, [Linked List Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 1, [Include/Require Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 0, [Include/Require Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 1, [Fmt String Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 0, [Fmt String Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 1, [HashTable DTOR Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 0, [HashTable DTOR Protection]) ++fi ++ +diff -Naur php-5.0.4/main/main.c hardening-patch-5.0.4-0.3.2/main/main.c +--- php-5.0.4/main/main.c 2005-03-24 02:11:35.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/main/main.c 2005-06-26 23:26:26.000000000 +0200 +@@ -92,6 +92,10 @@ + + #include "SAPI.h" + #include "rfc1867.h" ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#endif ++ + /* }}} */ + + #ifndef ZTS +@@ -116,10 +120,33 @@ + */ + static PHP_INI_MH(OnChangeMemoryLimit) + { ++#if HARDENING_PATCH ++ long orig_memory_limit; ++ ++ if (entry->modified) { ++ orig_memory_limit = zend_atoi(entry->orig_value, entry->orig_value_length); ++ } else { ++ orig_memory_limit = 1<<30; ++ } ++ if (orig_memory_limit < 0 || orig_memory_limit > (1<<30)) { ++ orig_memory_limit = 1<<30; ++ } ++#endif + if (new_value) { + PG(memory_limit) = zend_atoi(new_value, new_value_length); ++#if HARDENING_PATCH ++ if (PG(memory_limit) > orig_memory_limit) { ++ PG(memory_limit) = orig_memory_limit; ++ php_security_log(S_MISC, "script tried to increase memory_limit above allowed value"); ++ return FAILURE; ++ } ++#endif + } else { ++#if HARDENING_PATCH ++ PG(memory_limit) = orig_memory_limit; ++#else + PG(memory_limit) = 1<<30; /* effectively, no limit */ ++#endif + } + return zend_set_memory_limit(PG(memory_limit)); + } +@@ -1313,6 +1340,10 @@ + tsrm_ls = ts_resource(0); + #endif + ++#if HARDENING_PATCH ++ hardened_startup(); ++#endif ++ + module_shutdown = 0; + module_startup = 1; + sapi_initialize_empty_request(TSRMLS_C); +@@ -1326,6 +1357,12 @@ + + php_output_startup(); + ++#if HARDENING_PATCH_INC_PROTECT ++ zuf.is_valid_include = php_is_valid_include; ++#endif ++#if HARDENING_PATCH ++ zuf.security_log_function = php_security_log; ++#endif + zuf.error_function = php_error_cb; + zuf.printf_function = php_printf; + zuf.write_function = php_body_write_wrapper; +@@ -1429,6 +1466,10 @@ + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, sizeof(PHP_CONFIG_FILE_PATH)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("HARDENING_PATCH", 1, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_STRINGL_CONSTANT("HARDENING_PATCH_VERSION", HARDENING_PATCH_VERSION, sizeof(HARDENING_PATCH_VERSION)-1, CONST_PERSISTENT | CONST_CS); ++#endif + REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS); + php_output_register_constants(TSRMLS_C); + php_rfc1867_register_constants(TSRMLS_C); +diff -Naur php-5.0.4/main/php_config.h.in hardening-patch-5.0.4-0.3.2/main/php_config.h.in +--- php-5.0.4/main/php_config.h.in 2005-04-03 11:42:53.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/main/php_config.h.in 2005-06-26 22:25:22.000000000 +0200 +@@ -746,6 +746,39 @@ + /* hardcode for each of the cross compiler host */ + #undef PHP_UNAME + ++/* Hardening-Patch for PHP */ ++#undef HARDENING_PATCH ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ + /* Whether you have AOLserver */ + #undef HAVE_AOLSERVER + +@@ -1077,6 +1110,12 @@ + /* Define if you have the getaddrinfo function */ + #undef HAVE_GETADDRINFO + ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ + /* Whether system headers declare timezone */ + #undef HAVE_DECLARED_TIMEZONE + +diff -Naur php-5.0.4/main/php.h hardening-patch-5.0.4-0.3.2/main/php.h +--- php-5.0.4/main/php.h 2005-03-14 10:41:39.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/main/php.h 2005-06-28 14:49:57.000000000 +0200 +@@ -26,7 +26,7 @@ + #include + #endif + +-#define PHP_API_VERSION 20031224 ++#define PHP_API_VERSION 1020050627 + #define PHP_HAVE_STREAMS + #define YYDEBUG 0 + +@@ -35,11 +35,19 @@ + #include "zend_qsort.h" + #include "php_compat.h" + ++ + #include "zend_API.h" + + #undef sprintf + #define sprintf php_sprintf + ++#if HARDENING_PATCH ++#if HAVE_REALPATH ++#undef realpath ++#define realpath php_realpath ++#endif ++#endif ++ + /* PHP's DEBUG value must match Zend's ZEND_DEBUG value */ + #undef PHP_DEBUG + #define PHP_DEBUG ZEND_DEBUG +@@ -341,6 +349,7 @@ + #define PHP_FUNCTION ZEND_FUNCTION + #define PHP_METHOD ZEND_METHOD + ++#define PHP_STATIC_FE ZEND_STATIC_FE + #define PHP_NAMED_FE ZEND_NAMED_FE + #define PHP_FE ZEND_FE + #define PHP_FALIAS ZEND_FALIAS +@@ -446,6 +455,10 @@ + #endif + #endif /* !XtOffsetOf */ + ++#if HARDENING_PATCH ++#include "hardening_patch.h" ++#endif ++ + #endif + + /* +diff -Naur php-5.0.4/main/php_variables.c hardening-patch-5.0.4-0.3.2/main/php_variables.c +--- php-5.0.4/main/php_variables.c 2005-02-17 05:46:10.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/main/php_variables.c 2005-06-27 01:01:54.000000000 +0200 +@@ -493,7 +493,7 @@ + */ + static inline void php_register_server_variables(TSRMLS_D) + { +- zval *array_ptr=NULL; ++ zval *array_ptr=NULL, *vptr; + /* turn off magic_quotes while importing server variables */ + int magic_quotes_gpc = PG(magic_quotes_gpc); + +@@ -506,6 +506,16 @@ + /* Server variables */ + if (sapi_module.register_server_variables) { + sapi_module.register_server_variables(array_ptr TSRMLS_CC); ++ if (zend_hash_find(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA"), (void **)&vptr)==SUCCESS) { ++ char *str; ++ if (vptr->type != IS_STRING) { ++ str = "Array"; ++ } else { ++ str = vptr->value.str.val; ++ } ++ php_security_log(S_VARS, "Attacker tried to overwrite HTTP_RAW_POST_DATA with '%s' through a HTTP header", str); ++ zend_hash_del(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA")); ++ } + } + + /* PHP Authentication support */ +diff -Naur php-5.0.4/main/rfc1867.c hardening-patch-5.0.4-0.3.2/main/rfc1867.c +--- php-5.0.4/main/rfc1867.c 2005-02-15 01:26:35.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/main/rfc1867.c 2005-06-26 23:13:12.000000000 +0200 +@@ -131,6 +131,7 @@ + #define UPLOAD_ERROR_C 3 /* Partially uploaded */ + #define UPLOAD_ERROR_D 4 /* No file uploaded */ + #define UPLOAD_ERROR_E 6 /* Missing /tmp or similar directory */ ++#define UPLOAD_ERROR_F 7 /* Filter forbids upload */ + + void php_rfc1867_register_constants(TSRMLS_D) + { +@@ -140,6 +141,7 @@ + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL", UPLOAD_ERROR_C, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE", UPLOAD_ERROR_D, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FILTER", UPLOAD_ERROR_F, CONST_CS | CONST_PERSISTENT); + } + + static void normalize_protected_variable(char *varname TSRMLS_DC) +@@ -849,6 +851,7 @@ + char buff[FILLUNIT]; + char *cd=NULL,*param=NULL,*filename=NULL, *tmp=NULL; + int blen=0, wlen=0; ++ unsigned long offset; + + zend_llist_clean(&header); + +@@ -988,6 +991,11 @@ + cancel_upload = UPLOAD_ERROR_D; + } + ++ if (sapi_module.pre_upload_filter && sapi_module.pre_upload_filter(param, filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ ++ offset = 0; + while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff) TSRMLS_CC))) + { + if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize)) { +@@ -1001,6 +1009,11 @@ + #endif + cancel_upload = UPLOAD_ERROR_B; + } else if (blen > 0) { ++ ++ if (sapi_module.upload_content_filter && sapi_module.upload_content_filter(offset, buff, blen, &blen TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ + wlen = fwrite(buff, 1, blen, fp); + + if (wlen < blen) { +@@ -1024,6 +1037,10 @@ + } + #endif + ++ if (!cancel_upload && sapi_module.post_upload_filter && sapi_module.post_upload_filter(temp_filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ + if (cancel_upload) { + if (temp_filename) { + if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */ +diff -Naur php-5.0.4/main/SAPI.c hardening-patch-5.0.4-0.3.2/main/SAPI.c +--- php-5.0.4/main/SAPI.c 2005-02-22 15:46:15.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/main/SAPI.c 2005-06-26 23:18:17.000000000 +0200 +@@ -821,6 +821,30 @@ + zend_hash_del(&known_post_content_types, post_entry->content_type, post_entry->content_type_len+1); + } + ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) ++{ ++ sapi_module.input_filter = input_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)) ++{ ++ sapi_module.pre_upload_filter = pre_upload_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)) ++{ ++ sapi_module.upload_content_filter = upload_content_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)) ++{ ++ sapi_module.post_upload_filter = post_upload_filter; ++ return SUCCESS; ++} ++ + + SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D)) + { +@@ -835,11 +859,6 @@ + return SUCCESS; + } + +-SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) +-{ +- sapi_module.input_filter = input_filter; +- return SUCCESS; +-} + + SAPI_API int sapi_flush(TSRMLS_D) + { +diff -Naur php-5.0.4/main/SAPI.h hardening-patch-5.0.4-0.3.2/main/SAPI.h +--- php-5.0.4/main/SAPI.h 2004-01-08 18:33:04.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/main/SAPI.h 2005-06-26 23:16:27.000000000 +0200 +@@ -103,9 +103,10 @@ + char *current_user; + int current_user_length; + +- /* this is necessary for CLI module */ +- int argc; +- char **argv; ++ /* this is necessary for CLI module */ ++ int argc; ++ char **argv; ++ + } sapi_request_info; + + +@@ -183,6 +184,10 @@ + SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC)); + SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)); + ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)); ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)); ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)); ++ + SAPI_API int sapi_flush(TSRMLS_D); + SAPI_API struct stat *sapi_get_stat(TSRMLS_D); + SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC); +@@ -245,6 +250,10 @@ + int (*get_target_gid)(gid_t * TSRMLS_DC); + + unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); ++ ++ unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC); ++ unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC); ++ unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC); + + void (*ini_defaults)(HashTable *configuration_hash); + int phpinfo_as_text; +@@ -270,7 +279,11 @@ + + #define SAPI_DEFAULT_MIMETYPE "text/html" + #define SAPI_DEFAULT_CHARSET "" ++#if HARDENING_PATCH ++#define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION " with Hardening-Patch" ++#else + #define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION ++#endif + + #define SAPI_POST_READER_FUNC(post_reader) void post_reader(TSRMLS_D) + #define SAPI_POST_HANDLER_FUNC(post_handler) void post_handler(char *content_type_dup, void *arg TSRMLS_DC) +@@ -278,6 +291,10 @@ + #define SAPI_TREAT_DATA_FUNC(treat_data) void treat_data(int arg, char *str, zval* destArray TSRMLS_DC) + #define SAPI_INPUT_FILTER_FUNC(input_filter) unsigned int input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) + ++#define SAPI_PRE_UPLOAD_FILTER_FUNC(pre_upload_filter) unsigned int pre_upload_filter(char *varname, char *filename TSRMLS_DC) ++#define SAPI_UPLOAD_CONTENT_FILTER_FUNC(upload_content_filter) unsigned int upload_content_filter(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC) ++#define SAPI_POST_UPLOAD_FILTER_FUNC(post_upload_filter) unsigned int post_upload_filter(char *tmpfilename TSRMLS_DC) ++ + BEGIN_EXTERN_C() + SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data); + SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader); +diff -Naur php-5.0.4/main/snprintf.c hardening-patch-5.0.4-0.3.2/main/snprintf.c +--- php-5.0.4/main/snprintf.c 2004-11-16 00:14:40.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/main/snprintf.c 2005-06-26 22:07:19.000000000 +0200 +@@ -1013,7 +1013,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Naur php-5.0.4/main/spprintf.c hardening-patch-5.0.4-0.3.2/main/spprintf.c +--- php-5.0.4/main/spprintf.c 2004-04-16 01:04:49.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/main/spprintf.c 2005-06-26 22:03:49.000000000 +0200 +@@ -630,7 +630,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = xbuf->len; ++#endif + break; + + /* +diff -Naur php-5.0.4/pear/go-pear-list.php hardening-patch-5.0.4-0.3.2/pear/go-pear-list.php +--- php-5.0.4/pear/go-pear-list.php 2005-03-18 02:59:00.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/pear/go-pear-list.php 2005-07-02 00:15:21.000000000 +0200 +@@ -8,7 +8,7 @@ + $packages = array( + // required packages for the installer + "PEAR" => "1.3.5", +-"XML_RPC" => "1.2.2", ++"XML_RPC" => "1.3.1", + "Console_Getopt" => "1.2", + "Archive_Tar" => "1.3.1", + +diff -Naur php-5.0.4/pear/packages/XML_RPC-1.2.2.tar hardening-patch-5.0.4-0.3.2/pear/packages/XML_RPC-1.2.2.tar +--- php-5.0.4/pear/packages/XML_RPC-1.2.2.tar 2005-03-28 19:05:50.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/pear/packages/XML_RPC-1.2.2.tar 1970-01-01 01:00:00.000000000 +0100 +@@ -1,3393 +0,0 @@ +-package2.xml100666 0 0 24326 10213112551 6327 +- +- XML_RPC +- pear.php.net +- PHP implementation of the XML-RPC protocol +- A PEAR-ified version of Useful Inc's XML-RPC for PHP. +- +-It has support for HTTP/HTTPS transport, proxies and authentication. +- +- Stig Bakken +- ssb +- stig@php.net +- no +- +- +- Daniel Convissor +- danielc +- danielc@php.net +- yes +- +- 2005-03-07 +- +- +- 1.2.2 +- 1.2.0 +- +- +- stable +- stable +- +- PHP License +- * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- PEAR +- pear.php.net +- 1.4.0a1 +- 1.4.0a4 +- +- +- +- +- 4.2.0 +- 6.0.0 +- +- +- 1.4.0a1 +- +- +- +- +- +- +- +- 1.2.1 +- 1.2.0 +- +- +- stable +- stable +- +- 2005-03-01 +- PHP License +- * Add isset() check before examining the dispatch map. Bug 3658. +- +- +- +- 1.2.0 +- 1.2.0 +- +- +- stable +- stable +- +- 2005-02-27 +- PHP License +- * Provide the "stable" release. +-* Add package2.xml for compatibility with PEAR 1.4.0. +-* For changes since 1.1.0, see the changelogs for the various RC releases. +- +- +- +- 1.2.0RC7 +- 1.2.0RC7 +- +- +- beta +- beta +- +- 2005-02-22 +- PHP License +- * Add the setSendEncoding() method and $send_encoding +- property to XML_RPC_Message. Request 3537. +-* Allow class methods to be mapped using either syntax: +- 'function' => 'hello::sayHello', +- or +- 'function' => array('hello', 'sayhello'), +- Bug 3363. +-* Use 8192 instead of 32768 for bytes in fread() +- in parseResponseFile(). Bug 3340. +- +- +- +- 1.2.0RC6 +- 1.2.0RC6 +- +- +- beta +- beta +- +- 2005-01-25 +- PHP License +- * Don't put the protocol in the Host field of the POST data. (danielc) +- +- +- +- 1.2.0RC5 +- 1.2.0RC5 +- +- +- beta +- beta +- +- 2005-01-24 +- PHP License +- * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. +- +- +- +- 1.2.0RC4 +- 1.2.0RC4 +- +- +- beta +- beta +- +- 2005-01-24 +- PHP License +- * When a connection attempt fails, have the method return 0. (danielc) +-* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) +-* Add tests for setting the client properties. (danielc) +-* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) +-* Bundle the tests with the package. (danielc) +- +- +- +- 1.2.0RC3 +- 1.2.0RC3 +- +- +- beta +- beta +- +- 2005-01-19 +- PHP License +- * ssl uses port 443, not 445. +- +- +- +- 1.2.0RC2 +- 1.2.0RC2 +- +- +- beta +- beta +- +- 2005-01-11 +- PHP License +- * Handle ssl:// in the $server string. (danielc) +-* Also default to port 445 for ssl:// requests as well. (danielc) +-* Enhance debugging in the server. (danielc) +- +- +- +- 1.2.0RC1 +- 1.2.0RC1 +- +- +- beta +- beta +- +- 2004-12-30 +- PHP License +- * Make things work with SSL. Bug 2489. (nkukard lbsd net) +-* Allow array function callbacks (Matt Kane) +-* Some minor speed-ups (Matt Kane) +-* Add Dump.php to the package (Christian Weiske) +-* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) +-* Silence fsockopen() errors. Bug 1714. (danielc) +-* Encode empty arrays as an array. Bug 1493. (danielc) +-* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) +-* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) +-* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) +-* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) +-* Allow raiseError() to be called statically. (danielc) +-* Stop double escaping of character entities. Bug 987. (danielc) +- NOTICE: the following have been removed: +- * XML_RPC_dh() +- * $GLOBALS['XML_RPC_entities'] +- * XML_RPC_entity_decode() +- * XML_RPC_lookup_entity() +-* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) +- +- +- +- 1.1.0 +- 1.1.0 +- +- +- stable +- stable +- +- 2004-03-15 +- PHP License +- * Added support for sequential arrays to XML_RPC_encode() (mroch) +-* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) +-* Remove "require_once 'PEAR.php'", include only when needed to raise an error +-* Replace echo and error_log() with raiseError() (mroch) +-* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) +-* be tolerant of junk after methodResponse (Luca Mariano, mroch) +-* Silent notice even in the error log (pierre) +-* fix include of shared xml extension on win32 (pierre) +- +- +- +- 1.0.4 +- 1.0.4 +- +- +- stable +- stable +- +- 2002-10-02 +- PHP License +- * added HTTP proxy authorization support (thanks to Arnaud Limbourg) +- +- +- +- 1.0.3 +- 1.0.3 +- +- +- stable +- stable +- +- 2002-05-19 +- PHP License +- * fix bug when parsing responses with boolean types +- +- +- +- 1.0.2 +- 1.0.2 +- +- +- stable +- stable +- +- 2002-04-16 +- PHP License +- * E_ALL fixes +-* fix HTTP response header parsing +- +- +- +- 1.0.1 +- 1.0.1 +- +- +- stable +- stable +- +- 2001-09-25 +- PHP License +- This is a PEAR-ified version of Useful Inc's 1.0.1 release. +-Includes an urgent security fix identified by Dan Libby <dan@libby.com>. +- +- +-XML_RPC-1.2.2/tests/protoport.php100666 0 0 25543 10213112550 11656 +- * @copyright 2005 The PHP Group +- * @license http://www.php.net/license/3_0.txt PHP License +- * @version CVS: $Id: protoport.php,v 1.4 2005/01/24 17:48:47 danielc Exp $ +- * @link http://pear.php.net/package/XML_RPC +- * @since File available since Release 1.2 +- */ +- +-/* +- * If the package version number is found in the left hand +- * portion of the if() expression below, that means this file has +- * come from the PEAR installer. Therefore, let's test the +- * installed version of XML_RPC which should be in the include path. +- * +- * If the version has not been substituted in the if() expression, +- * this file has likely come from a CVS checkout or a .tar file. +- * Therefore, we'll assume the tests should use the version of +- * XML_RPC that has come from there as well. +- */ +-if ('1.2.2' != '@'.'package_version'.'@') { +- /** +- * Get the needed class from the PEAR installation +- */ +- require_once 'XML/RPC.php'; +-} else { +- /** +- * Get the needed class from the parent directory +- */ +- require_once '../RPC.php'; +-} +- +-/** +- * Compare the test result to the expected result +- * +- * If the test fails, echo out the results. +- * +- * @param array $expect the array of object properties you expect +- * from the test +- * @param object $actual the object results from the test +- * @param string $test_name the name of the test +- * +- * @return void +- */ +-function compare($expect, $actual, $test_name) { +- $actual = get_object_vars($actual); +- if (count(array_diff($actual, $expect))) { +- echo "$test_name failed.\nExpect: "; +- print_r($expect); +- echo "Actual: "; +- print_r($actual); +- echo "\n"; +- } +-} +- +-if (php_sapi_name() != 'cli') { +- echo "
\n";
+-}
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver');
+-compare($x, $c, 'defaults');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver');
+-compare($x, $c, 'defaults with http');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver');
+-compare($x, $c, 'defaults with https');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver');
+-compare($x, $c, 'defaults with ssl');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 65);
+-compare($x, $c, 'port 65');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 65);
+-compare($x, $c, 'port 65 with http');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 65);
+-compare($x, $c, 'port 65 with https');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65);
+-compare($x, $c, 'port 65 with ssl');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 0,
+-                        'theproxy');
+-compare($x, $c, 'defaults proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 0,
+-                        'http://theproxy');
+-compare($x, $c, 'defaults with http proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 0,
+-                        'https://theproxy');
+-compare($x, $c, 'defaults with https proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 0,
+-                        'ssl://theproxy');
+-compare($x, $c, 'defaults with ssl proxy');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 65,
+-                        'theproxy', 6565);
+-compare($x, $c, 'port 65 proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 65,
+-                        'http://theproxy', 6565);
+-compare($x, $c, 'port 65 with http proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 65,
+-                        'https://theproxy', 6565);
+-compare($x, $c, 'port 65 with https proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65,
+-                        'ssl://theproxy', 6565);
+-compare($x, $c, 'port 65 with ssl proxy 6565');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 443,
+-                        'theproxy', 443);
+-compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 0,
+-                        'ssl://theproxy', 6565);
+-compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
+-XML_RPC-1.2.2/tests/test_Dump.php100666      0      0        3042 10213112550  11520 new XML_RPC_Value('das ist der Titel', 'string'),
+-    'startDate'=>new XML_RPC_Value(mktime(0,0,0,13,11,2004), 'dateTime.iso8601'),
+-    'endDate'  =>new XML_RPC_Value(mktime(0,0,0,15,11,2004), 'dateTime.iso8601'),
+-    'error'    =>'string',
+-    'arkey'    => new XML_RPC_Value( array(
+-        new XML_RPC_Value('simple string'),
+-        new XML_RPC_Value(12345, 'int')
+-        ), 'array')
+-    )
+-    ,'struct');
+-
+-XML_RPC_Dump($val);
+-
+-echo '==============' . "\r\n";
+-$val2 = new XML_RPC_Value(44353, 'int');
+-XML_RPC_Dump($val2);
+-
+-echo '==============' . "\r\n";
+-$val3 = new XML_RPC_Value('this should be a string', 'string');
+-XML_RPC_Dump($val3);
+-
+-echo '==============' . "\r\n";
+-$val4 = new XML_RPC_Value(true, 'boolean');
+-XML_RPC_Dump($val4);
+-XML_RPC-1.2.2/Dump.php100666      0      0       12074 10213112550   7344 
+- * @version    CVS: $Id: Dump.php,v 1.7 2005/01/24 03:47:55 danielc Exp $
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-
+-
+-/**
+- * Pull in the XML_RPC class
+- */
+-require_once 'XML/RPC.php';
+-
+-
+-/**
+- * Generates the dump of the XML_RPC_Value and echoes it
+- *
+- * @param object $value  the XML_RPC_Value object to dump
+- *
+- * @return void
+- */
+-function XML_RPC_Dump($value)
+-{
+-    $dumper = new XML_RPC_Dump();
+-    echo $dumper->generateDump($value);
+-}
+-
+-
+-/**
+- * Class which generates a dump of a XML_RPC_Value object
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Christian Weiske 
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Dump
+-{
+-    /**
+-     * The indentation array cache
+-     * @var array
+-     */
+-    var $arIndent      = array();
+-
+-    /**
+-     * The spaces used for indenting the XML
+-     * @var string
+-     */
+-    var $strBaseIndent = '    ';
+-
+-    /**
+-     * Returns the dump in XML format without printing it out
+-     *
+-     * @param object $value   the XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  the dump
+-     */
+-    function generateDump($value, $nLevel = 0)
+-    {
+-        if (!is_object($value) && get_class($value) != 'xml_rpc_value') {
+-            require_once 'PEAR.php';
+-            PEAR::raiseError('Tried to dump non-XML_RPC_Value variable' . "\r\n",
+-                             0, PEAR_ERROR_PRINT);
+-            if (is_object($value)) {
+-                $strType = get_class($value);
+-            } else {
+-                $strType = gettype($value);
+-            }
+-            return $this->getIndent($nLevel) . 'NOT A XML_RPC_Value: '
+-                   . $strType . "\r\n";
+-        }
+-
+-        switch ($value->kindOf()) {
+-        case 'struct':
+-            $ret = $this->genStruct($value, $nLevel);
+-            break;
+-        case 'array':
+-            $ret = $this->genArray($value, $nLevel);
+-            break;
+-        case 'scalar':
+-            $ret = $this->genScalar($value->scalarval(), $nLevel);
+-            break;
+-        default:
+-            require_once 'PEAR.php';
+-            PEAR::raiseError('Illegal type "' . $value->kindOf()
+-                             . '" in XML_RPC_Value' . "\r\n", 0,
+-                             PEAR_ERROR_PRINT);
+-        }
+-
+-        return $ret;
+-    }
+-
+-    /**
+-     * Returns the scalar value dump
+-     *
+-     * @param object $value   the scalar XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genScalar($value, $nLevel)
+-    {
+-        if (gettype($value) == 'object') {
+-            $strClass = ' ' . get_class($value);
+-        } else {
+-            $strClass = '';
+-        }
+-        return $this->getIndent($nLevel) . gettype($value) . $strClass
+-               . ' ' . $value . "\r\n";
+-    }
+-
+-    /**
+-     * Returns the dump of a struct
+-     *
+-     * @param object $value   the struct XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genStruct($value, $nLevel)
+-    {
+-        $value->structreset();
+-        $strOutput = $this->getIndent($nLevel) . 'struct' . "\r\n";
+-        while (list($key, $keyval) = $value->structeach()) {
+-            $strOutput .= $this->getIndent($nLevel + 1) . $key . "\r\n";
+-            $strOutput .= $this->generateDump($keyval, $nLevel + 2);
+-        }
+-        return $strOutput;
+-    }
+-
+-    /**
+-     * Returns the dump of an array
+-     *
+-     * @param object $value   the array XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genArray($value, $nLevel)
+-    {
+-        $nSize     = $value->arraysize();
+-        $strOutput = $this->getIndent($nLevel) . 'array' . "\r\n";
+-        for($nA = 0; $nA < $nSize; $nA++) {
+-            $strOutput .= $this->getIndent($nLevel + 1) . $nA . "\r\n";
+-            $strOutput .= $this->generateDump($value->arraymem($nA),
+-                                              $nLevel + 2);
+-        }
+-        return $strOutput;
+-    }
+-
+-    /**
+-     * Returns the indent for a specific level and caches it for faster use
+-     *
+-     * @param int $nLevel  the level
+-     *
+-     * @return string  the indented string
+-     */
+-    function getIndent($nLevel)
+-    {
+-        if (!isset($this->arIndent[$nLevel])) {
+-            $this->arIndent[$nLevel] = str_repeat($this->strBaseIndent, $nLevel);
+-        }
+-        return $this->arIndent[$nLevel];
+-    }
+-}
+-
+-/*
+- * Local variables:
+- * tab-width: 4
+- * c-basic-offset: 4
+- * c-hanging-comment-ender-p: nil
+- * End:
+- */
+-
+-?>
+-XML_RPC-1.2.2/RPC.php100666      0      0      141000 10213112550   7073 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    CVS: $Id: RPC.php,v 1.60 2005/03/07 17:45:08 danielc Exp $
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-
+-
+-if (!function_exists('xml_parser_create')) {
+-    // Win 32 fix. From: "Leo West" 
+-    if ($WINDIR) {
+-        dl('php_xml.dll');
+-    } else {
+-        dl('xml.so');
+-    }
+-}
+-
+-/**#@+
+- * Error constants
+- */
+-define('XML_RPC_ERROR_INVALID_TYPE',        101);
+-define('XML_RPC_ERROR_NON_NUMERIC_FOUND',   102);
+-define('XML_RPC_ERROR_CONNECTION_FAILED',   103);
+-define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
+-/**#@-*/
+-
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_I4']
+- */
+-$GLOBALS['XML_RPC_I4'] = 'i4';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Int']
+- */
+-$GLOBALS['XML_RPC_Int'] = 'int';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Boolean']
+- */
+-$GLOBALS['XML_RPC_Boolean'] = 'boolean';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Double']
+- */
+-$GLOBALS['XML_RPC_Double'] = 'double';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_String']
+- */
+-$GLOBALS['XML_RPC_String'] = 'string';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_DateTime']
+- */
+-$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Base64']
+- */
+-$GLOBALS['XML_RPC_Base64'] = 'base64';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Array']
+- */
+-$GLOBALS['XML_RPC_Array'] = 'array';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Struct']
+- */
+-$GLOBALS['XML_RPC_Struct'] = 'struct';
+-
+-
+-/**
+- * Data type meta-types
+- * @global array $GLOBALS['XML_RPC_Types']
+- */
+-$GLOBALS['XML_RPC_Types'] = array(
+-    $GLOBALS['XML_RPC_I4']       => 1,
+-    $GLOBALS['XML_RPC_Int']      => 1,
+-    $GLOBALS['XML_RPC_Boolean']  => 1,
+-    $GLOBALS['XML_RPC_String']   => 1,
+-    $GLOBALS['XML_RPC_Double']   => 1,
+-    $GLOBALS['XML_RPC_DateTime'] => 1,
+-    $GLOBALS['XML_RPC_Base64']   => 1,
+-    $GLOBALS['XML_RPC_Array']    => 2,
+-    $GLOBALS['XML_RPC_Struct']   => 3,
+-);
+-
+-
+-/**
+- * Error message numbers
+- * @global array $GLOBALS['XML_RPC_err']
+- */
+-$GLOBALS['XML_RPC_err'] = array(
+-    'unknown_method'      => 1,
+-    'invalid_return'      => 2,
+-    'incorrect_params'    => 3,
+-    'introspect_unknown'  => 4,
+-    'http_error'          => 5,
+-);
+-
+-/**
+- * Error message strings
+- * @global array $GLOBALS['XML_RPC_str']
+- */
+-$GLOBALS['XML_RPC_str'] = array(
+-    'unknown_method'      => 'Unknown method',
+-    'invalid_return'      => 'Invalid return payload: enable debugging to examine incoming payload',
+-    'incorrect_params'    => 'Incorrect parameters passed to method',
+-    'introspect_unknown'  => 'Can\'t introspect: method unknown',
+-    'http_error'          => 'Didn\'t receive 200 OK from remote server.',
+-);
+-
+-
+-/**
+- * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
+- * @global string $GLOBALS['XML_RPC_defencoding']
+- */
+-$GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
+-
+-/**
+- * User error codes start at 800
+- * @global int $GLOBALS['XML_RPC_erruser']
+- */
+-$GLOBALS['XML_RPC_erruser'] = 800;
+-
+-/**
+- * XML parse error codes start at 100
+- * @global int $GLOBALS['XML_RPC_errxml']
+- */
+-$GLOBALS['XML_RPC_errxml'] = 100;
+-
+-
+-/**
+- * Compose backslashes for escaping regexp
+- * @global string $GLOBALS['XML_RPC_backslash']
+- */
+-$GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
+-
+-
+-/**
+- * Stores state during parsing
+- *
+- * quick explanation of components:
+- *   + st     = builds up a string for evaluation
+- *   + ac     = accumulates values
+- *   + qt     = decides if quotes are needed for evaluation
+- *   + cm     = denotes struct or array (comma needed)
+- *   + isf    = indicates a fault
+- *   + lv     = indicates "looking for a value": implements the logic
+- *               to allow values with no types to be strings
+- *   + params = stores parameters in method calls
+- *   + method = stores method name
+- *
+- * @global array $GLOBALS['XML_RPC_xh']
+- */
+-$GLOBALS['XML_RPC_xh'] = array();
+-
+-
+-/**
+- * Start element handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_se($parser, $name, $attrs)
+-{
+-    global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String;
+-
+-    switch ($name) {
+-    case 'STRUCT':
+-    case 'ARRAY':
+-        $XML_RPC_xh[$parser]['st'] .= 'array(';
+-        $XML_RPC_xh[$parser]['cm']++;
+-        // this last line turns quoting off
+-        // this means if we get an empty array we'll
+-        // simply get a bit of whitespace in the eval
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'NAME':
+-        $XML_RPC_xh[$parser]['st'] .= "'";
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        break;
+-
+-    case 'FAULT':
+-        $XML_RPC_xh[$parser]['isf'] = 1;
+-        break;
+-
+-    case 'PARAM':
+-        $XML_RPC_xh[$parser]['st'] = '';
+-        break;
+-
+-    case 'VALUE':
+-        $XML_RPC_xh[$parser]['st'] .= 'new XML_RPC_Value(';
+-        $XML_RPC_xh[$parser]['lv'] = 1;
+-        $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        // look for a value: if this is still 1 by the
+-        // time we reach the first data segment then the type is string
+-        // by implication and we need to add in a quote
+-        break;
+-
+-    case 'I4':
+-    case 'INT':
+-    case 'STRING':
+-    case 'BOOLEAN':
+-    case 'DOUBLE':
+-    case 'DATETIME.ISO8601':
+-    case 'BASE64':
+-        $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
+-
+-        if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
+-            $XML_RPC_xh[$parser]['qt'] = 1;
+-
+-            if ($name == 'DATETIME.ISO8601') {
+-                $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
+-            }
+-
+-        } elseif ($name == 'BASE64') {
+-            $XML_RPC_xh[$parser]['qt'] = 2;
+-        } else {
+-            // No quoting is required here -- but
+-            // at the end of the element we must check
+-            // for data format errors.
+-            $XML_RPC_xh[$parser]['qt'] = 0;
+-        }
+-        break;
+-
+-    case 'MEMBER':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-    }
+-
+-    if ($name != 'VALUE') {
+-        $XML_RPC_xh[$parser]['lv'] = 0;
+-    }
+-}
+-
+-/**
+- * End element handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_ee($parser, $name)
+-{
+-    global $XML_RPC_xh, $XML_RPC_Types, $XML_RPC_String;
+-
+-    switch ($name) {
+-    case 'STRUCT':
+-    case 'ARRAY':
+-        if ($XML_RPC_xh[$parser]['cm']
+-            && substr($XML_RPC_xh[$parser]['st'], -1) == ',')
+-        {
+-            $XML_RPC_xh[$parser]['st'] = substr($XML_RPC_xh[$parser]['st'], 0, -1);
+-        }
+-
+-        $XML_RPC_xh[$parser]['st'] .= ')';
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-        $XML_RPC_xh[$parser]['cm']--;
+-        break;
+-
+-    case 'NAME':
+-        $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'] . "' => ";
+-        break;
+-
+-    case 'BOOLEAN':
+-        // special case here: we translate boolean 1 or 0 into PHP
+-        // constants true or false
+-        if ($XML_RPC_xh[$parser]['ac'] == '1') {
+-            $XML_RPC_xh[$parser]['ac'] = 'true';
+-        } else {
+-            $XML_RPC_xh[$parser]['ac'] = 'false';
+-        }
+-
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-        // Drop through intentionally.
+-
+-    case 'I4':
+-    case 'INT':
+-    case 'STRING':
+-    case 'DOUBLE':
+-    case 'DATETIME.ISO8601':
+-    case 'BASE64':
+-        if ($XML_RPC_xh[$parser]['qt'] == 1) {
+-            // we use double quotes rather than single so backslashification works OK
+-            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
+-        } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
+-            $XML_RPC_xh[$parser]['st'] .= "base64_decode('"
+-                                        . $XML_RPC_xh[$parser]['ac'] . "')";
+-        } elseif ($name == 'BOOLEAN') {
+-            $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
+-        } else {
+-            // we have an I4, INT or a DOUBLE
+-            // we must check that only 0123456789-. are characters here
+-            if (!ereg("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
+-                XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
+-                                         XML_RPC_ERROR_NON_NUMERIC_FOUND);
+-                $XML_RPC_xh[$parser]['st'] .= 'XML_RPC_ERROR_NON_NUMERIC_FOUND';
+-            } else {
+-                // it's ok, add it on
+-                $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
+-            }
+-        }
+-
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
+-        break;
+-
+-    case 'VALUE':
+-        // deal with a string value
+-        if (strlen($XML_RPC_xh[$parser]['ac']) > 0 &&
+-            $XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
+-
+-            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
+-        }
+-
+-        // This if () detects if no scalar was inside 
+-        // and pads an empty "".
+-        if ($XML_RPC_xh[$parser]['st'][strlen($XML_RPC_xh[$parser]['st'])-1] == '(') {
+-            $XML_RPC_xh[$parser]['st'] .= '""';
+-        }
+-        $XML_RPC_xh[$parser]['st'] .= ", '" . $XML_RPC_xh[$parser]['vt'] . "')";
+-        if ($XML_RPC_xh[$parser]['cm']) {
+-            $XML_RPC_xh[$parser]['st'] .= ',';
+-        }
+-        break;
+-
+-    case 'MEMBER':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'DATA':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'PARAM':
+-        $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['st'];
+-        break;
+-
+-    case 'METHODNAME':
+-        $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", '',
+-                                                      $XML_RPC_xh[$parser]['ac']);
+-        break;
+-
+-    case 'BOOLEAN':
+-        // special case here: we translate boolean 1 or 0 into PHP
+-        // constants true or false
+-        if ($XML_RPC_xh[$parser]['ac'] == '1') {
+-            $XML_RPC_xh[$parser]['ac'] = 'true';
+-        } else {
+-            $XML_RPC_xh[$parser]['ac'] = 'false';
+-        }
+-
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-    }
+-
+-    // if it's a valid type name, set the type
+-    if (isset($XML_RPC_Types[strtolower($name)])) {
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-    }
+-}
+-
+-/**
+- * Character data handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_cd($parser, $data)
+-{
+-    global $XML_RPC_xh, $XML_RPC_backslash;
+-
+-    if ($XML_RPC_xh[$parser]['lv'] != 3) {
+-        // "lookforvalue==3" means that we've found an entire value
+-        // and should discard any further character data
+-
+-        if ($XML_RPC_xh[$parser]['lv'] == 1) {
+-            // if we've found text and we're just in a  then
+-            // turn quoting on, as this will be a string
+-            $XML_RPC_xh[$parser]['qt'] = 1;
+-            // and say we've found a value
+-            $XML_RPC_xh[$parser]['lv'] = 2;
+-        }
+-
+-        // replace characters that eval would
+-        // do special things with
+-        if (!isset($XML_RPC_xh[$parser]['ac'])) {
+-            $XML_RPC_xh[$parser]['ac'] = '';
+-        }
+-        $XML_RPC_xh[$parser]['ac'] .= str_replace('$', '\$',
+-            str_replace('"', '\"', str_replace(chr(92),
+-            $XML_RPC_backslash, $data)));
+-    }
+-}
+-
+-/**
+- * Base class
+- *
+- * This class provides common functions for all of the XML_RPC classes.
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Base {
+-
+-    /**
+-     * PEAR Error handling
+-     *
+-     * @return object  PEAR_Error object
+-     */
+-    function raiseError($msg, $code)
+-    {
+-        include_once 'PEAR.php';
+-        if (is_object(@$this)) {
+-            return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
+-        } else {
+-            return PEAR::raiseError('XML_RPC: ' . $msg, $code);
+-        }
+-    }
+-
+-    /**
+-     * Tell whether something is a PEAR_Error object
+-     *
+-     * @param mixed $value  the item to check
+-     *
+-     * @return bool  whether $value is a PEAR_Error object or not
+-     *
+-     * @access public
+-     */
+-    function isError($value)
+-    {
+-        return is_a($value, 'PEAR_Error');
+-    }
+-}
+-
+-/**
+- *
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Client extends XML_RPC_Base {
+-
+-    /**
+-     * The path and name of the RPC server script you want the request to go to
+-     * @var string
+-     */
+-    var $path = '';
+-
+-    /**
+-     * The name of the remote server to connect to
+-     * @var string
+-     */
+-    var $server = '';
+-
+-    /**
+-     * The protocol to use in contacting the remote server
+-     * @var string
+-     */
+-    var $protocol = 'http://';
+-
+-    /**
+-     * The port for connecting to the remote server
+-     *
+-     * The default is 80 for http:// connections
+-     * and 443 for https:// and ssl:// connections.
+-     *
+-     * @var integer
+-     */
+-    var $port = 80;
+-
+-    /**
+-     * A user name for accessing the RPC server
+-     * @var string
+-     * @see XML_RPC_Client::setCredentials()
+-     */
+-    var $username = '';
+-
+-    /**
+-     * A password for accessing the RPC server
+-     * @var string
+-     * @see XML_RPC_Client::setCredentials()
+-     */
+-    var $password = '';
+-
+-    /**
+-     * The name of the proxy server to use, if any
+-     * @var string
+-     */
+-    var $proxy = '';
+-
+-    /**
+-     * The protocol to use in contacting the proxy server, if any
+-     * @var string
+-     */
+-    var $proxy_protocol = 'http://';
+-
+-    /**
+-     * The port for connecting to the proxy server
+-     *
+-     * The default is 8080 for http:// connections
+-     * and 443 for https:// and ssl:// connections.
+-     *
+-     * @var integer
+-     */
+-    var $proxy_port = 8080;
+-
+-    /**
+-     * A user name for accessing the proxy server
+-     * @var string
+-     */
+-    var $proxy_user = '';
+-
+-    /**
+-     * A password for accessing the proxy server
+-     * @var string
+-     */
+-    var $proxy_pass = '';
+-
+-    /**
+-     * The error number, if any
+-     * @var integer
+-     */
+-    var $errno = 0;
+-
+-    /**
+-     * The error message, if any
+-     * @var string
+-     */
+-    var $errstring = '';
+-
+-    /**
+-     * The current debug mode (1 = on, 0 = off)
+-     * @var integer
+-     */
+-    var $debug = 0;
+-
+-
+-    /**
+-     * Sets the object's properties
+-     *
+-     * @param string  $path        the path and name of the RPC server script
+-     *                              you want the request to go to
+-     * @param string  $server      the URL of the remote server to connect to.
+-     *                              If this parameter doesn't specify a
+-     *                              protocol and $port is 443, ssl:// is
+-     *                              assumed.
+-     * @param integer $port        a port for connecting to the remote server.
+-     *                              Defaults to 80 for http:// connections and
+-     *                              443 for https:// and ssl:// connections.
+-     * @param string  $proxy       the URL of the proxy server to use, if any.
+-     *                              If this parameter doesn't specify a
+-     *                              protocol and $port is 443, ssl:// is
+-     *                              assumed.
+-     * @param integer $proxy_port  a port for connecting to the remote server.
+-     *                              Defaults to 8080 for http:// connections and
+-     *                              443 for https:// and ssl:// connections.
+-     * @param string  $proxy_user  a user name for accessing the proxy server
+-     * @param string  $proxy_pass  a password for accessing the proxy server
+-     *
+-     * @return void
+-     */
+-    function XML_RPC_Client($path, $server, $port = 0,
+-                            $proxy = '', $proxy_port = 0,
+-                            $proxy_user = '', $proxy_pass = '')
+-    {
+-        $this->path       = $path;
+-        $this->proxy_user = $proxy_user;
+-        $this->proxy_pass = $proxy_pass;
+-
+-        preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match);
+-        if ($match[1] == '') {
+-            if ($port == 443) {
+-                $this->server   = $match[2];
+-                $this->protocol = 'ssl://';
+-                $this->port     = 443;
+-            } else {
+-                $this->server = $match[2];
+-                if ($port) {
+-                    $this->port = $port;
+-                }
+-            }
+-        } elseif ($match[1] == 'http://') {
+-            $this->server = $match[2];
+-            if ($port) {
+-                $this->port = $port;
+-            }
+-        } else {
+-            $this->server   = $match[2];
+-            $this->protocol = 'ssl://';
+-            if ($port) {
+-                $this->port = $port;
+-            } else {
+-                $this->port = 443;
+-            }
+-        }
+-
+-        if ($proxy) {
+-            preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match);
+-            if ($match[1] == '') {
+-                if ($proxy_port == 443) {
+-                    $this->proxy          = $match[2];
+-                    $this->proxy_protocol = 'ssl://';
+-                    $this->proxy_port     = 443;
+-                } else {
+-                    $this->proxy = $match[2];
+-                    if ($proxy_port) {
+-                        $this->proxy_port = $proxy_port;
+-                    }
+-                }
+-            } elseif ($match[1] == 'http://') {
+-                $this->proxy = $match[2];
+-                if ($proxy_port) {
+-                    $this->proxy_port = $proxy_port;
+-                }
+-            } else {
+-                $this->proxy          = $match[2];
+-                $this->proxy_protocol = 'ssl://';
+-                if ($proxy_port) {
+-                    $this->proxy_port = $proxy_port;
+-                } else {
+-                    $this->proxy_port = 443;
+-                }
+-            }
+-        }
+-    }
+-
+-    /**
+-     * Change the current debug mode
+-     *
+-     * @param int $in  where 1 = on, 0 = off
+-     *
+-     * @return void
+-     */
+-    function setDebug($in)
+-    {
+-        if ($in) {
+-            $this->debug = 1;
+-        } else {
+-            $this->debug = 0;
+-        }
+-    }
+-
+-    /**
+-     * Set username and password properties for connecting to the RPC server
+-     *
+-     * @param string $u  the user name
+-     * @param string $p  the password
+-     *
+-     * @return void
+-     *
+-     * @see XML_RPC_Client::$username, XML_RPC_Client::$password
+-     */
+-    function setCredentials($u, $p)
+-    {
+-        $this->username = $u;
+-        $this->password = $p;
+-    }
+-
+-    /**
+-     * Transmit the RPC request via HTTP 1.0 protocol
+-     *
+-     * @param object $msg       the XML_RPC_Message object
+-     * @param int    $timeout   how many seconds to wait for the request
+-     *
+-     * @return object  an XML_RPC_Response object.  0 is returned if any
+-     *                  problems happen.
+-     *
+-     * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
+-     *      XML_RPC_Client::setCredentials()
+-     */
+-    function send($msg, $timeout = 0)
+-    {
+-        $msg->debug = $this->debug;
+-        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
+-                                        $timeout, $this->username,
+-                                        $this->password);
+-    }
+-
+-    /**
+-     * Transmit the RPC request via HTTP 1.0 protocol
+-     *
+-     * Requests should be sent using XML_RPC_Client send() rather than
+-     * calling this method directly.
+-     *
+-     * @param object $msg       the XML_RPC_Message object
+-     * @param string $server    the server to send the request to
+-     * @param int    $port      the server port send the request to
+-     * @param int    $timeout   how many seconds to wait for the request
+-     *                           before giving up
+-     * @param string $username  a user name for accessing the RPC server
+-     * @param string $password  a password for accessing the RPC server
+-     *
+-     * @return object  an XML_RPC_Response object.  0 is returned if any
+-     *                  problems happen.
+-     *
+-     * @see XML_RPC_Client::send()
+-     */
+-    function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
+-                               $username = '', $password = '')
+-    {
+-        /*
+-         * If we're using a proxy open a socket to the proxy server
+-         * instead to the xml-rpc server
+-         */
+-        if ($this->proxy) {
+-            if ($this->proxy_protocol == 'http://') {
+-                $protocol = '';
+-            } else {
+-                $protocol = $this->proxy_protocol;
+-            }
+-            if ($timeout > 0) {
+-                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
+-                                 $this->errno, $this->errstr, $timeout);
+-            } else {
+-                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
+-                                 $this->errno, $this->errstr);
+-            }
+-        } else {
+-            if ($this->protocol == 'http://') {
+-                $protocol = '';
+-            } else {
+-                $protocol = $this->protocol;
+-            }
+-            if ($timeout > 0) {
+-                $fp = @fsockopen($protocol . $server, $port,
+-                                 $this->errno, $this->errstr, $timeout);
+-            } else {
+-                $fp = @fsockopen($protocol . $server, $port,
+-                                 $this->errno, $this->errstr);
+-            }
+-        }
+-
+-        /*
+-         * Just raising the error without returning it is strange,
+-         * but keep it here for backwards compatibility.
+-         */
+-        if (!$fp && $this->proxy) {
+-            $this->raiseError('Connection to proxy server '
+-                              . $this->proxy . ':' . $this->proxy_port
+-                              . ' failed. ' . $this->errstr,
+-                              XML_RPC_ERROR_CONNECTION_FAILED);
+-            return 0;
+-        } elseif (!$fp) {
+-            $this->raiseError('Connection to RPC server '
+-                              . $server . ':' . $port
+-                              . ' failed. ' . $this->errstr,
+-                              XML_RPC_ERROR_CONNECTION_FAILED);
+-            return 0;
+-        }
+-
+-        // Only create the payload if it was not created previously
+-        if (empty($msg->payload)) {
+-            $msg->createPayload();
+-        }
+-
+-        // thanks to Grant Rauscher  for this
+-        $credentials = '';
+-        if ($username != '') {
+-            $credentials = 'Authorization: Basic ' .
+-                base64_encode($username . ':' . $password) . "\r\n";
+-        }
+-
+-        if ($this->proxy) {
+-            $op = 'POST ' . $this->protocol . $server;
+-            if ($this->proxy_port) {
+-                $op .= ':' . $this->port;
+-            }
+-        } else {
+-           $op = 'POST ';
+-        }
+-
+-        $op .= $this->path. " HTTP/1.0\r\n" .
+-               "User-Agent: PEAR XML_RPC\r\n" .
+-               'Host: ' . $server . "\r\n";
+-        if ($this->proxy && $this->proxy_user != '') {
+-            $op .= 'Proxy-Authorization: Basic ' .
+-                base64_encode($this->proxy_user . ':' . $this->proxy_pass) .
+-                "\r\n";
+-        }
+-        $op .= $credentials .
+-               "Content-Type: text/xml\r\n" .
+-               'Content-Length: ' . strlen($msg->payload) . "\r\n\r\n" .
+-               $msg->payload;
+-
+-        if (!fputs($fp, $op, strlen($op))) {
+-            $this->errstr = 'Write error';
+-            return 0;
+-        }
+-        $resp = $msg->parseResponseFile($fp);
+-        fclose($fp);
+-        return $resp;
+-    }
+-}
+-
+-/**
+- *
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Response extends XML_RPC_Base
+-{
+-    var $xv;
+-    var $fn;
+-    var $fs;
+-    var $hdrs;
+-
+-    /**
+-     * @return void
+-     */
+-    function XML_RPC_Response($val, $fcode = 0, $fstr = '')
+-    {
+-        if ($fcode != 0) {
+-            $this->fn = $fcode;
+-            $this->fs = htmlspecialchars($fstr);
+-        } else {
+-            $this->xv = $val;
+-        }
+-    }
+-
+-    /**
+-     * @return int  the error code
+-     */
+-    function faultCode()
+-    {
+-        if (isset($this->fn)) {
+-            return $this->fn;
+-        } else {
+-            return 0;
+-        }
+-    }
+-
+-    /**
+-     * @return string  the error string
+-     */
+-    function faultString()
+-    {
+-        return $this->fs;
+-    }
+-
+-    /**
+-     * @return mixed  the value
+-     */
+-    function value()
+-    {
+-        return $this->xv;
+-    }
+-
+-    /**
+-     * @return string  the error message in XML format
+-     */
+-    function serialize()
+-    {
+-        $rs = "\n";
+-        if ($this->fn) {
+-            $rs .= "
+-  
+-    
+-      
+-        faultCode
+-        " . $this->fn . "
+-      
+-      
+-        faultString
+-        " . $this->fs . "
+-      
+-    
+-  
+-";
+-        } else {
+-            $rs .= "\n\n" . $this->xv->serialize() .
+-        "\n";
+-        }
+-        $rs .= "\n";
+-        return $rs;
+-    }
+-}
+-
+-/**
+- *
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Message extends XML_RPC_Base
+-{
+-    /**
+-     * The current debug mode (1 = on, 0 = off)
+-     * @var integer
+-     */
+-    var $debug = 0;
+-
+-    /**
+-     * The encoding to be used for outgoing messages
+-     *
+-     * Defaults to the value of $GLOBALS['XML_RPC_defencoding']
+-     *
+-     * @var string
+-     * @see XML_RPC_Message::setSendEncoding(),
+-     *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
+-     */
+-    var $send_encoding = '';
+-
+-    /**
+-     * The method presently being evaluated
+-     * @var string
+-     */
+-    var $methodname = '';
+-
+-    /**
+-     * @var array
+-     */
+-    var $params = array();
+-
+-    /**
+-     * The XML message being generated
+-     * @var string
+-     */
+-    var $payload = '';
+-
+-    /**
+-     * @return void
+-     */
+-    function XML_RPC_Message($meth, $pars = 0)
+-    {
+-        $this->methodname = $meth;
+-        if (is_array($pars) && sizeof($pars) > 0) {
+-            for ($i = 0; $i < sizeof($pars); $i++) {
+-                $this->addParam($pars[$i]);
+-            }
+-        }
+-    }
+-
+-    /**
+-     * Produces the XML declaration including the encoding attribute
+-     *
+-     * The encoding is determined by this class' $send_encoding
+-     * property.  If the $send_encoding property is not set, use
+-     * $GLOBALS['XML_RPC_defencoding'].
+-     *
+-     * @return string  the XML declaration and  element
+-     *
+-     * @see XML_RPC_Message::setSendEncoding(),
+-     *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
+-     */
+-    function xml_header()
+-    {
+-        global $XML_RPC_defencoding;
+-        if (!$this->send_encoding) {
+-            $this->send_encoding = $XML_RPC_defencoding;
+-        }
+-        return 'send_encoding . '"?>'
+-               . "\n\n";
+-    }
+-
+-    /**
+-     * @return string  the closing  tag
+-     */
+-    function xml_footer()
+-    {
+-        return "\n";
+-    }
+-
+-    /**
+-     * @return void
+-     *
+-     * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
+-     */
+-    function createPayload()
+-    {
+-        $this->payload = $this->xml_header();
+-        $this->payload .= '' . $this->methodname . "\n";
+-        $this->payload .= "\n";
+-        for ($i = 0; $i < sizeof($this->params); $i++) {
+-            $p = $this->params[$i];
+-            $this->payload .= "\n" . $p->serialize() . "\n";
+-        }
+-        $this->payload .= "\n";
+-        $this->payload .= $this->xml_footer();
+-        $this->payload = ereg_replace("[\r\n]+", "\r\n", $this->payload);
+-    }
+-
+-    /**
+-     * @return string  the name of the method
+-     */
+-    function method($meth = '')
+-    {
+-        if ($meth != '') {
+-            $this->methodname = $meth;
+-        }
+-        return $this->methodname;
+-    }
+-
+-    /**
+-     * @return string  the payload
+-     */
+-    function serialize()
+-    {
+-        $this->createPayload();
+-        return $this->payload;
+-    }
+-
+-    /**
+-     * @return void
+-     */
+-    function addParam($par)
+-    {
+-        $this->params[] = $par;
+-    }
+-
+-    /**
+-     * @return void
+-     */
+-    function getParam($i)
+-    {
+-        return $this->params[$i];
+-    }
+-
+-    /**
+-     * @return int  the number of parameters
+-     */
+-    function getNumParams()
+-    {
+-        return sizeof($this->params);
+-    }
+-
+-    /**
+-     * Sets the XML declaration's encoding attribute
+-     *
+-     * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
+-     *
+-     * @return void
+-     *
+-     * @see XML_RPC_Message::$send_encoding, XML_RPC_Message::xml_header()
+-     * @since Method available since Release 1.2.0
+-     */
+-    function setSendEncoding($type)
+-    {
+-        $this->send_encoding = $type;
+-    }
+-
+-    /**
+-     * Determine the XML's encoding via the encoding attribute
+-     * in the XML declaration
+-     *
+-     * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
+-     * or US-ASCII, $XML_RPC_defencoding will be returned.
+-     *
+-     * @param string $data  the XML that will be parsed
+-     *
+-     * @return string  the encoding to be used
+-     *
+-     * @link   http://php.net/xml_parser_create
+-     * @since  Method available since Release 1.2.0
+-     */
+-    function getEncoding($data)
+-    {
+-        global $XML_RPC_defencoding;
+-
+-        if (preg_match('/<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]/i',
+-                       $data, $match))
+-        {
+-            $match[1] = trim(strtoupper($match[1]));
+-            switch ($match[1]) {
+-                case 'ISO-8859-1':
+-                case 'UTF-8':
+-                case 'US-ASCII':
+-                    return $match[1];
+-                    break;
+-
+-                default:
+-                    return $XML_RPC_defencoding;
+-            }
+-        } else {
+-            return $XML_RPC_defencoding;
+-        }
+-    }
+-
+-    /**
+-     * @return object  a new XML_RPC_Response object
+-     */
+-    function parseResponseFile($fp)
+-    {
+-        $ipd = '';
+-        while ($data = @fread($fp, 8192)) {
+-            $ipd .= $data;
+-        }
+-        return $this->parseResponse($ipd);
+-    }
+-
+-    /**
+-     * @return object  a new XML_RPC_Response object
+-     */
+-    function parseResponse($data = '')
+-    {
+-        global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
+-
+-        $encoding = $this->getEncoding($data);
+-        $parser = xml_parser_create($encoding);
+-
+-        $XML_RPC_xh[$parser] = array();
+-
+-        $XML_RPC_xh[$parser]['st'] = '';
+-        $XML_RPC_xh[$parser]['cm'] = 0;
+-        $XML_RPC_xh[$parser]['isf'] = 0;
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = '';
+-
+-        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
+-        xml_set_element_handler($parser, 'XML_RPC_se', 'XML_RPC_ee');
+-        xml_set_character_data_handler($parser, 'XML_RPC_cd');
+-
+-        $hdrfnd = 0;
+-        if ($this->debug) {
+-            print "
---GOT---\n";
+-            print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
+-            print "\n---END---\n
"; +- } +- +- // see if we got an HTTP 200 OK, else bomb +- // but only do this if we're using the HTTP protocol. +- if (ereg('^HTTP', $data) && +- !ereg('^HTTP/[0-9\.]+ 200 ', $data)) { +- $errstr = substr($data, 0, strpos($data, "\n") - 1); +- error_log('HTTP error, got response: ' . $errstr); +- $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], +- $XML_RPC_str['http_error'] . ' (' . +- $errstr . ')'); +- xml_parser_free($parser); +- return $r; +- } +- // gotta get rid of headers here +- +- +- if ((!$hdrfnd) && ($brpos = strpos($data,"\r\n\r\n"))) { +- $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos); +- $data = substr($data, $brpos + 4); +- $hdrfnd = 1; +- } +- +- /* +- * be tolerant of junk after methodResponse +- * (e.g. javascript automatically inserted by free hosts) +- * thanks to Luca Mariano +- */ +- $data = substr($data, 0, strpos($data, "") + 17); +- +- if (!xml_parse($parser, $data, sizeof($data))) { +- // thanks to Peter Kocks +- if ((xml_get_current_line_number($parser)) == 1) { +- $errstr = 'XML error at line 1, check URL'; +- } else { +- $errstr = sprintf('XML error: %s at line %d', +- xml_error_string(xml_get_error_code($parser)), +- xml_get_current_line_number($parser)); +- } +- error_log($errstr); +- $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], +- $XML_RPC_str['invalid_return']); +- xml_parser_free($parser); +- return $r; +- } +- xml_parser_free($parser); +- if ($this->debug) { +- print '
---EVALING---[' .
+-            strlen($XML_RPC_xh[$parser]['st']) . " chars]---\n" .
+-            htmlspecialchars($XML_RPC_xh[$parser]['st']) . ";\n---END---
"; +- } +- if (strlen($XML_RPC_xh[$parser]['st']) == 0) { +- // then something odd has happened +- // and it's time to generate a client side error +- // indicating something odd went on +- $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], +- $XML_RPC_str['invalid_return']); +- } else { +- eval('$v=' . $XML_RPC_xh[$parser]['st'] . '; $allOK=1;'); +- if ($XML_RPC_xh[$parser]['isf']) { +- $f = $v->structmem('faultCode'); +- $fs = $v->structmem('faultString'); +- $r = new XML_RPC_Response($v, $f->scalarval(), +- $fs->scalarval()); +- } else { +- $r = new XML_RPC_Response($v); +- } +- } +- $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]); +- return $r; +- } +-} +- +-/** +- * +- * +- * @category Web Services +- * @package XML_RPC +- * @author Edd Dumbill +- * @author Stig Bakken +- * @author Martin Jansen +- * @copyright 1999-2001 Edd Dumbill +- * @version Release: 1.2.2 +- * @link http://pear.php.net/package/XML_RPC +- */ +-class XML_RPC_Value extends XML_RPC_Base +-{ +- var $me = array(); +- var $mytype = 0; +- +- /** +- * @return void +- */ +- function XML_RPC_Value($val = -1, $type = '') +- { +- global $XML_RPC_Types; +- $this->me = array(); +- $this->mytype = 0; +- if ($val != -1 || $type != '') { +- if ($type == '') { +- $type = 'string'; +- } +- if (!array_key_exists($type, $XML_RPC_Types)) { +- // XXX +- // need some way to report this error +- } elseif ($XML_RPC_Types[$type] == 1) { +- $this->addScalar($val, $type); +- } elseif ($XML_RPC_Types[$type] == 2) { +- $this->addArray($val); +- } elseif ($XML_RPC_Types[$type] == 3) { +- $this->addStruct($val); +- } +- } +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addScalar($val, $type = 'string') +- { +- global $XML_RPC_Types, $XML_RPC_Boolean; +- +- if ($this->mytype == 1) { +- $this->raiseError('Scalar can have only one value', +- XML_RPC_ERROR_INVALID_TYPE); +- return 0; +- } +- $typeof = $XML_RPC_Types[$type]; +- if ($typeof != 1) { +- $this->raiseError("Not a scalar type (${typeof})", +- XML_RPC_ERROR_INVALID_TYPE); +- return 0; +- } +- +- if ($type == $XML_RPC_Boolean) { +- if (strcasecmp($val, 'true') == 0 +- || $val == 1 +- || ($val == true && strcasecmp($val, 'false'))) +- { +- $val = 1; +- } else { +- $val = 0; +- } +- } +- +- if ($this->mytype == 2) { +- // we're adding to an array here +- $ar = $this->me['array']; +- $ar[] = new XML_RPC_Value($val, $type); +- $this->me['array'] = $ar; +- } else { +- // a scalar, so set the value and remember we're scalar +- $this->me[$type] = $val; +- $this->mytype = $typeof; +- } +- return 1; +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addArray($vals) +- { +- global $XML_RPC_Types; +- if ($this->mytype != 0) { +- $this->raiseError( +- 'Already initialized as a [' . $this->kindOf() . ']', +- XML_RPC_ERROR_ALREADY_INITIALIZED); +- return 0; +- } +- $this->mytype = $XML_RPC_Types['array']; +- $this->me['array'] = $vals; +- return 1; +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addStruct($vals) +- { +- global $XML_RPC_Types; +- if ($this->mytype != 0) { +- $this->raiseError( +- 'Already initialized as a [' . $this->kindOf() . ']', +- XML_RPC_ERROR_ALREADY_INITIALIZED); +- return 0; +- } +- $this->mytype = $XML_RPC_Types['struct']; +- $this->me['struct'] = $vals; +- return 1; +- } +- +- /** +- * @return void +- */ +- function dump($ar) +- { +- reset($ar); +- while (list($key, $val) = each($ar)) { +- echo "$key => $val
"; +- if ($key == 'array') { +- while (list($key2, $val2) = each($val)) { +- echo "-- $key2 => $val2
"; +- } +- } +- } +- } +- +- /** +- * @return string the data type of the current value +- */ +- function kindOf() +- { +- switch ($this->mytype) { +- case 3: +- return 'struct'; +- +- case 2: +- return 'array'; +- +- case 1: +- return 'scalar'; +- +- default: +- return 'undef'; +- } +- } +- +- /** +- * @return string the data in XML format +- */ +- function serializedata($typ, $val) +- { +- $rs = ''; +- global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean; +- if (!array_key_exists($typ, $XML_RPC_Types)) { +- // XXX +- // need some way to report this error +- return; +- } +- switch ($XML_RPC_Types[$typ]) { +- case 3: +- // struct +- $rs .= "\n"; +- reset($val); +- while (list($key2, $val2) = each($val)) { +- $rs .= "${key2}\n"; +- $rs .= $this->serializeval($val2); +- $rs .= "\n"; +- } +- $rs .= ''; +- break; +- +- case 2: +- // array +- $rs .= "\n\n"; +- for ($i = 0; $i < sizeof($val); $i++) { +- $rs .= $this->serializeval($val[$i]); +- } +- $rs .= "\n"; +- break; +- +- case 1: +- switch ($typ) { +- case $XML_RPC_Base64: +- $rs .= "<${typ}>" . base64_encode($val) . ""; +- break; +- case $XML_RPC_Boolean: +- $rs .= "<${typ}>" . ($val ? '1' : '0') . ""; +- break; +- case $XML_RPC_String: +- $rs .= "<${typ}>" . htmlspecialchars($val). ""; +- break; +- default: +- $rs .= "<${typ}>${val}"; +- } +- } +- return $rs; +- } +- +- /** +- * @return string the data in XML format +- */ +- function serialize() +- { +- return $this->serializeval($this); +- } +- +- /** +- * @return string the data in XML format +- */ +- function serializeval($o) +- { +- $rs = ''; +- $ar = $o->me; +- reset($ar); +- list($typ, $val) = each($ar); +- $rs .= ''; +- $rs .= $this->serializedata($typ, $val); +- $rs .= "\n"; +- return $rs; +- } +- +- /** +- * @return mixed the contents of the element requested +- */ +- function structmem($m) +- { +- return $this->me['struct'][$m]; +- } +- +- /** +- * @return void +- */ +- function structreset() +- { +- reset($this->me['struct']); +- } +- +- /** +- * @return the key/value pair of the struct's current element +- */ +- function structeach() +- { +- return each($this->me['struct']); +- } +- +- /** +- * @return mixed the current value +- */ +- function getval() { +- // UNSTABLE +- global $XML_RPC_BOOLEAN, $XML_RPC_Base64; +- +- reset($this->me); +- list($a, $b) = each($this->me); +- +- // contributed by I Sofer, 2001-03-24 +- // add support for nested arrays to scalarval +- // i've created a new method here, so as to +- // preserve back compatibility +- +- if (is_array($b)) { +- foreach ($b as $id => $cont) { +- $b[$id] = $cont->scalarval(); +- } +- } +- +- // add support for structures directly encoding php objects +- if (is_object($b)) { +- $t = get_object_vars($b); +- foreach ($t as $id => $cont) { +- $t[$id] = $cont->scalarval(); +- } +- foreach ($t as $id => $cont) { +- eval('$b->'.$id.' = $cont;'); +- } +- } +- +- // end contrib +- return $b; +- } +- +- /** +- * @return mixed +- */ +- function scalarval() +- { +- global $XML_RPC_Boolean, $XML_RPC_Base64; +- reset($this->me); +- list($a, $b) = each($this->me); +- return $b; +- } +- +- /** +- * @return string +- */ +- function scalartyp() +- { +- global $XML_RPC_I4, $XML_RPC_Int; +- reset($this->me); +- list($a, $b) = each($this->me); +- if ($a == $XML_RPC_I4) { +- $a = $XML_RPC_Int; +- } +- return $a; +- } +- +- /** +- * @return mixed the struct's current element +- */ +- function arraymem($m) +- { +- return $this->me['array'][$m]; +- } +- +- /** +- * @return int the number of elements in the array +- */ +- function arraysize() +- { +- reset($this->me); +- list($a, $b) = each($this->me); +- return sizeof($b); +- } +-} +- +-/** +- * Return an ISO8601 encoded string +- * +- * While timezones ought to be supported, the XML-RPC spec says: +- * +- * "Don't assume a timezone. It should be specified by the server in its +- * documentation what assumptions it makes about timezones." +- * +- * This routine always assumes localtime unless $utc is set to 1, in which +- * case UTC is assumed and an adjustment for locale is made when encoding. +- * +- * @return string the formatted date +- */ +-function XML_RPC_iso8601_encode($timet, $utc = 0) { +- if (!$utc) { +- $t = strftime('%Y%m%dT%H:%M:%S', $timet); +- } else { +- if (function_exists('gmstrftime')) { +- // gmstrftime doesn't exist in some versions +- // of PHP +- $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); +- } else { +- $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); +- } +- } +- return $t; +-} +- +-/** +- * Convert a datetime string into a Unix timestamp +- * +- * While timezones ought to be supported, the XML-RPC spec says: +- * +- * "Don't assume a timezone. It should be specified by the server in its +- * documentation what assumptions it makes about timezones." +- * +- * This routine always assumes localtime unless $utc is set to 1, in which +- * case UTC is assumed and an adjustment for locale is made when encoding. +- * +- * @return int the unix timestamp of the date submitted +- */ +-function XML_RPC_iso8601_decode($idate, $utc = 0) { +- $t = 0; +- if (ereg('([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})', $idate, $regs)) { +- if ($utc) { +- $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +- } else { +- $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +- } +- } +- return $t; +-} +- +-/** +- * Takes a message in PHP XML_RPC object format and translates it into +- * native PHP types +- * +- * @return mixed +- * +- * @author Dan Libby +- */ +-function XML_RPC_decode($XML_RPC_val) +-{ +- $kind = $XML_RPC_val->kindOf(); +- +- if ($kind == 'scalar') { +- return $XML_RPC_val->scalarval(); +- +- } elseif ($kind == 'array') { +- $size = $XML_RPC_val->arraysize(); +- $arr = array(); +- for ($i = 0; $i < $size; $i++) { +- $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i)); +- } +- return $arr; +- +- } elseif ($kind == 'struct') { +- $XML_RPC_val->structreset(); +- $arr = array(); +- while (list($key, $value) = $XML_RPC_val->structeach()) { +- $arr[$key] = XML_RPC_decode($value); +- } +- return $arr; +- } +-} +- +-/** +- * Takes native php types and encodes them into XML_RPC PHP object format +- * +- * Feature creep -- could support more types via optional type argument. +- * +- * @return string +- * +- * @author Dan Libby +- */ +-function XML_RPC_encode($php_val) { +- global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double, $XML_RPC_String, +- $XML_RPC_Array, $XML_RPC_Struct; +- +- $type = gettype($php_val); +- $XML_RPC_val = new XML_RPC_Value; +- +- switch ($type) { +- case 'array': +- if (empty($php_val)) { +- $XML_RPC_val->addArray($php_val); +- break; +- } +- $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); +- if (empty($tmp)) { +- $arr = array(); +- foreach ($php_val as $k => $v) { +- $arr[$k] = XML_RPC_encode($v); +- } +- $XML_RPC_val->addArray($arr); +- break; +- } +- // fall though if it's not an enumerated array +- +- case 'object': +- $arr = array(); +- foreach ($php_val as $k => $v) { +- $arr[$k] = XML_RPC_encode($v); +- } +- $XML_RPC_val->addStruct($arr); +- break; +- +- case 'integer': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Int); +- break; +- +- case 'double': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Double); +- break; +- +- case 'string': +- case 'NULL': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_String); +- break; +- +- case 'boolean': +- // Add support for encoding/decoding of booleans, since they +- // are supported in PHP +- // by +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean); +- break; +- +- case 'unknown type': +- default: +- $XML_RPC_val = false; +- } +- return $XML_RPC_val; +-} +- +-/* +- * Local variables: +- * tab-width: 4 +- * c-basic-offset: 4 +- * c-hanging-comment-ender-p: nil +- * End: +- */ +- +-?> +-XML_RPC-1.2.2/Server.php100666 0 0 36235 10213112551 7713 +- * @author Stig Bakken +- * @author Martin Jansen +- * @copyright 1999-2001 Edd Dumbill +- * @version CVS: $Id: Server.php,v 1.17 2005/03/01 17:09:49 danielc Exp $ +- * @link http://pear.php.net/package/XML_RPC +- */ +- +- +-/** +- * Pull in the XML_RPC class +- */ +-require_once 'XML/RPC.php'; +- +- +-/** +- * listMethods: either a string, or nothing +- * @global array $GLOBALS['XML_RPC_Server_listMethods_sig'] +- */ +-$GLOBALS['XML_RPC_Server_listMethods_sig'] = array( +- array($GLOBALS['XML_RPC_Array'], +- $GLOBALS['XML_RPC_String'] +- ), +- array($GLOBALS['XML_RPC_Array']) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_listMethods_doc'] +- */ +-$GLOBALS['XML_RPC_Server_listMethods_doc'] = 'This method lists all the' +- . ' methods that the XML-RPC server knows how to dispatch'; +- +-/** +- * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig'] +- */ +-$GLOBALS['XML_RPC_Server_methodSignature_sig'] = array( +- array($GLOBALS['XML_RPC_Array'], +- $GLOBALS['XML_RPC_String'] +- ) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc'] +- */ +-$GLOBALS['XML_RPC_Server_methodSignature_doc'] = 'Returns an array of known' +- . ' signatures (an array of arrays) for the method name passed. If' +- . ' no signatures are known, returns a none-array (test for type !=' +- . ' array to detect missing signature)'; +- +-/** +- * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig'] +- */ +-$GLOBALS['XML_RPC_Server_methodHelp_sig'] = array( +- array($GLOBALS['XML_RPC_String'], +- $GLOBALS['XML_RPC_String'] +- ) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc'] +- */ +-$GLOBALS['XML_RPC_Server_methodHelp_doc'] = 'Returns help text if defined' +- . ' for the method passed, otherwise returns an empty string'; +- +-/** +- * @global array $GLOBALS['XML_RPC_Server_dmap'] +- */ +-$GLOBALS['XML_RPC_Server_dmap'] = array( +- 'system.listMethods' => array( +- 'function' => 'XML_RPC_Server_listMethods', +- 'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc'] +- ), +- 'system.methodHelp' => array( +- 'function' => 'XML_RPC_Server_methodHelp', +- 'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc'] +- ), +- 'system.methodSignature' => array( +- 'function' => 'XML_RPC_Server_methodSignature', +- 'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc'] +- ) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_debuginfo'] +- */ +-$GLOBALS['XML_RPC_Server_debuginfo'] = ''; +- +- +-/** +- * Lists all the methods that the XML-RPC server knows how to dispatch +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_listMethods($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $v = new XML_RPC_Value(); +- $dmap = $server->dmap; +- $outAr = array(); +- for (reset($dmap); list($key, $val) = each($dmap); ) { +- $outAr[] = new XML_RPC_Value($key, 'string'); +- } +- $dmap = $XML_RPC_Server_dmap; +- for (reset($dmap); list($key, $val) = each($dmap); ) { +- $outAr[] = new XML_RPC_Value($key, 'string'); +- } +- $v->addArray($outAr); +- return new XML_RPC_Response($v); +-} +- +-/** +- * Returns an array of known signatures (an array of arrays) +- * for the given method +- * +- * If no signatures are known, returns a none-array +- * (test for type != array to detect missing signature) +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_methodSignature($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $methName = $m->getParam(0); +- $methName = $methName->scalarval(); +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $server->dmap; +- $sysCall = 0; +- } +- // print "\n"; +- if (isset($dmap[$methName])) { +- if ($dmap[$methName]['signature']) { +- $sigs = array(); +- $thesigs = $dmap[$methName]['signature']; +- for ($i = 0; $i < sizeof($thesigs); $i++) { +- $cursig = array(); +- $inSig = $thesigs[$i]; +- for ($j = 0; $j < sizeof($inSig); $j++) { +- $cursig[] = new XML_RPC_Value($inSig[$j], 'string'); +- } +- $sigs[] = new XML_RPC_Value($cursig, 'array'); +- } +- $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array')); +- } else { +- $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string')); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], +- $XML_RPC_str['introspect_unknown']); +- } +- return $r; +-} +- +-/** +- * Returns help text if defined for the method passed, otherwise returns +- * an empty string +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_methodHelp($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $methName = $m->getParam(0); +- $methName = $methName->scalarval(); +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $server->dmap; +- $sysCall = 0; +- } +- // print "\n"; +- if (isset($dmap[$methName])) { +- if ($dmap[$methName]['docstring']) { +- $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']), +- 'string'); +- } else { +- $r = new XML_RPC_Response(new XML_RPC_Value('', 'string')); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], +- $XML_RPC_str['introspect_unknown']); +- } +- return $r; +-} +- +-/** +- * @return void +- */ +-function XML_RPC_Server_debugmsg($m) +-{ +- global $XML_RPC_Server_debuginfo; +- $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n"; +-} +- +- +-/** +- * +- * +- * @category Web Services +- * @package XML_RPC +- * @author Edd Dumbill +- * @author Stig Bakken +- * @author Martin Jansen +- * @copyright 1999-2001 Edd Dumbill +- * @version Release: 1.2.2 +- * @link http://pear.php.net/package/XML_RPC +- */ +-class XML_RPC_Server +-{ +- var $dmap = array(); +- var $encoding = ''; +- var $debug = 0; +- +- /** +- * @return void +- */ +- function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) +- { +- global $HTTP_RAW_POST_DATA; +- +- if ($debug) { +- $this->debug = 1; +- } else { +- $this->debug = 0; +- } +- +- // dispMap is a despatch array of methods +- // mapped to function names and signatures +- // if a method +- // doesn't appear in the map then an unknown +- // method error is generated +- $this->dmap = $dispMap; +- if ($serviceNow) { +- $this->service(); +- } +- } +- +- /** +- * @return string the debug information if debug debug mode is on +- */ +- function serializeDebug() +- { +- global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA; +- +- if ($this->debug) { +- XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n" +- . $HTTP_RAW_POST_DATA +- . "\n" . '^^^ END POST DATA ^^^'); +- } +- +- if ($XML_RPC_Server_debuginfo != '') { +- return "\n"; +- } else { +- return ''; +- } +- } +- +- /** +- * Print out the result +- * +- * The encoding and content-type are determined by +- * XML_RPC_Message::getEncoding() +- * +- * @return void +- * +- * @see XML_RPC_Message::getEncoding() +- */ +- function service() +- { +- $r = $this->parseRequest(); +- $payload = 'encoding . '"?>' . "\n" +- . $this->serializeDebug() +- . $r->serialize(); +- header('Content-Length: ' . strlen($payload)); +- header('Content-Type: text/xml; charset=' . $this->encoding); +- print $payload; +- } +- +- /** +- * @return array +- */ +- function verifySignature($in, $sig) +- { +- for ($i = 0; $i < sizeof($sig); $i++) { +- // check each possible signature in turn +- $cursig = $sig[$i]; +- if (sizeof($cursig) == $in->getNumParams() + 1) { +- $itsOK = 1; +- for ($n = 0; $n < $in->getNumParams(); $n++) { +- $p = $in->getParam($n); +- // print "\n"; +- if ($p->kindOf() == 'scalar') { +- $pt = $p->scalartyp(); +- } else { +- $pt = $p->kindOf(); +- } +- // $n+1 as first type of sig is return type +- if ($pt != $cursig[$n+1]) { +- $itsOK = 0; +- $pno = $n+1; +- $wanted = $cursig[$n+1]; +- $got = $pt; +- break; +- } +- } +- if ($itsOK) { +- return array(1); +- } +- } +- } +- return array(0, "Wanted ${wanted}, got ${got} at param ${pno})"); +- } +- +- /** +- * @return object a new XML_RPC_Response object +- */ +- function parseRequest($data = '') +- { +- global $XML_RPC_xh, $HTTP_RAW_POST_DATA, +- $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml, +- $XML_RPC_defencoding, $XML_RPC_Server_dmap; +- +- if ($data == '') { +- $data = $HTTP_RAW_POST_DATA; +- } +- +- $this->encoding = XML_RPC_Message::getEncoding($data); +- $parser = xml_parser_create($this->encoding); +- +- $XML_RPC_xh[$parser] = array(); +- $XML_RPC_xh[$parser]['st'] = ''; +- $XML_RPC_xh[$parser]['cm'] = 0; +- $XML_RPC_xh[$parser]['isf'] = 0; +- $XML_RPC_xh[$parser]['params'] = array(); +- $XML_RPC_xh[$parser]['method'] = ''; +- +- $plist = ''; +- +- // decompose incoming XML into request structure +- +- xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); +- xml_set_element_handler($parser, 'XML_RPC_se', 'XML_RPC_ee'); +- xml_set_character_data_handler($parser, 'XML_RPC_cd'); +- if (!xml_parse($parser, $data, 1)) { +- // return XML error as a faultCode +- $r = new XML_RPC_Response(0, +- $XML_RPC_errxml+xml_get_error_code($parser), +- sprintf('XML error: %s at line %d', +- xml_error_string(xml_get_error_code($parser)), +- xml_get_current_line_number($parser))); +- xml_parser_free($parser); +- } else { +- xml_parser_free($parser); +- $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']); +- // now add parameters in +- for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) { +- // print '\n"; +- $plist .= "$i - " . $XML_RPC_xh[$parser]['params'][$i] . " \n"; +- eval('$m->addParam(' . $XML_RPC_xh[$parser]['params'][$i] . ');'); +- } +- XML_RPC_Server_debugmsg($plist); +- +- // now to deal with the method +- $methName = $XML_RPC_xh[$parser]['method']; +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $this->dmap; +- $sysCall = 0; +- } +- +- if (isset($dmap[$methName]['function']) +- && is_string($dmap[$methName]['function']) +- && strpos($dmap[$methName]['function'], '::') !== false) +- { +- $dmap[$methName]['function'] = +- explode('::', $dmap[$methName]['function']); +- } +- +- if (isset($dmap[$methName]['function']) +- && is_callable($dmap[$methName]['function'])) +- { +- // dispatch if exists +- if (isset($dmap[$methName]['signature'])) { +- $sr = $this->verifySignature($m, +- $dmap[$methName]['signature'] ); +- } +- if ( (!isset($dmap[$methName]['signature'])) || $sr[0]) { +- // if no signature or correct signature +- if ($sysCall) { +- $r = call_user_func($dmap[$methName]['function'], $this, $m); +- } else { +- $r = call_user_func($dmap[$methName]['function'], $m); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], +- $XML_RPC_str['incorrect_params'] +- . ': ' . $sr[1]); +- } +- } else { +- // else prepare error response +- $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'], +- $XML_RPC_str['unknown_method']); +- } +- } +- return $r; +- } +- +- /** +- * Echos back the input packet as a string value +- * +- * @return void +- * +- * Useful for debugging. +- */ +- function echoInput() { +- global $HTTP_RAW_POST_DATA; +- +- $r = new XML_RPC_Response(0); +- $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); +- print $r->serialize(); +- } +-} +- +-/* +- * Local variables: +- * tab-width: 4 +- * c-basic-offset: 4 +- * c-hanging-comment-ender-p: nil +- * End: +- */ +- +-?> +-package.xml100666 0 0 15556 10213112551 6252 +- +- +- XML_RPC +- PHP implementation of the XML-RPC protocol +- A PEAR-ified version of Useful Inc's XML-RPC for PHP. +- +-It has support for HTTP/HTTPS transport, proxies and authentication. +- +- +- +- ssb +- Stig Bakken +- stig@php.net +- lead +- +- +- danielc +- Daniel Convissor +- danielc@php.net +- lead +- +- +- +- 1.2.2 +- 2005-03-07 +- PHP License +- stable +- * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- 1.2.1 +- 2005-03-01 +- stable +- * Add isset() check before examining the dispatch map. Bug 3658. +- +- +- +- 1.2.0 +- 2005-02-27 +- stable +- * Provide the "stable" release. +-* Add package2.xml for compatibility with PEAR 1.4.0. +-* For changes since 1.1.0, see the changelogs for the various RC releases. +- +- +- +- 1.2.0RC7 +- 2005-02-22 +- beta +- * Add the setSendEncoding() method and $send_encoding +- property to XML_RPC_Message. Request 3537. +-* Allow class methods to be mapped using either syntax: +- 'function' => 'hello::sayHello', +- or +- 'function' => array('hello', 'sayhello'), +- Bug 3363. +-* Use 8192 instead of 32768 for bytes in fread() +- in parseResponseFile(). Bug 3340. +- +- +- +- 1.2.0RC6 +- 2005-01-25 +- beta +- * Don't put the protocol in the Host field of the POST data. (danielc) +- +- +- +- 1.2.0RC5 +- 2005-01-24 +- beta +- * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. +- +- +- +- 1.2.0RC4 +- 2005-01-24 +- beta +- * When a connection attempt fails, have the method return 0. (danielc) +-* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) +-* Add tests for setting the client properties. (danielc) +-* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) +-* Bundle the tests with the package. (danielc) +- +- +- +- 1.2.0RC3 +- 2005-01-19 +- beta +- * ssl uses port 443, not 445. +- +- +- +- 1.2.0RC2 +- 2005-01-11 +- beta +- * Handle ssl:// in the $server string. (danielc) +-* Also default to port 445 for ssl:// requests as well. (danielc) +-* Enhance debugging in the server. (danielc) +- +- +- +- 1.2.0RC1 +- 2004-12-30 +- beta +- * Make things work with SSL. Bug 2489. (nkukard lbsd net) +-* Allow array function callbacks (Matt Kane) +-* Some minor speed-ups (Matt Kane) +-* Add Dump.php to the package (Christian Weiske) +-* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) +-* Silence fsockopen() errors. Bug 1714. (danielc) +-* Encode empty arrays as an array. Bug 1493. (danielc) +-* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) +-* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) +-* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) +-* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) +-* Allow raiseError() to be called statically. (danielc) +-* Stop double escaping of character entities. Bug 987. (danielc) +- NOTICE: the following have been removed: +- * XML_RPC_dh() +- * $GLOBALS['XML_RPC_entities'] +- * XML_RPC_entity_decode() +- * XML_RPC_lookup_entity() +-* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) +- +- +- +- 1.1.0 +- 2004-03-15 +- stable +- * Added support for sequential arrays to XML_RPC_encode() (mroch) +-* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) +-* Remove "require_once 'PEAR.php'", include only when needed to raise an error +-* Replace echo and error_log() with raiseError() (mroch) +-* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) +-* be tolerant of junk after methodResponse (Luca Mariano, mroch) +-* Silent notice even in the error log (pierre) +-* fix include of shared xml extension on win32 (pierre) +- +- +- +- 1.0.4 +- 2002-10-02 +- stable +- * added HTTP proxy authorization support (thanks to Arnaud Limbourg) +- +- +- +- 1.0.3 +- 2002-05-19 +- stable +- * fix bug when parsing responses with boolean types +- +- +- +- 1.0.2 +- 2002-04-16 +- stable +- * E_ALL fixes +-* fix HTTP response header parsing +- +- +- +- 1.0.1 +- 2001-09-25 +- stable +- This is a PEAR-ified version of Useful Inc's 1.0.1 release. +-Includes an urgent security fix identified by Dan Libby <dan@libby.com>. +- +- +- +- +- +\ Kein Zeilenumbruch am Dateiende. +diff -Naur php-5.0.4/pear/packages/XML_RPC-1.3.1.tar hardening-patch-5.0.4-0.3.2/pear/packages/XML_RPC-1.3.1.tar +--- php-5.0.4/pear/packages/XML_RPC-1.3.1.tar 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/pear/packages/XML_RPC-1.3.1.tar 2005-06-29 16:04:30.000000000 +0200 +@@ -0,0 +1,3733 @@ ++package2.xml100644 1750 144 32557 10260516576 6517 ++ ++ XML_RPC ++ pear.php.net ++ PHP implementation of the XML-RPC protocol ++ A PEAR-ified version of Useful Inc's XML-RPC for PHP. ++ ++It has support for HTTP/HTTPS transport, proxies and authentication. ++ ++ Stig Bakken ++ ssb ++ stig@php.net ++ no ++ ++ ++ Daniel Convissor ++ danielc ++ danielc@php.net ++ yes ++ ++ 2005-06-29 ++ ++ ++ 1.3.1 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ PHP License ++ * Security fix. Update highly recommended! ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ PEAR ++ pear.php.net ++ 1.4.0a1 ++ 1.4.0a12 ++ ++ ++ ++ ++ 4.2.0 ++ 6.0.0 ++ ++ ++ 1.4.0a1 ++ ++ ++ ++ ++ ++ ++ ++ 1.3.0RC3 ++ 1.3.0 ++ ++ ++ beta ++ stable ++ ++ 2005-05-10 ++ PHP License ++ * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. ++* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. ++* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. ++* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. ++* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). ++* Use <br /> instead of <br> in XML_RPC_Value::dump(). ++ ++ ++ ++ 1.3.0RC2 ++ 1.3.0 ++ ++ ++ beta ++ beta ++ ++ 2005-05-05 ++ PHP License ++ * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. ++* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. ++* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. ++* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. ++ ++ ++ ++ 1.3.0RC1 ++ 1.3.0 ++ ++ ++ beta ++ beta ++ ++ 2005-04-07 ++ PHP License ++ * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. ++* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. ++* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. ++* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. ++* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. ++* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. ++ ++ ++ ++ 1.2.2 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-03-07 ++ PHP License ++ * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. ++ ++ ++ ++ 1.2.1 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-03-01 ++ PHP License ++ * Add isset() check before examining the dispatch map. Bug 3658. ++ ++ ++ ++ 1.2.0 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-02-27 ++ PHP License ++ * Provide the "stable" release. ++* Add package2.xml for compatibility with PEAR 1.4.0. ++* For changes since 1.1.0, see the changelogs for the various RC releases. ++ ++ ++ ++ 1.2.0RC7 ++ 1.2.0RC7 ++ ++ ++ beta ++ beta ++ ++ 2005-02-22 ++ PHP License ++ * Add the setSendEncoding() method and $send_encoding ++ property to XML_RPC_Message. Request 3537. ++* Allow class methods to be mapped using either syntax: ++ 'function' => 'hello::sayHello', ++ or ++ 'function' => array('hello', 'sayhello'), ++ Bug 3363. ++* Use 8192 instead of 32768 for bytes in fread() ++ in parseResponseFile(). Bug 3340. ++ ++ ++ ++ 1.2.0RC6 ++ 1.2.0RC6 ++ ++ ++ beta ++ beta ++ ++ 2005-01-25 ++ PHP License ++ * Don't put the protocol in the Host field of the POST data. (danielc) ++ ++ ++ ++ 1.2.0RC5 ++ 1.2.0RC5 ++ ++ ++ beta ++ beta ++ ++ 2005-01-24 ++ PHP License ++ * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. ++ ++ ++ ++ 1.2.0RC4 ++ 1.2.0RC4 ++ ++ ++ beta ++ beta ++ ++ 2005-01-24 ++ PHP License ++ * When a connection attempt fails, have the method return 0. (danielc) ++* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) ++* Add tests for setting the client properties. (danielc) ++* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) ++* Bundle the tests with the package. (danielc) ++ ++ ++ ++ 1.2.0RC3 ++ 1.2.0RC3 ++ ++ ++ beta ++ beta ++ ++ 2005-01-19 ++ PHP License ++ * ssl uses port 443, not 445. ++ ++ ++ ++ 1.2.0RC2 ++ 1.2.0RC2 ++ ++ ++ beta ++ beta ++ ++ 2005-01-11 ++ PHP License ++ * Handle ssl:// in the $server string. (danielc) ++* Also default to port 445 for ssl:// requests as well. (danielc) ++* Enhance debugging in the server. (danielc) ++ ++ ++ ++ 1.2.0RC1 ++ 1.2.0RC1 ++ ++ ++ beta ++ beta ++ ++ 2004-12-30 ++ PHP License ++ * Make things work with SSL. Bug 2489. (nkukard lbsd net) ++* Allow array function callbacks (Matt Kane) ++* Some minor speed-ups (Matt Kane) ++* Add Dump.php to the package (Christian Weiske) ++* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) ++* Silence fsockopen() errors. Bug 1714. (danielc) ++* Encode empty arrays as an array. Bug 1493. (danielc) ++* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) ++* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) ++* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) ++* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) ++* Allow raiseError() to be called statically. (danielc) ++* Stop double escaping of character entities. Bug 987. (danielc) ++ NOTICE: the following have been removed: ++ * XML_RPC_dh() ++ * $GLOBALS['XML_RPC_entities'] ++ * XML_RPC_entity_decode() ++ * XML_RPC_lookup_entity() ++* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) ++ ++ ++ ++ 1.1.0 ++ 1.1.0 ++ ++ ++ stable ++ stable ++ ++ 2004-03-15 ++ PHP License ++ * Added support for sequential arrays to XML_RPC_encode() (mroch) ++* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) ++* Remove "require_once 'PEAR.php'", include only when needed to raise an error ++* Replace echo and error_log() with raiseError() (mroch) ++* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) ++* be tolerant of junk after methodResponse (Luca Mariano, mroch) ++* Silent notice even in the error log (pierre) ++* fix include of shared xml extension on win32 (pierre) ++ ++ ++ ++ 1.0.4 ++ 1.0.4 ++ ++ ++ stable ++ stable ++ ++ 2002-10-02 ++ PHP License ++ * added HTTP proxy authorization support (thanks to Arnaud Limbourg) ++ ++ ++ ++ 1.0.3 ++ 1.0.3 ++ ++ ++ stable ++ stable ++ ++ 2002-05-19 ++ PHP License ++ * fix bug when parsing responses with boolean types ++ ++ ++ ++ 1.0.2 ++ 1.0.2 ++ ++ ++ stable ++ stable ++ ++ 2002-04-16 ++ PHP License ++ * E_ALL fixes ++* fix HTTP response header parsing ++ ++ ++ ++ 1.0.1 ++ 1.0.1 ++ ++ ++ stable ++ stable ++ ++ 2001-09-25 ++ PHP License ++ This is a PEAR-ified version of Useful Inc's 1.0.1 release. ++Includes an urgent security fix identified by Dan Libby <dan@libby.com>. ++ ++ ++ ++XML_RPC-1.3.1/tests/protoport.php100644 1750 144 25543 10260516576 12042 ++ * @copyright 2005 The PHP Group ++ * @license http://www.php.net/license/3_0.txt PHP License ++ * @version CVS: $Id: protoport.php,v 1.4 2005/01/24 17:48:47 danielc Exp $ ++ * @link http://pear.php.net/package/XML_RPC ++ * @since File available since Release 1.2 ++ */ ++ ++/* ++ * If the package version number is found in the left hand ++ * portion of the if() expression below, that means this file has ++ * come from the PEAR installer. Therefore, let's test the ++ * installed version of XML_RPC which should be in the include path. ++ * ++ * If the version has not been substituted in the if() expression, ++ * this file has likely come from a CVS checkout or a .tar file. ++ * Therefore, we'll assume the tests should use the version of ++ * XML_RPC that has come from there as well. ++ */ ++if ('1.3.1' != '@'.'package_version'.'@') { ++ /** ++ * Get the needed class from the PEAR installation ++ */ ++ require_once 'XML/RPC.php'; ++} else { ++ /** ++ * Get the needed class from the parent directory ++ */ ++ require_once '../RPC.php'; ++} ++ ++/** ++ * Compare the test result to the expected result ++ * ++ * If the test fails, echo out the results. ++ * ++ * @param array $expect the array of object properties you expect ++ * from the test ++ * @param object $actual the object results from the test ++ * @param string $test_name the name of the test ++ * ++ * @return void ++ */ ++function compare($expect, $actual, $test_name) { ++ $actual = get_object_vars($actual); ++ if (count(array_diff($actual, $expect))) { ++ echo "$test_name failed.\nExpect: "; ++ print_r($expect); ++ echo "Actual: "; ++ print_r($actual); ++ echo "\n"; ++ } ++} ++ ++if (php_sapi_name() != 'cli') { ++ echo "
\n";
++}
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver');
++compare($x, $c, 'defaults');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver');
++compare($x, $c, 'defaults with http');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver');
++compare($x, $c, 'defaults with https');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver');
++compare($x, $c, 'defaults with ssl');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 65);
++compare($x, $c, 'port 65');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 65);
++compare($x, $c, 'port 65 with http');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 65);
++compare($x, $c, 'port 65 with https');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65);
++compare($x, $c, 'port 65 with ssl');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 0,
++                        'theproxy');
++compare($x, $c, 'defaults proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 0,
++                        'http://theproxy');
++compare($x, $c, 'defaults with http proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 0,
++                        'https://theproxy');
++compare($x, $c, 'defaults with https proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 0,
++                        'ssl://theproxy');
++compare($x, $c, 'defaults with ssl proxy');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 65,
++                        'theproxy', 6565);
++compare($x, $c, 'port 65 proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 65,
++                        'http://theproxy', 6565);
++compare($x, $c, 'port 65 with http proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 65,
++                        'https://theproxy', 6565);
++compare($x, $c, 'port 65 with https proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65,
++                        'ssl://theproxy', 6565);
++compare($x, $c, 'port 65 with ssl proxy 6565');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 443,
++                        'theproxy', 443);
++compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 0,
++                        'ssl://theproxy', 6565);
++compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
++XML_RPC-1.3.1/tests/test_Dump.php100644   1750    144        3042 10260516576  11704 new XML_RPC_Value('das ist der Titel', 'string'),
++    'startDate'=>new XML_RPC_Value(mktime(0,0,0,13,11,2004), 'dateTime.iso8601'),
++    'endDate'  =>new XML_RPC_Value(mktime(0,0,0,15,11,2004), 'dateTime.iso8601'),
++    'error'    =>'string',
++    'arkey'    => new XML_RPC_Value( array(
++        new XML_RPC_Value('simple string'),
++        new XML_RPC_Value(12345, 'int')
++        ), 'array')
++    )
++    ,'struct');
++
++XML_RPC_Dump($val);
++
++echo '==============' . "\r\n";
++$val2 = new XML_RPC_Value(44353, 'int');
++XML_RPC_Dump($val2);
++
++echo '==============' . "\r\n";
++$val3 = new XML_RPC_Value('this should be a string', 'string');
++XML_RPC_Dump($val3);
++
++echo '==============' . "\r\n";
++$val4 = new XML_RPC_Value(true, 'boolean');
++XML_RPC_Dump($val4);
++XML_RPC-1.3.1/Dump.php100644   1750    144       12074 10260516576   7530 
++ * @version    CVS: $Id: Dump.php,v 1.7 2005/01/24 03:47:55 danielc Exp $
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++
++
++/**
++ * Pull in the XML_RPC class
++ */
++require_once 'XML/RPC.php';
++
++
++/**
++ * Generates the dump of the XML_RPC_Value and echoes it
++ *
++ * @param object $value  the XML_RPC_Value object to dump
++ *
++ * @return void
++ */
++function XML_RPC_Dump($value)
++{
++    $dumper = new XML_RPC_Dump();
++    echo $dumper->generateDump($value);
++}
++
++
++/**
++ * Class which generates a dump of a XML_RPC_Value object
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Christian Weiske 
++ * @version    Release: 1.3.1
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Dump
++{
++    /**
++     * The indentation array cache
++     * @var array
++     */
++    var $arIndent      = array();
++
++    /**
++     * The spaces used for indenting the XML
++     * @var string
++     */
++    var $strBaseIndent = '    ';
++
++    /**
++     * Returns the dump in XML format without printing it out
++     *
++     * @param object $value   the XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  the dump
++     */
++    function generateDump($value, $nLevel = 0)
++    {
++        if (!is_object($value) && get_class($value) != 'xml_rpc_value') {
++            require_once 'PEAR.php';
++            PEAR::raiseError('Tried to dump non-XML_RPC_Value variable' . "\r\n",
++                             0, PEAR_ERROR_PRINT);
++            if (is_object($value)) {
++                $strType = get_class($value);
++            } else {
++                $strType = gettype($value);
++            }
++            return $this->getIndent($nLevel) . 'NOT A XML_RPC_Value: '
++                   . $strType . "\r\n";
++        }
++
++        switch ($value->kindOf()) {
++        case 'struct':
++            $ret = $this->genStruct($value, $nLevel);
++            break;
++        case 'array':
++            $ret = $this->genArray($value, $nLevel);
++            break;
++        case 'scalar':
++            $ret = $this->genScalar($value->scalarval(), $nLevel);
++            break;
++        default:
++            require_once 'PEAR.php';
++            PEAR::raiseError('Illegal type "' . $value->kindOf()
++                             . '" in XML_RPC_Value' . "\r\n", 0,
++                             PEAR_ERROR_PRINT);
++        }
++
++        return $ret;
++    }
++
++    /**
++     * Returns the scalar value dump
++     *
++     * @param object $value   the scalar XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genScalar($value, $nLevel)
++    {
++        if (gettype($value) == 'object') {
++            $strClass = ' ' . get_class($value);
++        } else {
++            $strClass = '';
++        }
++        return $this->getIndent($nLevel) . gettype($value) . $strClass
++               . ' ' . $value . "\r\n";
++    }
++
++    /**
++     * Returns the dump of a struct
++     *
++     * @param object $value   the struct XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genStruct($value, $nLevel)
++    {
++        $value->structreset();
++        $strOutput = $this->getIndent($nLevel) . 'struct' . "\r\n";
++        while (list($key, $keyval) = $value->structeach()) {
++            $strOutput .= $this->getIndent($nLevel + 1) . $key . "\r\n";
++            $strOutput .= $this->generateDump($keyval, $nLevel + 2);
++        }
++        return $strOutput;
++    }
++
++    /**
++     * Returns the dump of an array
++     *
++     * @param object $value   the array XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genArray($value, $nLevel)
++    {
++        $nSize     = $value->arraysize();
++        $strOutput = $this->getIndent($nLevel) . 'array' . "\r\n";
++        for($nA = 0; $nA < $nSize; $nA++) {
++            $strOutput .= $this->getIndent($nLevel + 1) . $nA . "\r\n";
++            $strOutput .= $this->generateDump($value->arraymem($nA),
++                                              $nLevel + 2);
++        }
++        return $strOutput;
++    }
++
++    /**
++     * Returns the indent for a specific level and caches it for faster use
++     *
++     * @param int $nLevel  the level
++     *
++     * @return string  the indented string
++     */
++    function getIndent($nLevel)
++    {
++        if (!isset($this->arIndent[$nLevel])) {
++            $this->arIndent[$nLevel] = str_repeat($this->strBaseIndent, $nLevel);
++        }
++        return $this->arIndent[$nLevel];
++    }
++}
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * c-hanging-comment-ender-p: nil
++ * End:
++ */
++
++?>
++XML_RPC-1.3.1/RPC.php100644   1750    144      150065 10260516576   7272 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    CVS: $Id: RPC.php,v 1.74 2005/05/09 20:51:54 danielc Exp $
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++
++
++if (!function_exists('xml_parser_create')) {
++    PEAR::loadExtension('xml');
++}
++
++/**#@+
++ * Error constants
++ */
++/**
++ * Parameter values don't match parameter types
++ */
++define('XML_RPC_ERROR_INVALID_TYPE', 101);
++/**
++ * Parameter declared to be numeric but the values are not
++ */
++define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102);
++/**
++ * Communication error
++ */
++define('XML_RPC_ERROR_CONNECTION_FAILED', 103);
++/**
++ * The array or struct has already been started
++ */
++define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
++/**
++ * Incorrect parameters submitted
++ */
++define('XML_RPC_ERROR_INCORRECT_PARAMS', 105);
++/**
++ * Programming error by developer
++ */
++define('XML_RPC_ERROR_PROGRAMMING', 106);
++/**#@-*/
++
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_I4']
++ */
++$GLOBALS['XML_RPC_I4'] = 'i4';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Int']
++ */
++$GLOBALS['XML_RPC_Int'] = 'int';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Boolean']
++ */
++$GLOBALS['XML_RPC_Boolean'] = 'boolean';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Double']
++ */
++$GLOBALS['XML_RPC_Double'] = 'double';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_String']
++ */
++$GLOBALS['XML_RPC_String'] = 'string';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_DateTime']
++ */
++$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Base64']
++ */
++$GLOBALS['XML_RPC_Base64'] = 'base64';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Array']
++ */
++$GLOBALS['XML_RPC_Array'] = 'array';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Struct']
++ */
++$GLOBALS['XML_RPC_Struct'] = 'struct';
++
++
++/**
++ * Data type meta-types
++ * @global array $GLOBALS['XML_RPC_Types']
++ */
++$GLOBALS['XML_RPC_Types'] = array(
++    $GLOBALS['XML_RPC_I4']       => 1,
++    $GLOBALS['XML_RPC_Int']      => 1,
++    $GLOBALS['XML_RPC_Boolean']  => 1,
++    $GLOBALS['XML_RPC_String']   => 1,
++    $GLOBALS['XML_RPC_Double']   => 1,
++    $GLOBALS['XML_RPC_DateTime'] => 1,
++    $GLOBALS['XML_RPC_Base64']   => 1,
++    $GLOBALS['XML_RPC_Array']    => 2,
++    $GLOBALS['XML_RPC_Struct']   => 3,
++);
++
++
++/**
++ * Error message numbers
++ * @global array $GLOBALS['XML_RPC_err']
++ */
++$GLOBALS['XML_RPC_err'] = array(
++    'unknown_method'      => 1,
++    'invalid_return'      => 2,
++    'incorrect_params'    => 3,
++    'introspect_unknown'  => 4,
++    'http_error'          => 5,
++    'not_response_object' => 6,
++);
++
++/**
++ * Error message strings
++ * @global array $GLOBALS['XML_RPC_str']
++ */
++$GLOBALS['XML_RPC_str'] = array(
++    'unknown_method'      => 'Unknown method',
++    'invalid_return'      => 'Invalid return payload: enable debugging to examine incoming payload',
++    'incorrect_params'    => 'Incorrect parameters passed to method',
++    'introspect_unknown'  => 'Can\'t introspect: method unknown',
++    'http_error'          => 'Didn\'t receive 200 OK from remote server.',
++    'not_response_object' => 'The requested method didn\'t return an XML_RPC_Response object.',
++);
++
++
++/**
++ * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
++ * @global string $GLOBALS['XML_RPC_defencoding']
++ */
++$GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
++
++/**
++ * User error codes start at 800
++ * @global int $GLOBALS['XML_RPC_erruser']
++ */
++$GLOBALS['XML_RPC_erruser'] = 800;
++
++/**
++ * XML parse error codes start at 100
++ * @global int $GLOBALS['XML_RPC_errxml']
++ */
++$GLOBALS['XML_RPC_errxml'] = 100;
++
++
++/**
++ * Compose backslashes for escaping regexp
++ * @global string $GLOBALS['XML_RPC_backslash']
++ */
++$GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
++
++
++/**
++ * Stores state during parsing
++ *
++ * quick explanation of components:
++ *   + st     = builds up a string for evaluation
++ *   + ac     = accumulates values
++ *   + qt     = decides if quotes are needed for evaluation
++ *   + cm     = denotes struct or array (comma needed)
++ *   + isf    = indicates a fault
++ *   + lv     = indicates "looking for a value": implements the logic
++ *               to allow values with no types to be strings
++ *   + params = stores parameters in method calls
++ *   + method = stores method name
++ *
++ * @global array $GLOBALS['XML_RPC_xh']
++ */
++$GLOBALS['XML_RPC_xh'] = array();
++
++
++/**
++ * Start element handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_se($parser_resource, $name, $attrs)
++{
++    global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String;
++    $parser = (int) $parser_resource;
++
++    switch ($name) {
++    case 'STRUCT':
++    case 'ARRAY':
++        $XML_RPC_xh[$parser]['st'] .= 'array(';
++        $XML_RPC_xh[$parser]['cm']++;
++        // this last line turns quoting off
++        // this means if we get an empty array we'll
++        // simply get a bit of whitespace in the eval
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        break;
++
++    case 'NAME':
++        $XML_RPC_xh[$parser]['st'] .= '"';
++        $XML_RPC_xh[$parser]['ac'] = '';
++        break;
++
++    case 'FAULT':
++        $XML_RPC_xh[$parser]['isf'] = 1;
++        break;
++
++    case 'PARAM':
++        $XML_RPC_xh[$parser]['st'] = '';
++        break;
++
++    case 'VALUE':
++        $XML_RPC_xh[$parser]['st'] .= 'new XML_RPC_Value(';
++        $XML_RPC_xh[$parser]['lv'] = 1;
++        $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        // look for a value: if this is still 1 by the
++        // time we reach the first data segment then the type is string
++        // by implication and we need to add in a quote
++        break;
++
++    case 'I4':
++    case 'INT':
++    case 'STRING':
++    case 'BOOLEAN':
++    case 'DOUBLE':
++    case 'DATETIME.ISO8601':
++    case 'BASE64':
++        $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
++
++        if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
++            $XML_RPC_xh[$parser]['qt'] = 1;
++
++            if ($name == 'DATETIME.ISO8601') {
++                $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
++            }
++
++        } elseif ($name == 'BASE64') {
++            $XML_RPC_xh[$parser]['qt'] = 2;
++        } else {
++            // No quoting is required here -- but
++            // at the end of the element we must check
++            // for data format errors.
++            $XML_RPC_xh[$parser]['qt'] = 0;
++        }
++        break;
++
++    case 'MEMBER':
++        $XML_RPC_xh[$parser]['ac'] = '';
++    }
++
++    if ($name != 'VALUE') {
++        $XML_RPC_xh[$parser]['lv'] = 0;
++    }
++}
++
++/**
++ * End element handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_ee($parser_resource, $name)
++{
++    global $XML_RPC_xh, $XML_RPC_Types, $XML_RPC_String;
++    $parser = (int) $parser_resource;
++
++    switch ($name) {
++    case 'STRUCT':
++    case 'ARRAY':
++        if ($XML_RPC_xh[$parser]['cm']
++            && substr($XML_RPC_xh[$parser]['st'], -1) == ',')
++        {
++            $XML_RPC_xh[$parser]['st'] = substr($XML_RPC_xh[$parser]['st'], 0, -1);
++        }
++
++        $XML_RPC_xh[$parser]['st'] .= ')';
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++        $XML_RPC_xh[$parser]['cm']--;
++        break;
++
++    case 'NAME':
++        $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'] . '" => ';
++        break;
++
++    case 'BOOLEAN':
++        // special case here: we translate boolean 1 or 0 into PHP
++        // constants true or false
++        if ($XML_RPC_xh[$parser]['ac'] == '1') {
++            $XML_RPC_xh[$parser]['ac'] = 'true';
++        } else {
++            $XML_RPC_xh[$parser]['ac'] = 'false';
++        }
++
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++        // Drop through intentionally.
++
++    case 'I4':
++    case 'INT':
++    case 'STRING':
++    case 'DOUBLE':
++    case 'DATETIME.ISO8601':
++    case 'BASE64':
++        if ($XML_RPC_xh[$parser]['qt'] == 1) {
++            // we use double quotes rather than single so backslashification works OK
++            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
++        } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
++            $XML_RPC_xh[$parser]['st'] .= 'base64_decode("'
++                                        . $XML_RPC_xh[$parser]['ac'] . '")';
++        } elseif ($name == 'BOOLEAN') {
++            $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
++        } else {
++            // we have an I4, INT or a DOUBLE
++            // we must check that only 0123456789-. are characters here
++            if (!ereg("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
++                XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
++                                         XML_RPC_ERROR_NON_NUMERIC_FOUND);
++                $XML_RPC_xh[$parser]['st'] .= 'XML_RPC_ERROR_NON_NUMERIC_FOUND';
++            } else {
++                // it's ok, add it on
++                $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
++            }
++        }
++
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
++        break;
++
++    case 'VALUE':
++        // deal with a string value
++        if (strlen($XML_RPC_xh[$parser]['ac']) > 0 &&
++            $XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
++
++            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
++        }
++
++        // This if () detects if no scalar was inside 
++        // and pads an empty "".
++        if ($XML_RPC_xh[$parser]['st'][strlen($XML_RPC_xh[$parser]['st'])-1] == '(') {
++            $XML_RPC_xh[$parser]['st'] .= '""';
++        }
++        $XML_RPC_xh[$parser]['st'] .= ", '" . $XML_RPC_xh[$parser]['vt'] . "')";
++        if ($XML_RPC_xh[$parser]['cm']) {
++            $XML_RPC_xh[$parser]['st'] .= ',';
++        }
++        break;
++
++    case 'MEMBER':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        break;
++
++    case 'DATA':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        break;
++
++    case 'PARAM':
++        $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['st'];
++        break;
++
++    case 'METHODNAME':
++    case 'RPCMETHODNAME':
++        $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", '',
++                                                      $XML_RPC_xh[$parser]['ac']);
++        break;
++    }
++
++    // if it's a valid type name, set the type
++    if (isset($XML_RPC_Types[strtolower($name)])) {
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++    }
++}
++
++/**
++ * Character data handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_cd($parser_resource, $data)
++{
++    global $XML_RPC_xh, $XML_RPC_backslash;
++    $parser = (int) $parser_resource;
++
++    if ($XML_RPC_xh[$parser]['lv'] != 3) {
++        // "lookforvalue==3" means that we've found an entire value
++        // and should discard any further character data
++
++        if ($XML_RPC_xh[$parser]['lv'] == 1) {
++            // if we've found text and we're just in a  then
++            // turn quoting on, as this will be a string
++            $XML_RPC_xh[$parser]['qt'] = 1;
++            // and say we've found a value
++            $XML_RPC_xh[$parser]['lv'] = 2;
++        }
++
++        // replace characters that eval would
++        // do special things with
++        if (!isset($XML_RPC_xh[$parser]['ac'])) {
++            $XML_RPC_xh[$parser]['ac'] = '';
++        }
++        $XML_RPC_xh[$parser]['ac'] .= str_replace('$', '\$',
++            str_replace('"', '\"', str_replace(chr(92),
++            $XML_RPC_backslash, $data)));
++    }
++}
++
++/**
++ * The common methods and properties for all of the XML_RPC classes
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.3.1
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Base {
++
++    /**
++     * PEAR Error handling
++     *
++     * @return object  PEAR_Error object
++     */
++    function raiseError($msg, $code)
++    {
++        include_once 'PEAR.php';
++        if (is_object(@$this)) {
++            return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
++        } else {
++            return PEAR::raiseError('XML_RPC: ' . $msg, $code);
++        }
++    }
++
++    /**
++     * Tell whether something is a PEAR_Error object
++     *
++     * @param mixed $value  the item to check
++     *
++     * @return bool  whether $value is a PEAR_Error object or not
++     *
++     * @access public
++     */
++    function isError($value)
++    {
++        return is_a($value, 'PEAR_Error');
++    }
++}
++
++/**
++ * The methods and properties for submitting XML RPC requests
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.3.1
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Client extends XML_RPC_Base {
++
++    /**
++     * The path and name of the RPC server script you want the request to go to
++     * @var string
++     */
++    var $path = '';
++
++    /**
++     * The name of the remote server to connect to
++     * @var string
++     */
++    var $server = '';
++
++    /**
++     * The protocol to use in contacting the remote server
++     * @var string
++     */
++    var $protocol = 'http://';
++
++    /**
++     * The port for connecting to the remote server
++     *
++     * The default is 80 for http:// connections
++     * and 443 for https:// and ssl:// connections.
++     *
++     * @var integer
++     */
++    var $port = 80;
++
++    /**
++     * A user name for accessing the RPC server
++     * @var string
++     * @see XML_RPC_Client::setCredentials()
++     */
++    var $username = '';
++
++    /**
++     * A password for accessing the RPC server
++     * @var string
++     * @see XML_RPC_Client::setCredentials()
++     */
++    var $password = '';
++
++    /**
++     * The name of the proxy server to use, if any
++     * @var string
++     */
++    var $proxy = '';
++
++    /**
++     * The protocol to use in contacting the proxy server, if any
++     * @var string
++     */
++    var $proxy_protocol = 'http://';
++
++    /**
++     * The port for connecting to the proxy server
++     *
++     * The default is 8080 for http:// connections
++     * and 443 for https:// and ssl:// connections.
++     *
++     * @var integer
++     */
++    var $proxy_port = 8080;
++
++    /**
++     * A user name for accessing the proxy server
++     * @var string
++     */
++    var $proxy_user = '';
++
++    /**
++     * A password for accessing the proxy server
++     * @var string
++     */
++    var $proxy_pass = '';
++
++    /**
++     * The error number, if any
++     * @var integer
++     */
++    var $errno = 0;
++
++    /**
++     * The error message, if any
++     * @var string
++     */
++    var $errstring = '';
++
++    /**
++     * The current debug mode (1 = on, 0 = off)
++     * @var integer
++     */
++    var $debug = 0;
++
++    /**
++     * The HTTP headers for the current request.
++     * @var string
++     */
++    var $headers = '';
++
++
++    /**
++     * Sets the object's properties
++     *
++     * @param string  $path        the path and name of the RPC server script
++     *                              you want the request to go to
++     * @param string  $server      the URL of the remote server to connect to.
++     *                              If this parameter doesn't specify a
++     *                              protocol and $port is 443, ssl:// is
++     *                              assumed.
++     * @param integer $port        a port for connecting to the remote server.
++     *                              Defaults to 80 for http:// connections and
++     *                              443 for https:// and ssl:// connections.
++     * @param string  $proxy       the URL of the proxy server to use, if any.
++     *                              If this parameter doesn't specify a
++     *                              protocol and $port is 443, ssl:// is
++     *                              assumed.
++     * @param integer $proxy_port  a port for connecting to the remote server.
++     *                              Defaults to 8080 for http:// connections and
++     *                              443 for https:// and ssl:// connections.
++     * @param string  $proxy_user  a user name for accessing the proxy server
++     * @param string  $proxy_pass  a password for accessing the proxy server
++     *
++     * @return void
++     */
++    function XML_RPC_Client($path, $server, $port = 0,
++                            $proxy = '', $proxy_port = 0,
++                            $proxy_user = '', $proxy_pass = '')
++    {
++        $this->path       = $path;
++        $this->proxy_user = $proxy_user;
++        $this->proxy_pass = $proxy_pass;
++
++        preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match);
++        if ($match[1] == '') {
++            if ($port == 443) {
++                $this->server   = $match[2];
++                $this->protocol = 'ssl://';
++                $this->port     = 443;
++            } else {
++                $this->server = $match[2];
++                if ($port) {
++                    $this->port = $port;
++                }
++            }
++        } elseif ($match[1] == 'http://') {
++            $this->server = $match[2];
++            if ($port) {
++                $this->port = $port;
++            }
++        } else {
++            $this->server   = $match[2];
++            $this->protocol = 'ssl://';
++            if ($port) {
++                $this->port = $port;
++            } else {
++                $this->port = 443;
++            }
++        }
++
++        if ($proxy) {
++            preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match);
++            if ($match[1] == '') {
++                if ($proxy_port == 443) {
++                    $this->proxy          = $match[2];
++                    $this->proxy_protocol = 'ssl://';
++                    $this->proxy_port     = 443;
++                } else {
++                    $this->proxy = $match[2];
++                    if ($proxy_port) {
++                        $this->proxy_port = $proxy_port;
++                    }
++                }
++            } elseif ($match[1] == 'http://') {
++                $this->proxy = $match[2];
++                if ($proxy_port) {
++                    $this->proxy_port = $proxy_port;
++                }
++            } else {
++                $this->proxy          = $match[2];
++                $this->proxy_protocol = 'ssl://';
++                if ($proxy_port) {
++                    $this->proxy_port = $proxy_port;
++                } else {
++                    $this->proxy_port = 443;
++                }
++            }
++        }
++    }
++
++    /**
++     * Change the current debug mode
++     *
++     * @param int $in  where 1 = on, 0 = off
++     *
++     * @return void
++     */
++    function setDebug($in)
++    {
++        if ($in) {
++            $this->debug = 1;
++        } else {
++            $this->debug = 0;
++        }
++    }
++
++    /**
++     * Set username and password properties for connecting to the RPC server
++     *
++     * @param string $u  the user name
++     * @param string $p  the password
++     *
++     * @return void
++     *
++     * @see XML_RPC_Client::$username, XML_RPC_Client::$password
++     */
++    function setCredentials($u, $p)
++    {
++        $this->username = $u;
++        $this->password = $p;
++    }
++
++    /**
++     * Transmit the RPC request via HTTP 1.0 protocol
++     *
++     * @param object $msg       the XML_RPC_Message object
++     * @param int    $timeout   how many seconds to wait for the request
++     *
++     * @return object  an XML_RPC_Response object.  0 is returned if any
++     *                  problems happen.
++     *
++     * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
++     *      XML_RPC_Client::setCredentials()
++     */
++    function send($msg, $timeout = 0)
++    {
++        if (strtolower(get_class($msg)) != 'xml_rpc_message') {
++            $this->errstr = 'send()\'s $msg parameter must be an'
++                          . ' XML_RPC_Message object.';
++            $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING);
++            return 0;
++        }
++        $msg->debug = $this->debug;
++        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
++                                        $timeout, $this->username,
++                                        $this->password);
++    }
++
++    /**
++     * Transmit the RPC request via HTTP 1.0 protocol
++     *
++     * Requests should be sent using XML_RPC_Client send() rather than
++     * calling this method directly.
++     *
++     * @param object $msg       the XML_RPC_Message object
++     * @param string $server    the server to send the request to
++     * @param int    $port      the server port send the request to
++     * @param int    $timeout   how many seconds to wait for the request
++     *                           before giving up
++     * @param string $username  a user name for accessing the RPC server
++     * @param string $password  a password for accessing the RPC server
++     *
++     * @return object  an XML_RPC_Response object.  0 is returned if any
++     *                  problems happen.
++     *
++     * @access protected
++     * @see XML_RPC_Client::send()
++     */
++    function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
++                               $username = '', $password = '')
++    {
++        /*
++         * If we're using a proxy open a socket to the proxy server
++         * instead to the xml-rpc server
++         */
++        if ($this->proxy) {
++            if ($this->proxy_protocol == 'http://') {
++                $protocol = '';
++            } else {
++                $protocol = $this->proxy_protocol;
++            }
++            if ($timeout > 0) {
++                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
++                                 $this->errno, $this->errstr, $timeout);
++            } else {
++                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
++                                 $this->errno, $this->errstr);
++            }
++        } else {
++            if ($this->protocol == 'http://') {
++                $protocol = '';
++            } else {
++                $protocol = $this->protocol;
++            }
++            if ($timeout > 0) {
++                $fp = @fsockopen($protocol . $server, $port,
++                                 $this->errno, $this->errstr, $timeout);
++            } else {
++                $fp = @fsockopen($protocol . $server, $port,
++                                 $this->errno, $this->errstr);
++            }
++        }
++
++        /*
++         * Just raising the error without returning it is strange,
++         * but keep it here for backwards compatibility.
++         */
++        if (!$fp && $this->proxy) {
++            $this->raiseError('Connection to proxy server '
++                              . $this->proxy . ':' . $this->proxy_port
++                              . ' failed. ' . $this->errstr,
++                              XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        } elseif (!$fp) {
++            $this->raiseError('Connection to RPC server '
++                              . $server . ':' . $port
++                              . ' failed. ' . $this->errstr,
++                              XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        }
++
++        if ($timeout) {
++            stream_set_timeout($fp, $timeout);
++        }
++
++        // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly
++        if ($username != $this->username) {
++            $this->setCredentials($username, $password);
++        }
++
++        // Only create the payload if it was not created previously
++        if (empty($msg->payload)) {
++            $msg->createPayload();
++        }
++        $this->createHeaders($msg);
++
++        $op  = $this->headers . "\r\n\r\n";
++        $op .= $msg->payload;
++
++        if (!fputs($fp, $op, strlen($op))) {
++            $this->errstr = 'Write error';
++            return 0;
++        }
++        $resp = $msg->parseResponseFile($fp);
++
++        $meta = stream_get_meta_data($fp);
++        if ($meta['timed_out']) {
++            fclose($fp);
++            $this->errstr = 'RPC server did not send response before timeout.';
++            $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        }
++
++        fclose($fp);
++        return $resp;
++    }
++
++    /**
++     * Determines the HTTP headers and puts it in the $headers property
++     *
++     * @param object $msg       the XML_RPC_Message object
++     *
++     * @return boolean  TRUE if okay, FALSE if the message payload isn't set.
++     *
++     * @access protected
++     */
++    function createHeaders($msg)
++    {
++        if (empty($msg->payload)) {
++            return false;
++        }
++        if ($this->proxy) {
++            $this->headers = 'POST ' . $this->protocol . $this->server;
++            if ($this->proxy_port) {
++                $this->headers .= ':' . $this->port;
++            }
++        } else {
++           $this->headers = 'POST ';
++        }
++        $this->headers .= $this->path. " HTTP/1.0\r\n";
++        
++        $this->headers .= "User-Agent: PEAR XML_RPC\r\n";
++        $this->headers .= 'Host: ' . $this->server . "\r\n";
++
++        if ($this->proxy && $this->proxy_user) {
++            $this->headers .= 'Proxy-Authorization: Basic '
++                     . base64_encode("$this->proxy_user:$this->proxy_pass")
++                     . "\r\n";
++        }
++
++        // thanks to Grant Rauscher  for this
++        if ($this->username) {
++            $this->headers .= 'Authorization: Basic '
++                     . base64_encode("$this->username:$this->password")
++                     . "\r\n";
++        }
++
++        $this->headers .= "Content-Type: text/xml\r\n";
++        $this->headers .= 'Content-Length: ' . strlen($msg->payload);
++        return true;
++    }
++}
++
++/**
++ * The methods and properties for interpreting responses to XML RPC requests
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.3.1
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Response extends XML_RPC_Base
++{
++    var $xv;
++    var $fn;
++    var $fs;
++    var $hdrs;
++
++    /**
++     * @return void
++     */
++    function XML_RPC_Response($val, $fcode = 0, $fstr = '')
++    {
++        if ($fcode != 0) {
++            $this->fn = $fcode;
++            $this->fs = htmlspecialchars($fstr);
++        } else {
++            $this->xv = $val;
++        }
++    }
++
++    /**
++     * @return int  the error code
++     */
++    function faultCode()
++    {
++        if (isset($this->fn)) {
++            return $this->fn;
++        } else {
++            return 0;
++        }
++    }
++
++    /**
++     * @return string  the error string
++     */
++    function faultString()
++    {
++        return $this->fs;
++    }
++
++    /**
++     * @return mixed  the value
++     */
++    function value()
++    {
++        return $this->xv;
++    }
++
++    /**
++     * @return string  the error message in XML format
++     */
++    function serialize()
++    {
++        $rs = "\n";
++        if ($this->fn) {
++            $rs .= "
++  
++    
++      
++        faultCode
++        " . $this->fn . "
++      
++      
++        faultString
++        " . $this->fs . "
++      
++    
++  
++";
++        } else {
++            $rs .= "\n\n" . $this->xv->serialize() .
++        "\n";
++        }
++        $rs .= "\n";
++        return $rs;
++    }
++}
++
++/**
++ * The methods and properties for composing XML RPC messages
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.3.1
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Message extends XML_RPC_Base
++{
++    /**
++     * The current debug mode (1 = on, 0 = off)
++     * @var integer
++     */
++    var $debug = 0;
++
++    /**
++     * The encoding to be used for outgoing messages
++     *
++     * Defaults to the value of $GLOBALS['XML_RPC_defencoding']
++     *
++     * @var string
++     * @see XML_RPC_Message::setSendEncoding(),
++     *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
++     */
++    var $send_encoding = '';
++
++    /**
++     * The method presently being evaluated
++     * @var string
++     */
++    var $methodname = '';
++
++    /**
++     * @var array
++     */
++    var $params = array();
++
++    /**
++     * The XML message being generated
++     * @var string
++     */
++    var $payload = '';
++
++    /**
++     * @return void
++     */
++    function XML_RPC_Message($meth, $pars = 0)
++    {
++        $this->methodname = $meth;
++        if (is_array($pars) && sizeof($pars) > 0) {
++            for ($i = 0; $i < sizeof($pars); $i++) {
++                $this->addParam($pars[$i]);
++            }
++        }
++    }
++
++    /**
++     * Produces the XML declaration including the encoding attribute
++     *
++     * The encoding is determined by this class' $send_encoding
++     * property.  If the $send_encoding property is not set, use
++     * $GLOBALS['XML_RPC_defencoding'].
++     *
++     * @return string  the XML declaration and  element
++     *
++     * @see XML_RPC_Message::setSendEncoding(),
++     *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
++     */
++    function xml_header()
++    {
++        global $XML_RPC_defencoding;
++        if (!$this->send_encoding) {
++            $this->send_encoding = $XML_RPC_defencoding;
++        }
++        return 'send_encoding . '"?>'
++               . "\n\n";
++    }
++
++    /**
++     * @return string  the closing  tag
++     */
++    function xml_footer()
++    {
++        return "\n";
++    }
++
++    /**
++     * @return void
++     *
++     * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
++     */
++    function createPayload()
++    {
++        $this->payload = $this->xml_header();
++        $this->payload .= '' . $this->methodname . "\n";
++        $this->payload .= "\n";
++        for ($i = 0; $i < sizeof($this->params); $i++) {
++            $p = $this->params[$i];
++            $this->payload .= "\n" . $p->serialize() . "\n";
++        }
++        $this->payload .= "\n";
++        $this->payload .= $this->xml_footer();
++        $this->payload = ereg_replace("[\r\n]+", "\r\n", $this->payload);
++    }
++
++    /**
++     * @return string  the name of the method
++     */
++    function method($meth = '')
++    {
++        if ($meth != '') {
++            $this->methodname = $meth;
++        }
++        return $this->methodname;
++    }
++
++    /**
++     * @return string  the payload
++     */
++    function serialize()
++    {
++        $this->createPayload();
++        return $this->payload;
++    }
++
++    /**
++     * @return void
++     */
++    function addParam($par)
++    {
++        $this->params[] = $par;
++    }
++
++    /**
++     * Obtains an XML_RPC_Value object for the given parameter
++     *
++     * @param int $i  the index number of the parameter to obtain
++     *
++     * @return object  the XML_RPC_Value object.
++     *                  If the parameter doesn't exist, an XML_RPC_Response object.
++     *
++     * @since Returns XML_RPC_Response object on error since Release 1.3.0
++     */
++    function getParam($i)
++    {
++        global $XML_RPC_err, $XML_RPC_str;
++
++        if (isset($this->params[$i])) {
++            return $this->params[$i];
++        } else {
++            $this->raiseError('The submitted request did not contain this parameter',
++                              XML_RPC_ERROR_INCORRECT_PARAMS);
++            return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
++                                        $XML_RPC_str['incorrect_params']);
++        }
++    }
++
++    /**
++     * @return int  the number of parameters
++     */
++    function getNumParams()
++    {
++        return sizeof($this->params);
++    }
++
++    /**
++     * Sets the XML declaration's encoding attribute
++     *
++     * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
++     *
++     * @return void
++     *
++     * @see XML_RPC_Message::$send_encoding, XML_RPC_Message::xml_header()
++     * @since Method available since Release 1.2.0
++     */
++    function setSendEncoding($type)
++    {
++        $this->send_encoding = $type;
++    }
++
++    /**
++     * Determine the XML's encoding via the encoding attribute
++     * in the XML declaration
++     *
++     * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
++     * or US-ASCII, $XML_RPC_defencoding will be returned.
++     *
++     * @param string $data  the XML that will be parsed
++     *
++     * @return string  the encoding to be used
++     *
++     * @link   http://php.net/xml_parser_create
++     * @since  Method available since Release 1.2.0
++     */
++    function getEncoding($data)
++    {
++        global $XML_RPC_defencoding;
++
++        if (preg_match('/<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]/i',
++                       $data, $match))
++        {
++            $match[1] = trim(strtoupper($match[1]));
++            switch ($match[1]) {
++                case 'ISO-8859-1':
++                case 'UTF-8':
++                case 'US-ASCII':
++                    return $match[1];
++                    break;
++
++                default:
++                    return $XML_RPC_defencoding;
++            }
++        } else {
++            return $XML_RPC_defencoding;
++        }
++    }
++
++    /**
++     * @return object  a new XML_RPC_Response object
++     */
++    function parseResponseFile($fp)
++    {
++        $ipd = '';
++        while ($data = @fread($fp, 8192)) {
++            $ipd .= $data;
++        }
++        return $this->parseResponse($ipd);
++    }
++
++    /**
++     * @return object  a new XML_RPC_Response object
++     */
++    function parseResponse($data = '')
++    {
++        global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
++
++        $encoding = $this->getEncoding($data);
++        $parser_resource = xml_parser_create($encoding);
++        $parser = (int) $parser_resource;
++
++        $XML_RPC_xh[$parser] = array();
++
++        $XML_RPC_xh[$parser]['st'] = '';
++        $XML_RPC_xh[$parser]['cm'] = 0;
++        $XML_RPC_xh[$parser]['isf'] = 0;
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = '';
++
++        xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
++        xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
++        xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
++
++        $hdrfnd = 0;
++        if ($this->debug) {
++            print "
---GOT---\n";
++            print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
++            print "\n---END---\n
"; ++ } ++ ++ // See if response is a 200 or a 100 then a 200, else raise error. ++ // But only do this if we're using the HTTP protocol. ++ if (ereg('^HTTP', $data) && ++ !ereg('^HTTP/[0-9\.]+ 200 ', $data) && ++ !preg_match('@^HTTP/[0-9\.]+ 10[0-9]([A-Za-z ]+)?[\r\n]+HTTP/[0-9\.]+ 200@', $data)) ++ { ++ $errstr = substr($data, 0, strpos($data, "\n") - 1); ++ error_log('HTTP error, got response: ' . $errstr); ++ $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], ++ $XML_RPC_str['http_error'] . ' (' . ++ $errstr . ')'); ++ xml_parser_free($parser_resource); ++ return $r; ++ } ++ // gotta get rid of headers here ++ ++ ++ if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) { ++ $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos); ++ $data = substr($data, $brpos + 4); ++ $hdrfnd = 1; ++ } ++ ++ /* ++ * be tolerant of junk after methodResponse ++ * (e.g. javascript automatically inserted by free hosts) ++ * thanks to Luca Mariano ++ */ ++ $data = substr($data, 0, strpos($data, "") + 17); ++ ++ if (!xml_parse($parser_resource, $data, sizeof($data))) { ++ // thanks to Peter Kocks ++ if (xml_get_current_line_number($parser_resource) == 1) { ++ $errstr = 'XML error at line 1, check URL'; ++ } else { ++ $errstr = sprintf('XML error: %s at line %d', ++ xml_error_string(xml_get_error_code($parser_resource)), ++ xml_get_current_line_number($parser_resource)); ++ } ++ error_log($errstr); ++ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], ++ $XML_RPC_str['invalid_return']); ++ xml_parser_free($parser_resource); ++ return $r; ++ } ++ xml_parser_free($parser_resource); ++ if ($this->debug) { ++ print '
---EVALING---[' .
++            strlen($XML_RPC_xh[$parser]['st']) . " chars]---\n" .
++            htmlspecialchars($XML_RPC_xh[$parser]['st']) . ";\n---END---
"; ++ } ++ if (strlen($XML_RPC_xh[$parser]['st']) == 0) { ++ // then something odd has happened ++ // and it's time to generate a client side error ++ // indicating something odd went on ++ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], ++ $XML_RPC_str['invalid_return']); ++ } else { ++ eval('$v=' . $XML_RPC_xh[$parser]['st'] . '; $allOK=1;'); ++ if ($XML_RPC_xh[$parser]['isf']) { ++ $f = $v->structmem('faultCode'); ++ $fs = $v->structmem('faultString'); ++ $r = new XML_RPC_Response($v, $f->scalarval(), ++ $fs->scalarval()); ++ } else { ++ $r = new XML_RPC_Response($v); ++ } ++ } ++ $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]); ++ return $r; ++ } ++} ++ ++/** ++ * The methods and properties that represent data in XML RPC format ++ * ++ * @category Web Services ++ * @package XML_RPC ++ * @author Edd Dumbill ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version Release: 1.3.1 ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++class XML_RPC_Value extends XML_RPC_Base ++{ ++ var $me = array(); ++ var $mytype = 0; ++ ++ /** ++ * @return void ++ */ ++ function XML_RPC_Value($val = -1, $type = '') ++ { ++ global $XML_RPC_Types; ++ $this->me = array(); ++ $this->mytype = 0; ++ if ($val != -1 || $type != '') { ++ if ($type == '') { ++ $type = 'string'; ++ } ++ if (!array_key_exists($type, $XML_RPC_Types)) { ++ // XXX ++ // need some way to report this error ++ } elseif ($XML_RPC_Types[$type] == 1) { ++ $this->addScalar($val, $type); ++ } elseif ($XML_RPC_Types[$type] == 2) { ++ $this->addArray($val); ++ } elseif ($XML_RPC_Types[$type] == 3) { ++ $this->addStruct($val); ++ } ++ } ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addScalar($val, $type = 'string') ++ { ++ global $XML_RPC_Types, $XML_RPC_Boolean; ++ ++ if ($this->mytype == 1) { ++ $this->raiseError('Scalar can have only one value', ++ XML_RPC_ERROR_INVALID_TYPE); ++ return 0; ++ } ++ $typeof = $XML_RPC_Types[$type]; ++ if ($typeof != 1) { ++ $this->raiseError("Not a scalar type (${typeof})", ++ XML_RPC_ERROR_INVALID_TYPE); ++ return 0; ++ } ++ ++ if ($type == $XML_RPC_Boolean) { ++ if (strcasecmp($val, 'true') == 0 ++ || $val == 1 ++ || ($val == true && strcasecmp($val, 'false'))) ++ { ++ $val = 1; ++ } else { ++ $val = 0; ++ } ++ } ++ ++ if ($this->mytype == 2) { ++ // we're adding to an array here ++ $ar = $this->me['array']; ++ $ar[] = new XML_RPC_Value($val, $type); ++ $this->me['array'] = $ar; ++ } else { ++ // a scalar, so set the value and remember we're scalar ++ $this->me[$type] = $val; ++ $this->mytype = $typeof; ++ } ++ return 1; ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addArray($vals) ++ { ++ global $XML_RPC_Types; ++ if ($this->mytype != 0) { ++ $this->raiseError( ++ 'Already initialized as a [' . $this->kindOf() . ']', ++ XML_RPC_ERROR_ALREADY_INITIALIZED); ++ return 0; ++ } ++ $this->mytype = $XML_RPC_Types['array']; ++ $this->me['array'] = $vals; ++ return 1; ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addStruct($vals) ++ { ++ global $XML_RPC_Types; ++ if ($this->mytype != 0) { ++ $this->raiseError( ++ 'Already initialized as a [' . $this->kindOf() . ']', ++ XML_RPC_ERROR_ALREADY_INITIALIZED); ++ return 0; ++ } ++ $this->mytype = $XML_RPC_Types['struct']; ++ $this->me['struct'] = $vals; ++ return 1; ++ } ++ ++ /** ++ * @return void ++ */ ++ function dump($ar) ++ { ++ reset($ar); ++ foreach ($ar as $key => $val) { ++ echo "$key => $val
"; ++ if ($key == 'array') { ++ foreach ($val as $key2 => $val2) { ++ echo "-- $key2 => $val2
"; ++ } ++ } ++ } ++ } ++ ++ /** ++ * @return string the data type of the current value ++ */ ++ function kindOf() ++ { ++ switch ($this->mytype) { ++ case 3: ++ return 'struct'; ++ ++ case 2: ++ return 'array'; ++ ++ case 1: ++ return 'scalar'; ++ ++ default: ++ return 'undef'; ++ } ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serializedata($typ, $val) ++ { ++ $rs = ''; ++ global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean; ++ if (!array_key_exists($typ, $XML_RPC_Types)) { ++ // XXX ++ // need some way to report this error ++ return; ++ } ++ switch ($XML_RPC_Types[$typ]) { ++ case 3: ++ // struct ++ $rs .= "\n"; ++ reset($val); ++ foreach ($val as $key2 => $val2) { ++ $rs .= "${key2}\n"; ++ $rs .= $this->serializeval($val2); ++ $rs .= "\n"; ++ } ++ $rs .= ''; ++ break; ++ ++ case 2: ++ // array ++ $rs .= "\n\n"; ++ for ($i = 0; $i < sizeof($val); $i++) { ++ $rs .= $this->serializeval($val[$i]); ++ } ++ $rs .= "\n"; ++ break; ++ ++ case 1: ++ switch ($typ) { ++ case $XML_RPC_Base64: ++ $rs .= "<${typ}>" . base64_encode($val) . ""; ++ break; ++ case $XML_RPC_Boolean: ++ $rs .= "<${typ}>" . ($val ? '1' : '0') . ""; ++ break; ++ case $XML_RPC_String: ++ $rs .= "<${typ}>" . htmlspecialchars($val). ""; ++ break; ++ default: ++ $rs .= "<${typ}>${val}"; ++ } ++ } ++ return $rs; ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serialize() ++ { ++ return $this->serializeval($this); ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serializeval($o) ++ { ++ $rs = ''; ++ $ar = $o->me; ++ reset($ar); ++ list($typ, $val) = each($ar); ++ $rs .= ''; ++ $rs .= $this->serializedata($typ, $val); ++ $rs .= "\n"; ++ return $rs; ++ } ++ ++ /** ++ * @return mixed the contents of the element requested ++ */ ++ function structmem($m) ++ { ++ return $this->me['struct'][$m]; ++ } ++ ++ /** ++ * @return void ++ */ ++ function structreset() ++ { ++ reset($this->me['struct']); ++ } ++ ++ /** ++ * @return the key/value pair of the struct's current element ++ */ ++ function structeach() ++ { ++ return each($this->me['struct']); ++ } ++ ++ /** ++ * @return mixed the current value ++ */ ++ function getval() ++ { ++ // UNSTABLE ++ global $XML_RPC_BOOLEAN, $XML_RPC_Base64; ++ ++ reset($this->me); ++ $b = current($this->me); ++ ++ // contributed by I Sofer, 2001-03-24 ++ // add support for nested arrays to scalarval ++ // i've created a new method here, so as to ++ // preserve back compatibility ++ ++ if (is_array($b)) { ++ foreach ($b as $id => $cont) { ++ $b[$id] = $cont->scalarval(); ++ } ++ } ++ ++ // add support for structures directly encoding php objects ++ if (is_object($b)) { ++ $t = get_object_vars($b); ++ foreach ($t as $id => $cont) { ++ $t[$id] = $cont->scalarval(); ++ } ++ foreach ($t as $id => $cont) { ++ eval('$b->'.$id.' = $cont;'); ++ } ++ } ++ ++ // end contrib ++ return $b; ++ } ++ ++ /** ++ * @return mixed ++ */ ++ function scalarval() ++ { ++ global $XML_RPC_Boolean, $XML_RPC_Base64; ++ reset($this->me); ++ return current($this->me); ++ } ++ ++ /** ++ * @return string ++ */ ++ function scalartyp() ++ { ++ global $XML_RPC_I4, $XML_RPC_Int; ++ reset($this->me); ++ $a = key($this->me); ++ if ($a == $XML_RPC_I4) { ++ $a = $XML_RPC_Int; ++ } ++ return $a; ++ } ++ ++ /** ++ * @return mixed the struct's current element ++ */ ++ function arraymem($m) ++ { ++ return $this->me['array'][$m]; ++ } ++ ++ /** ++ * @return int the number of elements in the array ++ */ ++ function arraysize() ++ { ++ reset($this->me); ++ list($a, $b) = each($this->me); ++ return sizeof($b); ++ } ++ ++ /** ++ * Determines if the item submitted is an XML_RPC_Value object ++ * ++ * @param mixed $val the variable to be evaluated ++ * ++ * @return bool TRUE if the item is an XML_RPC_Value object ++ * ++ * @static ++ * @since Method available since Release 1.3.0 ++ */ ++ function isValue($val) ++ { ++ return (strtolower(get_class($val)) == 'xml_rpc_value'); ++ } ++} ++ ++/** ++ * Return an ISO8601 encoded string ++ * ++ * While timezones ought to be supported, the XML-RPC spec says: ++ * ++ * "Don't assume a timezone. It should be specified by the server in its ++ * documentation what assumptions it makes about timezones." ++ * ++ * This routine always assumes localtime unless $utc is set to 1, in which ++ * case UTC is assumed and an adjustment for locale is made when encoding. ++ * ++ * @return string the formatted date ++ */ ++function XML_RPC_iso8601_encode($timet, $utc = 0) ++{ ++ if (!$utc) { ++ $t = strftime('%Y%m%dT%H:%M:%S', $timet); ++ } else { ++ if (function_exists('gmstrftime')) { ++ // gmstrftime doesn't exist in some versions ++ // of PHP ++ $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); ++ } else { ++ $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); ++ } ++ } ++ return $t; ++} ++ ++/** ++ * Convert a datetime string into a Unix timestamp ++ * ++ * While timezones ought to be supported, the XML-RPC spec says: ++ * ++ * "Don't assume a timezone. It should be specified by the server in its ++ * documentation what assumptions it makes about timezones." ++ * ++ * This routine always assumes localtime unless $utc is set to 1, in which ++ * case UTC is assumed and an adjustment for locale is made when encoding. ++ * ++ * @return int the unix timestamp of the date submitted ++ */ ++function XML_RPC_iso8601_decode($idate, $utc = 0) ++{ ++ $t = 0; ++ if (ereg('([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})', $idate, $regs)) { ++ if ($utc) { ++ $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); ++ } else { ++ $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); ++ } ++ } ++ return $t; ++} ++ ++/** ++ * Converts an XML_RPC_Value object into native PHP types ++ * ++ * @param object $XML_RPC_val the XML_RPC_Value object to decode ++ * ++ * @return mixed the PHP values ++ */ ++function XML_RPC_decode($XML_RPC_val) ++{ ++ $kind = $XML_RPC_val->kindOf(); ++ ++ if ($kind == 'scalar') { ++ return $XML_RPC_val->scalarval(); ++ ++ } elseif ($kind == 'array') { ++ $size = $XML_RPC_val->arraysize(); ++ $arr = array(); ++ for ($i = 0; $i < $size; $i++) { ++ $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i)); ++ } ++ return $arr; ++ ++ } elseif ($kind == 'struct') { ++ $XML_RPC_val->structreset(); ++ $arr = array(); ++ while (list($key, $value) = $XML_RPC_val->structeach()) { ++ $arr[$key] = XML_RPC_decode($value); ++ } ++ return $arr; ++ } ++} ++ ++/** ++ * Converts native PHP types into an XML_RPC_Value object ++ * ++ * @param mixed $php_val the PHP value or variable you want encoded ++ * ++ * @return object the XML_RPC_Value object ++ */ ++function XML_RPC_encode($php_val) ++{ ++ global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double, $XML_RPC_String, ++ $XML_RPC_Array, $XML_RPC_Struct; ++ ++ $type = gettype($php_val); ++ $XML_RPC_val = new XML_RPC_Value; ++ ++ switch ($type) { ++ case 'array': ++ if (empty($php_val)) { ++ $XML_RPC_val->addArray($php_val); ++ break; ++ } ++ $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); ++ if (empty($tmp)) { ++ $arr = array(); ++ foreach ($php_val as $k => $v) { ++ $arr[$k] = XML_RPC_encode($v); ++ } ++ $XML_RPC_val->addArray($arr); ++ break; ++ } ++ // fall though if it's not an enumerated array ++ ++ case 'object': ++ $arr = array(); ++ foreach ($php_val as $k => $v) { ++ $arr[$k] = XML_RPC_encode($v); ++ } ++ $XML_RPC_val->addStruct($arr); ++ break; ++ ++ case 'integer': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Int); ++ break; ++ ++ case 'double': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Double); ++ break; ++ ++ case 'string': ++ case 'NULL': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_String); ++ break; ++ ++ case 'boolean': ++ // Add support for encoding/decoding of booleans, since they ++ // are supported in PHP ++ // by ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean); ++ break; ++ ++ case 'unknown type': ++ default: ++ $XML_RPC_val = false; ++ } ++ return $XML_RPC_val; ++} ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * c-hanging-comment-ender-p: nil ++ * End: ++ */ ++ ++?> ++XML_RPC-1.3.1/Server.php100644 1750 144 47770 10260516576 10104 ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version CVS: $Id: Server.php,v 1.26 2005/05/09 21:39:47 danielc Exp $ ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++ ++ ++/** ++ * Pull in the XML_RPC class ++ */ ++require_once 'XML/RPC.php'; ++ ++ ++/** ++ * signature for system.listMethods: return = array, ++ * parameters = a string or nothing ++ * @global array $GLOBALS['XML_RPC_Server_listMethods_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_listMethods_sig'] = array( ++ array($GLOBALS['XML_RPC_Array'], ++ $GLOBALS['XML_RPC_String'] ++ ), ++ array($GLOBALS['XML_RPC_Array']) ++); ++ ++/** ++ * docstring for system.listMethods ++ * @global string $GLOBALS['XML_RPC_Server_listMethods_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_listMethods_doc'] = 'This method lists all the' ++ . ' methods that the XML-RPC server knows how to dispatch'; ++ ++/** ++ * signature for system.methodSignature: return = array, ++ * parameters = string ++ * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_methodSignature_sig'] = array( ++ array($GLOBALS['XML_RPC_Array'], ++ $GLOBALS['XML_RPC_String'] ++ ) ++); ++ ++/** ++ * docstring for system.methodSignature ++ * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_methodSignature_doc'] = 'Returns an array of known' ++ . ' signatures (an array of arrays) for the method name passed. If' ++ . ' no signatures are known, returns a none-array (test for type !=' ++ . ' array to detect missing signature)'; ++ ++/** ++ * signature for system.methodHelp: return = string, ++ * parameters = string ++ * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_methodHelp_sig'] = array( ++ array($GLOBALS['XML_RPC_String'], ++ $GLOBALS['XML_RPC_String'] ++ ) ++); ++ ++/** ++ * docstring for methodHelp ++ * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_methodHelp_doc'] = 'Returns help text if defined' ++ . ' for the method passed, otherwise returns an empty string'; ++ ++/** ++ * dispatch map for the automatically declared XML-RPC methods. ++ * @global array $GLOBALS['XML_RPC_Server_dmap'] ++ */ ++$GLOBALS['XML_RPC_Server_dmap'] = array( ++ 'system.listMethods' => array( ++ 'function' => 'XML_RPC_Server_listMethods', ++ 'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc'] ++ ), ++ 'system.methodHelp' => array( ++ 'function' => 'XML_RPC_Server_methodHelp', ++ 'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc'] ++ ), ++ 'system.methodSignature' => array( ++ 'function' => 'XML_RPC_Server_methodSignature', ++ 'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc'] ++ ) ++); ++ ++/** ++ * @global string $GLOBALS['XML_RPC_Server_debuginfo'] ++ */ ++$GLOBALS['XML_RPC_Server_debuginfo'] = ''; ++ ++ ++/** ++ * Lists all the methods that the XML-RPC server knows how to dispatch ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_listMethods($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $v = new XML_RPC_Value(); ++ $outAr = array(); ++ foreach ($server->dmap as $key => $val) { ++ $outAr[] = new XML_RPC_Value($key, 'string'); ++ } ++ foreach ($XML_RPC_Server_dmap as $key => $val) { ++ $outAr[] = new XML_RPC_Value($key, 'string'); ++ } ++ $v->addArray($outAr); ++ return new XML_RPC_Response($v); ++} ++ ++/** ++ * Returns an array of known signatures (an array of arrays) ++ * for the given method ++ * ++ * If no signatures are known, returns a none-array ++ * (test for type != array to detect missing signature) ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_methodSignature($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $methName = $m->getParam(0); ++ $methName = $methName->scalarval(); ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $server->dmap; ++ $sysCall = 0; ++ } ++ // print "\n"; ++ if (isset($dmap[$methName])) { ++ if ($dmap[$methName]['signature']) { ++ $sigs = array(); ++ $thesigs = $dmap[$methName]['signature']; ++ for ($i = 0; $i < sizeof($thesigs); $i++) { ++ $cursig = array(); ++ $inSig = $thesigs[$i]; ++ for ($j = 0; $j < sizeof($inSig); $j++) { ++ $cursig[] = new XML_RPC_Value($inSig[$j], 'string'); ++ } ++ $sigs[] = new XML_RPC_Value($cursig, 'array'); ++ } ++ $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array')); ++ } else { ++ $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string')); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], ++ $XML_RPC_str['introspect_unknown']); ++ } ++ return $r; ++} ++ ++/** ++ * Returns help text if defined for the method passed, otherwise returns ++ * an empty string ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_methodHelp($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $methName = $m->getParam(0); ++ $methName = $methName->scalarval(); ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $server->dmap; ++ $sysCall = 0; ++ } ++ // print "\n"; ++ if (isset($dmap[$methName])) { ++ if ($dmap[$methName]['docstring']) { ++ $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']), ++ 'string'); ++ } else { ++ $r = new XML_RPC_Response(new XML_RPC_Value('', 'string')); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], ++ $XML_RPC_str['introspect_unknown']); ++ } ++ return $r; ++} ++ ++/** ++ * @return void ++ */ ++function XML_RPC_Server_debugmsg($m) ++{ ++ global $XML_RPC_Server_debuginfo; ++ $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n"; ++} ++ ++ ++/** ++ * A server for receiving and replying to XML RPC requests ++ * ++ * ++ * $server = new XML_RPC_Server( ++ * array( ++ * 'isan8' => ++ * array( ++ * 'function' => 'is_8', ++ * 'signature' => ++ * array( ++ * array('boolean', 'int'), ++ * array('boolean', 'int', 'boolean'), ++ * array('boolean', 'string'), ++ * array('boolean', 'string', 'boolean'), ++ * ), ++ * 'docstring' => 'Is the value an 8?' ++ * ), ++ * ), ++ * 1, ++ * 0 ++ * ); ++ * ++ * ++ * @category Web Services ++ * @package XML_RPC ++ * @author Edd Dumbill ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version Release: 1.3.1 ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++class XML_RPC_Server ++{ ++ /** ++ * The dispatch map, listing the methods this server provides. ++ * @var array ++ */ ++ var $dmap = array(); ++ ++ /** ++ * The present response's encoding ++ * @var string ++ * @see XML_RPC_Message::getEncoding() ++ */ ++ var $encoding = ''; ++ ++ /** ++ * Debug mode (0 = off, 1 = on) ++ * @var integer ++ */ ++ var $debug = 0; ++ ++ /** ++ * The response's HTTP headers ++ * @var string ++ */ ++ var $server_headers = ''; ++ ++ /** ++ * The response's XML payload ++ * @var string ++ */ ++ var $server_payload = ''; ++ ++ ++ /** ++ * Constructor for the XML_RPC_Server class ++ * ++ * @param array $dispMap the dispatch map. An associative array ++ * explaining each function. The keys of the main ++ * array are the procedure names used by the ++ * clients. The value is another associative array ++ * that contains up to three elements: ++ * + The 'function' element's value is the name ++ * of the function or method that gets called. ++ * To define a class' method: 'class::method'. ++ * + The 'signature' element (optional) is an ++ * array describing the return values and ++ * parameters ++ * + The 'docstring' element (optional) is a ++ * string describing what the method does ++ * @param int $serviceNow should the HTTP response be sent now? ++ * (1 = yes, 0 = no) ++ * @param int $debug should debug output be displayed? ++ * (1 = yes, 0 = no) ++ * ++ * @return void ++ */ ++ function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) ++ { ++ global $HTTP_RAW_POST_DATA; ++ ++ if ($debug) { ++ $this->debug = 1; ++ } else { ++ $this->debug = 0; ++ } ++ ++ $this->dmap = $dispMap; ++ ++ if ($serviceNow) { ++ $this->service(); ++ } else { ++ $this->createServerPayload(); ++ $this->createServerHeaders(); ++ } ++ } ++ ++ /** ++ * @return string the debug information if debug debug mode is on ++ */ ++ function serializeDebug() ++ { ++ global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA; ++ ++ if ($this->debug) { ++ XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n" ++ . $HTTP_RAW_POST_DATA ++ . "\n" . '^^^ END POST DATA ^^^'); ++ } ++ ++ if ($XML_RPC_Server_debuginfo != '') { ++ return "\n"; ++ } else { ++ return ''; ++ } ++ } ++ ++ /** ++ * Sends the response ++ * ++ * The encoding and content-type are determined by ++ * XML_RPC_Message::getEncoding() ++ * ++ * @return void ++ * ++ * @uses XML_RPC_Server::createServerPayload(), ++ * XML_RPC_Server::createServerHeaders() ++ */ ++ function service() ++ { ++ $this->createServerPayload(); ++ $this->createServerHeaders(); ++ header($this->server_headers); ++ print $this->server_payload; ++ } ++ ++ /** ++ * Generates the payload and puts it in the $server_payload property ++ * ++ * @return void ++ * ++ * @uses XML_RPC_Server::parseRequest(), XML_RPC_Server::$encoding, ++ * XML_RPC_Response::serialize(), XML_RPC_Server::serializeDebug() ++ */ ++ function createServerPayload() ++ { ++ $r = $this->parseRequest(); ++ $this->server_payload = 'encoding . '"?>' . "\n" ++ . $this->serializeDebug() ++ . $r->serialize(); ++ } ++ ++ /** ++ * Determines the HTTP headers and puts them in the $server_headers ++ * property ++ * ++ * @return boolean TRUE if okay, FALSE if $server_payload isn't set. ++ * ++ * @uses XML_RPC_Server::createServerPayload(), ++ * XML_RPC_Server::$server_headers ++ */ ++ function createServerHeaders() ++ { ++ if (!$this->server_payload) { ++ return false; ++ } ++ $this->server_headers = 'Content-Length: ' ++ . strlen($this->server_payload) . "\r\n" ++ . 'Content-Type: text/xml;' ++ . ' charset=' . $this->encoding; ++ return true; ++ } ++ ++ /** ++ * @return array ++ */ ++ function verifySignature($in, $sig) ++ { ++ for ($i = 0; $i < sizeof($sig); $i++) { ++ // check each possible signature in turn ++ $cursig = $sig[$i]; ++ if (sizeof($cursig) == $in->getNumParams() + 1) { ++ $itsOK = 1; ++ for ($n = 0; $n < $in->getNumParams(); $n++) { ++ $p = $in->getParam($n); ++ // print "\n"; ++ if ($p->kindOf() == 'scalar') { ++ $pt = $p->scalartyp(); ++ } else { ++ $pt = $p->kindOf(); ++ } ++ // $n+1 as first type of sig is return type ++ if ($pt != $cursig[$n+1]) { ++ $itsOK = 0; ++ $pno = $n+1; ++ $wanted = $cursig[$n+1]; ++ $got = $pt; ++ break; ++ } ++ } ++ if ($itsOK) { ++ return array(1); ++ } ++ } ++ } ++ if (isset($wanted)) { ++ return array(0, "Wanted ${wanted}, got ${got} at param ${pno}"); ++ } else { ++ $allowed = array(); ++ foreach ($sig as $val) { ++ end($val); ++ $allowed[] = key($val); ++ } ++ $allowed = array_unique($allowed); ++ $last = count($allowed) - 1; ++ if ($last > 0) { ++ $allowed[$last] = 'or ' . $allowed[$last]; ++ } ++ return array(0, ++ 'Signature permits ' . implode(', ', $allowed) ++ . ' parameters but the request had ' ++ . $in->getNumParams()); ++ } ++ } ++ ++ /** ++ * @return object a new XML_RPC_Response object ++ * ++ * @uses XML_RPC_Message::getEncoding(), XML_RPC_Server::$encoding ++ */ ++ function parseRequest($data = '') ++ { ++ global $XML_RPC_xh, $HTTP_RAW_POST_DATA, ++ $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml, ++ $XML_RPC_defencoding, $XML_RPC_Server_dmap; ++ ++ if ($data == '') { ++ $data = $HTTP_RAW_POST_DATA; ++ } ++ ++ $this->encoding = XML_RPC_Message::getEncoding($data); ++ $parser_resource = xml_parser_create($this->encoding); ++ $parser = (int) $parser_resource; ++ ++ $XML_RPC_xh[$parser] = array(); ++ $XML_RPC_xh[$parser]['st'] = ''; ++ $XML_RPC_xh[$parser]['cm'] = 0; ++ $XML_RPC_xh[$parser]['isf'] = 0; ++ $XML_RPC_xh[$parser]['params'] = array(); ++ $XML_RPC_xh[$parser]['method'] = ''; ++ ++ $plist = ''; ++ ++ // decompose incoming XML into request structure ++ ++ xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true); ++ xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee'); ++ xml_set_character_data_handler($parser_resource, 'XML_RPC_cd'); ++ if (!xml_parse($parser_resource, $data, 1)) { ++ // return XML error as a faultCode ++ $r = new XML_RPC_Response(0, ++ $XML_RPC_errxml+xml_get_error_code($parser_resource), ++ sprintf('XML error: %s at line %d', ++ xml_error_string(xml_get_error_code($parser_resource)), ++ xml_get_current_line_number($parser_resource))); ++ xml_parser_free($parser_resource); ++ } else { ++ xml_parser_free($parser_resource); ++ $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']); ++ // now add parameters in ++ for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) { ++ // print '\n"; ++ $plist .= "$i - " . $XML_RPC_xh[$parser]['params'][$i] . " \n"; ++ eval('$m->addParam(' . $XML_RPC_xh[$parser]['params'][$i] . ');'); ++ } ++ XML_RPC_Server_debugmsg($plist); ++ ++ // now to deal with the method ++ $methName = $XML_RPC_xh[$parser]['method']; ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $this->dmap; ++ $sysCall = 0; ++ } ++ ++ if (isset($dmap[$methName]['function']) ++ && is_string($dmap[$methName]['function']) ++ && strpos($dmap[$methName]['function'], '::') !== false) ++ { ++ $dmap[$methName]['function'] = ++ explode('::', $dmap[$methName]['function']); ++ } ++ ++ if (isset($dmap[$methName]['function']) ++ && is_callable($dmap[$methName]['function'])) ++ { ++ // dispatch if exists ++ if (isset($dmap[$methName]['signature'])) { ++ $sr = $this->verifySignature($m, ++ $dmap[$methName]['signature'] ); ++ } ++ if (!isset($dmap[$methName]['signature']) || $sr[0]) { ++ // if no signature or correct signature ++ if ($sysCall) { ++ $r = call_user_func($dmap[$methName]['function'], $this, $m); ++ } else { ++ $r = call_user_func($dmap[$methName]['function'], $m); ++ } ++ if (!is_a($r, 'XML_RPC_Response')) { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['not_response_object'], ++ $XML_RPC_str['not_response_object']); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], ++ $XML_RPC_str['incorrect_params'] ++ . ': ' . $sr[1]); ++ } ++ } else { ++ // else prepare error response ++ $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'], ++ $XML_RPC_str['unknown_method']); ++ } ++ } ++ return $r; ++ } ++ ++ /** ++ * Echos back the input packet as a string value ++ * ++ * @return void ++ * ++ * Useful for debugging. ++ */ ++ function echoInput() ++ { ++ global $HTTP_RAW_POST_DATA; ++ ++ $r = new XML_RPC_Response(0); ++ $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); ++ print $r->serialize(); ++ } ++} ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * c-hanging-comment-ender-p: nil ++ * End: ++ */ ++ ++?> ++package.xml100644 1750 144 22507 10260516576 6427 ++ ++ ++ XML_RPC ++ PHP implementation of the XML-RPC protocol ++ A PEAR-ified version of Useful Inc's XML-RPC for PHP. ++ ++It has support for HTTP/HTTPS transport, proxies and authentication. ++ ++ ++ ++ ssb ++ Stig Bakken ++ stig@php.net ++ lead ++ ++ ++ danielc ++ Daniel Convissor ++ danielc@php.net ++ lead ++ ++ ++ ++ 1.3.1 ++ 2005-06-29 ++ PHP License ++ stable ++ * Security fix. Update highly recommended! ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 1.3.0RC3 ++ 2005-05-10 ++ beta ++ * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. ++* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. ++* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. ++* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. ++* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). ++* Use <br /> instead of <br> in XML_RPC_Value::dump(). ++ ++ ++ ++ 1.3.0RC2 ++ 2005-05-05 ++ beta ++ * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. ++* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. ++* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. ++* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. ++ ++ ++ ++ 1.3.0RC1 ++ 2005-04-07 ++ beta ++ * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. ++* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. ++* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. ++* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. ++* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. ++* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. ++ ++ ++ ++ 1.2.2 ++ 2005-03-07 ++ stable ++ * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. ++ ++ ++ ++ 1.2.1 ++ 2005-03-01 ++ stable ++ * Add isset() check before examining the dispatch map. Bug 3658. ++ ++ ++ ++ 1.2.0 ++ 2005-02-27 ++ stable ++ * Provide the "stable" release. ++* Add package2.xml for compatibility with PEAR 1.4.0. ++* For changes since 1.1.0, see the changelogs for the various RC releases. ++ ++ ++ ++ 1.2.0RC7 ++ 2005-02-22 ++ beta ++ * Add the setSendEncoding() method and $send_encoding ++ property to XML_RPC_Message. Request 3537. ++* Allow class methods to be mapped using either syntax: ++ 'function' => 'hello::sayHello', ++ or ++ 'function' => array('hello', 'sayhello'), ++ Bug 3363. ++* Use 8192 instead of 32768 for bytes in fread() ++ in parseResponseFile(). Bug 3340. ++ ++ ++ ++ 1.2.0RC6 ++ 2005-01-25 ++ beta ++ * Don't put the protocol in the Host field of the POST data. (danielc) ++ ++ ++ ++ 1.2.0RC5 ++ 2005-01-24 ++ beta ++ * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. ++ ++ ++ ++ 1.2.0RC4 ++ 2005-01-24 ++ beta ++ * When a connection attempt fails, have the method return 0. (danielc) ++* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) ++* Add tests for setting the client properties. (danielc) ++* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) ++* Bundle the tests with the package. (danielc) ++ ++ ++ ++ 1.2.0RC3 ++ 2005-01-19 ++ beta ++ * ssl uses port 443, not 445. ++ ++ ++ ++ 1.2.0RC2 ++ 2005-01-11 ++ beta ++ * Handle ssl:// in the $server string. (danielc) ++* Also default to port 445 for ssl:// requests as well. (danielc) ++* Enhance debugging in the server. (danielc) ++ ++ ++ ++ 1.2.0RC1 ++ 2004-12-30 ++ beta ++ * Make things work with SSL. Bug 2489. (nkukard lbsd net) ++* Allow array function callbacks (Matt Kane) ++* Some minor speed-ups (Matt Kane) ++* Add Dump.php to the package (Christian Weiske) ++* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) ++* Silence fsockopen() errors. Bug 1714. (danielc) ++* Encode empty arrays as an array. Bug 1493. (danielc) ++* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) ++* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) ++* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) ++* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) ++* Allow raiseError() to be called statically. (danielc) ++* Stop double escaping of character entities. Bug 987. (danielc) ++ NOTICE: the following have been removed: ++ * XML_RPC_dh() ++ * $GLOBALS['XML_RPC_entities'] ++ * XML_RPC_entity_decode() ++ * XML_RPC_lookup_entity() ++* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) ++ ++ ++ ++ 1.1.0 ++ 2004-03-15 ++ stable ++ * Added support for sequential arrays to XML_RPC_encode() (mroch) ++* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) ++* Remove "require_once 'PEAR.php'", include only when needed to raise an error ++* Replace echo and error_log() with raiseError() (mroch) ++* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) ++* be tolerant of junk after methodResponse (Luca Mariano, mroch) ++* Silent notice even in the error log (pierre) ++* fix include of shared xml extension on win32 (pierre) ++ ++ ++ ++ 1.0.4 ++ 2002-10-02 ++ stable ++ * added HTTP proxy authorization support (thanks to Arnaud Limbourg) ++ ++ ++ ++ 1.0.3 ++ 2002-05-19 ++ stable ++ * fix bug when parsing responses with boolean types ++ ++ ++ ++ 1.0.2 ++ 2002-04-16 ++ stable ++ * E_ALL fixes ++* fix HTTP response header parsing ++ ++ ++ ++ 1.0.1 ++ 2001-09-25 ++ stable ++ This is a PEAR-ified version of Useful Inc's 1.0.1 release. ++Includes an urgent security fix identified by Dan Libby <dan@libby.com>. ++ ++ ++ ++ ++ +\ Kein Zeilenumbruch am Dateiende. +diff -Naur php-5.0.4/php.ini-dist hardening-patch-5.0.4-0.3.2/php.ini-dist +--- php-5.0.4/php.ini-dist 2005-03-01 01:25:09.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/php.ini-dist 2005-07-02 13:37:27.000000000 +0200 +@@ -1187,6 +1187,177 @@ + ; instead of original one. + soap.wsdl_cache_ttl=86400 + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Naur php-5.0.4/php.ini-recommended hardening-patch-5.0.4-0.3.2/php.ini-recommended +--- php-5.0.4/php.ini-recommended 2005-03-01 01:25:09.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/php.ini-recommended 2005-07-02 13:38:04.000000000 +0200 +@@ -1245,6 +1245,176 @@ + ; instead of original one. + soap.wsdl_cache_ttl=86400 + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Naur php-5.0.4/sapi/apache/mod_php5.c hardening-patch-5.0.4-0.3.2/sapi/apache/mod_php5.c +--- php-5.0.4/sapi/apache/mod_php5.c 2004-07-14 11:43:26.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/sapi/apache/mod_php5.c 2005-06-26 21:58:33.000000000 +0200 +@@ -447,7 +447,7 @@ + sapi_apache_get_fd, + sapi_apache_force_http_10, + sapi_apache_get_target_uid, +- sapi_apache_get_target_gid ++ sapi_apache_get_target_gid, + }; + /* }}} */ + +@@ -899,7 +899,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component("PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component("PHP/" PHP_VERSION); ++#endif + } + } + #endif +diff -Naur php-5.0.4/sapi/apache2filter/sapi_apache2.c hardening-patch-5.0.4-0.3.2/sapi/apache2filter/sapi_apache2.c +--- php-5.0.4/sapi/apache2filter/sapi_apache2.c 2005-01-07 07:28:24.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/sapi/apache2filter/sapi_apache2.c 2005-06-26 21:56:59.000000000 +0200 +@@ -572,7 +572,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Naur php-5.0.4/sapi/apache2handler/sapi_apache2.c hardening-patch-5.0.4-0.3.2/sapi/apache2handler/sapi_apache2.c +--- php-5.0.4/sapi/apache2handler/sapi_apache2.c 2005-03-10 12:23:57.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/sapi/apache2handler/sapi_apache2.c 2005-06-26 21:56:13.000000000 +0200 +@@ -340,7 +340,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Naur php-5.0.4/sapi/cgi/cgi_main.c hardening-patch-5.0.4-0.3.2/sapi/cgi/cgi_main.c +--- php-5.0.4/sapi/cgi/cgi_main.c 2005-02-11 03:06:48.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/sapi/cgi/cgi_main.c 2005-06-26 22:01:33.000000000 +0200 +@@ -1414,11 +1414,19 @@ + SG(headers_sent) = 1; + SG(request_info).no_headers = 1; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit(1); + break; +diff -Naur php-5.0.4/sapi/cli/php_cli.c hardening-patch-5.0.4-0.3.2/sapi/cli/php_cli.c +--- php-5.0.4/sapi/cli/php_cli.c 2005-03-22 16:09:20.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/sapi/cli/php_cli.c 2005-06-28 01:08:04.000000000 +0200 +@@ -694,11 +694,19 @@ + if (php_request_startup(TSRMLS_C)==FAILURE) { + goto err; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit_status=1; + goto out; +diff -Naur php-5.0.4/TSRM/TSRM.h hardening-patch-5.0.4-0.3.2/TSRM/TSRM.h +--- php-5.0.4/TSRM/TSRM.h 2005-03-11 12:12:07.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/TSRM/TSRM.h 2005-06-26 22:07:33.000000000 +0200 +@@ -33,6 +33,13 @@ + # define TSRM_API + #endif + ++#if HARDENING_PATCH ++# if HAVE_REALPATH ++# undef realpath ++# define realpath php_realpath ++# endif ++#endif ++ + /* Only compile multi-threading functions if we're in ZTS mode */ + #ifdef ZTS + +@@ -88,6 +95,7 @@ + + #define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts + ++ + #ifdef __cplusplus + extern "C" { + #endif +diff -Naur php-5.0.4/TSRM/tsrm_virtual_cwd.c hardening-patch-5.0.4-0.3.2/TSRM/tsrm_virtual_cwd.c +--- php-5.0.4/TSRM/tsrm_virtual_cwd.c 2005-03-11 12:09:42.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/TSRM/tsrm_virtual_cwd.c 2005-06-26 22:07:48.000000000 +0200 +@@ -197,6 +197,165 @@ + return p; + } + ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved) ++{ ++ struct stat sb; ++ char *p, *q, *s; ++ size_t left_len, resolved_len; ++ unsigned symlinks; ++ int serrno, slen; ++ int is_dir = 1; ++ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; ++ ++ serrno = errno; ++ symlinks = 0; ++ if (path[0] == '/') { ++ resolved[0] = '/'; ++ resolved[1] = '\0'; ++ if (path[1] == '\0') ++ return (resolved); ++ resolved_len = 1; ++ left_len = strlcpy(left, path + 1, sizeof(left)); ++ } else { ++ if (getcwd(resolved, PATH_MAX) == NULL) { ++ strlcpy(resolved, ".", PATH_MAX); ++ return (NULL); ++ } ++ resolved_len = strlen(resolved); ++ left_len = strlcpy(left, path, sizeof(left)); ++ } ++ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ ++ /* ++ * Iterate over path components in `left'. ++ */ ++ while (left_len != 0) { ++ /* ++ * Extract the next path component and adjust `left' ++ * and its length. ++ */ ++ p = strchr(left, '/'); ++ s = p ? p : left + left_len; ++ if (s - left >= sizeof(next_token)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ memcpy(next_token, left, s - left); ++ next_token[s - left] = '\0'; ++ left_len -= s - left; ++ if (p != NULL) ++ memmove(left, s + 1, left_len + 1); ++ if (resolved[resolved_len - 1] != '/') { ++ if (resolved_len + 1 >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ resolved[resolved_len++] = '/'; ++ resolved[resolved_len] = '\0'; ++ } ++ if (next_token[0] == '\0') ++ continue; ++ else if (strcmp(next_token, ".") == 0) ++ continue; ++ else if (strcmp(next_token, "..") == 0) { ++ /* ++ * Strip the last path component except when we have ++ * single "/" ++ */ ++ if (!is_dir) { ++ errno = ENOENT; ++ return (NULL); ++ } ++ if (resolved_len > 1) { ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ continue; ++ } ++ ++ /* ++ * Append the next path component and lstat() it. If ++ * lstat() fails we still can return successfully if ++ * there are no more path components left. ++ */ ++ resolved_len = strlcat(resolved, next_token, PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ if (lstat(resolved, &sb) != 0) { ++ if (errno == ENOENT && p == NULL) { ++ errno = serrno; ++ return (resolved); ++ } ++ return (NULL); ++ } ++ if (S_ISLNK(sb.st_mode)) { ++ if (symlinks++ > MAXSYMLINKS) { ++ errno = ELOOP; ++ return (NULL); ++ } ++ slen = readlink(resolved, symlink, sizeof(symlink) - 1); ++ if (slen < 0) ++ return (NULL); ++ symlink[slen] = '\0'; ++ if (symlink[0] == '/') { ++ resolved[1] = 0; ++ resolved_len = 1; ++ } else if (resolved_len > 1) { ++ /* Strip the last path component. */ ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ ++ /* ++ * If there are any path components left, then ++ * append them to symlink. The result is placed ++ * in `left'. ++ */ ++ if (p != NULL) { ++ if (symlink[slen - 1] != '/') { ++ if (slen + 1 >= sizeof(symlink)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ symlink[slen] = '/'; ++ symlink[slen + 1] = 0; ++ } ++ left_len = strlcat(symlink, left, sizeof(left)); ++ if (left_len >= sizeof(left)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ } ++ left_len = strlcpy(left, symlink, sizeof(left)); ++ } else { ++ if (S_ISDIR(sb.st_mode)) { ++ is_dir = 1; ++ } else { ++ is_dir = 0; ++ } ++ } ++ } ++ ++ /* ++ * Remove trailing slash except when the resolved pathname ++ * is a single "/". ++ */ ++ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') ++ resolved[resolved_len - 1] = '\0'; ++ return (resolved); ++} ++#endif ++ + CWD_API void virtual_cwd_startup(void) + { + char cwd[MAXPATHLEN]; +@@ -321,8 +480,7 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now +- return 1; */ ++ return 1; + } + } + } else { /* Concat current directory with relative path and then run realpath() on it */ +@@ -348,9 +506,8 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now + free(tmp); +- return 1; */ ++ return 1; + } + } + free(tmp); +diff -Naur php-5.0.4/TSRM/tsrm_virtual_cwd.h hardening-patch-5.0.4-0.3.2/TSRM/tsrm_virtual_cwd.h +--- php-5.0.4/TSRM/tsrm_virtual_cwd.h 2005-03-11 12:07:17.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/TSRM/tsrm_virtual_cwd.h 2005-06-26 22:07:57.000000000 +0200 +@@ -128,6 +128,22 @@ + + typedef int (*verify_path_func)(const cwd_state *); + ++#ifndef HAVE_STRLCPY ++CWD_API size_t php_strlcpy(char *dst, const char *src, size_t siz); ++#undef strlcpy ++#define strlcpy php_strlcpy ++#endif ++ ++#ifndef HAVE_STRLCAT ++CWD_API size_t php_strlcat(char *dst, const char *src, size_t siz); ++#undef strlcat ++#define strlcat php_strlcat ++#endif ++ ++ ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved); ++#endif + CWD_API void virtual_cwd_startup(void); + CWD_API void virtual_cwd_shutdown(void); + CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC); +diff -Naur php-5.0.4/Zend/zend_alloc.c hardening-patch-5.0.4-0.3.2/Zend/zend_alloc.c +--- php-5.0.4/Zend/zend_alloc.c 2004-08-27 18:49:54.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_alloc.c 2005-06-26 22:52:59.000000000 +0200 +@@ -64,6 +64,11 @@ + # define END_MAGIC_SIZE 0 + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++# define CANARY_SIZE sizeof(unsigned int) ++#else ++# define CANARY_SIZE 0 ++#endif + + # if MEMORY_LIMIT + # if ZEND_DEBUG +@@ -104,9 +109,17 @@ + if (p==AG(head)) { \ + AG(head) = p->pNext; \ + } else { \ ++ if (p != p->pLast->pNext) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pLast->pNext = p->pNext; \ + } \ + if (p->pNext) { \ ++ if (p != p->pNext->pLast) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pNext->pLast = p->pLast; \ + } + #else +@@ -145,6 +158,12 @@ + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (size > LONG_MAX - sizeof(zend_mem_header) - MEM_HEADER_PADDING - END_MAGIC_SIZE - CANARY_SIZE) { ++ zend_security_log(S_MEMORY, "emalloc() - requested size would result in integer overflow"); ++ exit(1); ++ } ++#endif + CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size); + + #if !ZEND_DISABLE_MEMORY_CACHE +@@ -163,6 +182,10 @@ + AG(cache_stats)[CACHE_INDEX][1]++; + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->cached = 0; + p->size = size; + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); +@@ -179,7 +202,7 @@ + AG(allocated_memory_peak) = AG(allocated_memory); + } + #endif +- p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE + CANARY_SIZE); + #if !ZEND_DISABLE_MEMORY_CACHE + } + #endif +@@ -211,7 +234,10 @@ + # endif + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif +- ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); + } +@@ -239,6 +265,10 @@ + } + } + ++ ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by safe_emalloc()"); ++#endif + zend_error(E_ERROR, "Possible integer overflow in memory allocation (%zd * %zd + %zd)", nmemb, size, offset); + return 0; + } +@@ -247,9 +277,22 @@ + + ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int *canary_2; ++#endif + zend_mem_header *p = (zend_mem_header *) ((char *)ptr - sizeof(zend_mem_header) - MEM_HEADER_PADDING); + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); ++ ++#if HARDENING_PATCH_MM_PROTECT ++ canary_2 = (unsigned int *)(((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE); ++ if (p->canary != HG(canary_1) || *canary_2 != HG(canary_2)) { ++ zend_security_log(S_MEMORY, "canary mismatch on efree() - heap overflow or double efree detected"); ++ exit(1); ++ } ++ /* to catch double efree()s */ ++ *canary_2 = p->canary = 0; ++#endif + + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { +@@ -291,23 +334,35 @@ + + ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { +- void *p; +- int final_size = size*nmemb; ++ char *p; ++ size_t _size = nmemb * size; ++ ++ if (nmemb && (_size/nmemb!=size)) { ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by ecalloc()"); ++#endif ++ fprintf(stderr,"FATAL: ecalloc(): Unable to allocate %ld * %ld bytes\n", (long) nmemb, (long) size); ++#if ZEND_DEBUG && HAVE_KILL && HAVE_GETPID ++ kill(getpid(), SIGSEGV); ++#else ++ exit(1); ++#endif ++ } + +- HANDLE_BLOCK_INTERRUPTIONS(); +- p = _emalloc(final_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); +- if (!p) { +- HANDLE_UNBLOCK_INTERRUPTIONS(); +- return (void *) p; ++ p = (char *) _emalloc(_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); ++ if (p) { ++ memset(p, 0, _size); + } +- memset(p, 0, final_size); +- HANDLE_UNBLOCK_INTERRUPTIONS(); +- return p; ++ ++ return ((void *)p); + } + + + ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p; + zend_mem_header *orig; + DECLARE_CACHE_VARS(); +@@ -319,6 +374,14 @@ + + p = orig = (zend_mem_header *) ((char *)ptr-sizeof(zend_mem_header)-MEM_HEADER_PADDING); + ++#if HARDENING_PATCH_MM_PROTECT ++ canary_2 = *(unsigned int *)(((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE); ++ if (p->canary != HG(canary_1) || canary_2 != HG(canary_2)) { ++ zend_security_log(S_MEMORY, "canary mismatch on erealloc() - heap overflow detected"); ++ exit(1); ++ } ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + void *new_p; +@@ -342,7 +405,7 @@ + } + #endif + REMOVE_POINTER_FROM_LIST(p); +- p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE+CANARY_SIZE); + if (!p) { + if (!allow_failure) { + fprintf(stderr,"FATAL: erealloc(): Unable to allocate %ld bytes\n", (long) size); +@@ -364,6 +427,9 @@ + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->size = size; + + HANDLE_UNBLOCK_INTERRUPTIONS(); +@@ -439,6 +505,10 @@ + { + AG(head) = NULL; + ++#if HARDENING_PATCH_MM_PROTECT ++ HG(canary_1) = zend_canary(); ++ HG(canary_2) = zend_canary(); ++#endif + #if MEMORY_LIMIT + AG(memory_limit) = 1<<30; /* ridiculous limit, effectively no limit */ + AG(allocated_memory) = 0; +diff -Naur php-5.0.4/Zend/zend_alloc.h hardening-patch-5.0.4-0.3.2/Zend/zend_alloc.h +--- php-5.0.4/Zend/zend_alloc.h 2004-08-11 08:13:12.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_alloc.h 2005-06-26 22:16:00.000000000 +0200 +@@ -35,6 +35,9 @@ + #define MEM_BLOCK_CACHED_MAGIC 0xFB8277DCL + + typedef struct _zend_mem_header { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary; ++#endif + #if ZEND_DEBUG + long magic; + char *filename; +diff -Naur php-5.0.4/Zend/zend_API.h hardening-patch-5.0.4-0.3.2/Zend/zend_API.h +--- php-5.0.4/Zend/zend_API.h 2005-01-22 13:29:13.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_API.h 2005-06-26 20:59:20.000000000 +0200 +@@ -47,6 +47,7 @@ + #define ZEND_METHOD(classname, name) ZEND_NAMED_FUNCTION(ZEND_FN(classname##_##name)) + + #define ZEND_FENTRY(zend_name, name, arg_info, flags) { #zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeof(struct _zend_arg_info)-1), flags }, ++#define ZEND_STATIC_FE(zend_name, name, arg_info) { zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeof(struct _zend_arg_info)-1), 0 }, + + #define ZEND_NAMED_FE(zend_name, name, arg_info) ZEND_FENTRY(zend_name, name, arg_info, 0) + #define ZEND_FE(name, arg_info) ZEND_FENTRY(name, ZEND_FN(name), arg_info, 0) +diff -Naur php-5.0.4/Zend/zend_builtin_functions.c hardening-patch-5.0.4-0.3.2/Zend/zend_builtin_functions.c +--- php-5.0.4/Zend/zend_builtin_functions.c 2005-03-14 10:13:14.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_builtin_functions.c 2005-06-26 22:15:50.000000000 +0200 +@@ -52,6 +52,9 @@ + static ZEND_FUNCTION(crash); + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++static ZEND_FUNCTION(heap_overflow); ++#endif + static ZEND_FUNCTION(get_included_files); + static ZEND_FUNCTION(is_subclass_of); + static ZEND_FUNCTION(is_a); +@@ -111,6 +114,9 @@ + ZEND_FE(crash, NULL) + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ ZEND_FE(heap_overflow, NULL) ++#endif + ZEND_FE(get_included_files, NULL) + ZEND_FALIAS(get_required_files, get_included_files, NULL) + ZEND_FE(is_subclass_of, NULL) +@@ -999,6 +1005,19 @@ + + #endif /* ZEND_DEBUG */ + ++ ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ZEND_FUNCTION(heap_overflow) ++{ ++ char *nowhere = emalloc(10); ++ ++ memcpy(nowhere, "something1234567890", sizeof("something1234567890")); ++ ++ efree(nowhere); ++} ++#endif ++ ++ + /* {{{ proto array get_included_files(void) + Returns an array with the file names that were include_once()'d */ + ZEND_FUNCTION(get_included_files) +diff -Naur php-5.0.4/Zend/zend.c hardening-patch-5.0.4-0.3.2/Zend/zend.c +--- php-5.0.4/Zend/zend.c 2005-03-16 00:47:12.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend.c 2005-07-05 18:32:04.000000000 +0200 +@@ -54,6 +54,12 @@ + ZEND_API void (*zend_unblock_interruptions)(void); + ZEND_API void (*zend_ticks_function)(int ticks); + ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); ++#if HARDENING_PATCH ++ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); + + void (*zend_on_timeout)(int seconds TSRMLS_DC); +@@ -72,9 +78,80 @@ + return SUCCESS; + } + ++#if HARDENING_PATCH ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog) = S_ALL & ~S_SQL | S_MEMORY; ++ } else { ++ EG(hphp_log_syslog) = atoi(new_value) | S_MEMORY; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_facility) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_facility) = LOG_USER; ++ } else { ++ EG(hphp_log_syslog_facility) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_priority) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_priority) = LOG_ALERT; ++ } else { ++ EG(hphp_log_syslog_priority) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_sapi) ++{ ++ if (!new_value) { ++ EG(hphp_log_sapi) = S_ALL & ~S_SQL; ++ } else { ++ EG(hphp_log_sapi) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_script) ++{ ++ if (!new_value) { ++ EG(hphp_log_script) = S_ALL & ~S_MEMORY; ++ } else { ++ EG(hphp_log_script) = atoi(new_value) & ~S_MEMORY; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_scriptname) ++{ ++ if (!new_value) { ++ EG(hphp_log_scriptname) = NULL; ++ } else { ++ if (EG(hphp_log_scriptname)) { ++ pefree(EG(hphp_log_scriptname),1); ++ } ++ EG(hphp_log_scriptname) = pestrdup(new_value,1); ++ } ++ return SUCCESS; ++} ++#endif + + ZEND_INI_BEGIN() + ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) ++#if HARDENING_PATCH ++ ZEND_INI_ENTRY("hphp.log.syslog", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog) ++ ZEND_INI_ENTRY("hphp.log.syslog.facility", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_facility) ++ ZEND_INI_ENTRY("hphp.log.syslog.priority", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_priority) ++ ZEND_INI_ENTRY("hphp.log.sapi", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_sapi) ++ ZEND_INI_ENTRY("hphp.log.script", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_script) ++ ZEND_INI_ENTRY("hphp.log.script.name", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_scriptname) ++ STD_ZEND_INI_BOOLEAN("hphp.log.use-x-forwarded-for", "0", ZEND_INI_SYSTEM, OnUpdateBool, hphp_log_use_x_forwarded_for, zend_executor_globals, executor_globals) ++ STD_ZEND_INI_ENTRY("hphp.executor.max_depth", "0", ZEND_INI_PERDIR, OnUpdateLong, hphp_executor_max_depth, zend_executor_globals, executor_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.sql.bailout_on_error", "0", ZEND_INI_PERDIR, OnUpdateBool, hphp_sql_bailout_on_error, hardened_globals_struct, hardened_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.multiheader", "0", ZEND_INI_PERDIR, OnUpdateBool, hphp_multiheader, hardened_globals_struct, hardened_globals) ++#endif + STD_ZEND_INI_BOOLEAN("zend.ze1_compatibility_mode", "0", ZEND_INI_ALL, OnUpdateBool, ze1_compatibility_mode, zend_executor_globals, executor_globals) + ZEND_INI_END() + +@@ -476,6 +553,7 @@ + EG(user_error_handler) = NULL; + EG(user_exception_handler) = NULL; + EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(in_autoload) = NULL; + EG(current_execute_data) = NULL; + EG(current_module) = NULL; +@@ -545,6 +623,14 @@ + extern zend_scanner_globals language_scanner_globals; + #endif + ++ /* Set up Hardening-Patch utility functions first */ ++#if HARDENING_PATCH ++ zend_security_log = utility_functions->security_log_function; ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ zend_is_valid_include = utility_functions->is_valid_include; ++#endif ++ + #ifdef ZTS + ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); + #else +@@ -747,6 +833,7 @@ + } + CG(unclean_shutdown) = 1; + CG(in_compilation) = EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(current_execute_data) = NULL; + longjmp(EG(bailout), FAILURE); + } +diff -Naur php-5.0.4/Zend/zend_canary.c hardening-patch-5.0.4-0.3.2/Zend/zend_canary.c +--- php-5.0.4/Zend/zend_canary.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_canary.c 2005-06-26 22:13:40.000000000 +0200 +@@ -0,0 +1,58 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: zend_canary.c,v 1.1 2004/11/26 12:45:41 ionic Exp $ */ ++ ++#include "zend.h" ++ ++#include ++#include ++ ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++ZEND_API unsigned int zend_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Naur php-5.0.4/Zend/zend_compile.c hardening-patch-5.0.4-0.3.2/Zend/zend_compile.c +--- php-5.0.4/Zend/zend_compile.c 2005-03-10 14:24:32.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_compile.c 2005-06-27 00:23:42.000000000 +0200 +@@ -1455,7 +1455,7 @@ + zend_op *opline; + + if (switch_entry->cond.op_type != IS_VAR && switch_entry->cond.op_type != IS_TMP_VAR) { +- return 0; ++ return (switch_entry->cond.op_type == IS_UNUSED); + } + + opline = get_next_op(CG(active_op_array) TSRMLS_CC); +diff -Naur php-5.0.4/Zend/zend_compile.h hardening-patch-5.0.4-0.3.2/Zend/zend_compile.h +--- php-5.0.4/Zend/zend_compile.h 2004-09-16 02:44:12.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_compile.h 2005-06-27 23:31:04.000000000 +0200 +@@ -275,6 +275,8 @@ + zval *object; + union _temp_variable *Ts; + zend_bool original_in_execution; ++ zend_uint original_in_code_type; ++ zend_uint execute_depth; + zend_class_entry *calling_scope; + struct _zend_execute_data *prev_execute_data; + }; +@@ -767,6 +769,7 @@ + #define ZEND_OVERLOADED_FUNCTION 3 + #define ZEND_EVAL_CODE 4 + #define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5 ++#define ZEND_SANDBOX_CODE 6 + + #define ZEND_INTERNAL_CLASS 1 + #define ZEND_USER_CLASS 2 +diff -Naur php-5.0.4/Zend/zend_constants.c hardening-patch-5.0.4-0.3.2/Zend/zend_constants.c +--- php-5.0.4/Zend/zend_constants.c 2004-07-13 21:22:11.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_constants.c 2005-07-01 18:17:57.000000000 +0200 +@@ -107,6 +107,72 @@ + REGISTER_MAIN_LONG_CONSTANT("E_USER_NOTICE", E_USER_NOTICE, CONST_PERSISTENT | CONST_CS); + + REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("S_MEMORY", S_MEMORY, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_VARS", S_VARS, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_FILES", S_VARS, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INCLUDE", S_INCLUDE, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_SQL", S_SQL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_EXECUTOR", S_EXECUTOR, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_MISC", S_MISC, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_ALL", S_ALL, CONST_PERSISTENT | CONST_CS); ++ ++ /* error levels */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRIT", LOG_CRIT, CONST_CS | CONST_PERSISTENT); /* critical conditions */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ERR", LOG_ERR, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_WARNING", LOG_WARNING, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOTICE", LOG_NOTICE, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_INFO", LOG_INFO, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DEBUG", LOG_DEBUG, CONST_CS | CONST_PERSISTENT); ++ /* facility: type of program logging the message */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_KERN", LOG_KERN, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_USER", LOG_USER, CONST_CS | CONST_PERSISTENT); /* generic user level */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_MAIL", LOG_MAIL, CONST_CS | CONST_PERSISTENT); /* log to email */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DAEMON", LOG_DAEMON, CONST_CS | CONST_PERSISTENT); /* other system daemons */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTH", LOG_AUTH, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_SYSLOG", LOG_SYSLOG, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LPR", LOG_LPR, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NEWS ++ /* No LOG_NEWS on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NEWS", LOG_NEWS, CONST_CS | CONST_PERSISTENT); /* usenet new */ ++#endif ++#ifdef LOG_UUCP ++ /* No LOG_UUCP on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_UUCP", LOG_UUCP, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_CRON ++ /* apparently some systems don't have this one */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRON", LOG_CRON, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_AUTHPRIV ++ /* AIX doesn't have LOG_AUTHPRIV */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTHPRIV", LOG_AUTHPRIV, CONST_CS | CONST_PERSISTENT); ++#endif ++#if !defined(PHP_WIN32) && !defined(NETWARE) ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL0", LOG_LOCAL0, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL1", LOG_LOCAL1, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL2", LOG_LOCAL2, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL3", LOG_LOCAL3, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL4", LOG_LOCAL4, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL5", LOG_LOCAL5, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL6", LOG_LOCAL6, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL7", LOG_LOCAL7, CONST_CS | CONST_PERSISTENT); ++#endif ++ /* options */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PID", LOG_PID, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CONS", LOG_CONS, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ODELAY", LOG_ODELAY, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NDELAY", LOG_NDELAY, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NOWAIT ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOWAIT", LOG_NOWAIT, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_PERROR ++ /* AIX doesn't have LOG_PERROR */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ ++#endif ++#endif + + /* true/false constants */ + { +diff -Naur php-5.0.4/Zend/zend_errors.h hardening-patch-5.0.4-0.3.2/Zend/zend_errors.h +--- php-5.0.4/Zend/zend_errors.h 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_errors.h 2005-06-28 00:03:24.000000000 +0200 +@@ -38,6 +38,17 @@ + #define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE) + #define E_CORE (E_CORE_ERROR | E_CORE_WARNING) + ++#if HARDENING_PATCH ++#define S_MEMORY (1<<0L) ++#define S_VARS (1<<1L) ++#define S_FILES (1<<2L) ++#define S_INCLUDE (1<<3L) ++#define S_SQL (1<<4L) ++#define S_EXECUTOR (1<<5L) ++#define S_MISC (1<<30L) ++#define S_ALL (S_MEMORY | S_VARS | S_INCLUDE | S_FILES | S_MISC | S_SQL | S_EXECUTOR) ++#endif ++ + #endif /* ZEND_ERRORS_H */ + + /* +diff -Naur php-5.0.4/Zend/zend_execute_API.c hardening-patch-5.0.4-0.3.2/Zend/zend_execute_API.c +--- php-5.0.4/Zend/zend_execute_API.c 2005-03-19 15:29:18.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_execute_API.c 2005-07-03 10:40:05.000000000 +0200 +@@ -137,6 +137,7 @@ + EG(class_table) = CG(class_table); + + EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(in_autoload) = NULL; + + zend_ptr_stack_init(&EG(argument_stack)); +@@ -966,7 +967,7 @@ + return retval; + } + +-ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) ++ZEND_API int zend_eval_string_ex_ex(char *str, zval *retval_ptr, char *string_name, int type TSRMLS_DC) + { + zval pv; + zend_op_array *new_op_array; +@@ -999,6 +1000,7 @@ + zval **original_return_value_ptr_ptr = EG(return_value_ptr_ptr); + zend_op **original_opline_ptr = EG(opline_ptr); + ++ new_op_array->type = type; + EG(return_value_ptr_ptr) = &local_retval_ptr; + EG(active_op_array) = new_op_array; + EG(no_extensions)=1; +@@ -1033,6 +1035,12 @@ + } + + ++ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) ++{ ++ return (zend_eval_string_ex_ex(str, retval_ptr, string_name, ZEND_EVAL_CODE TSRMLS_CC)); ++} ++ ++ + ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC) + { + int result; +diff -Naur php-5.0.4/Zend/zend_execute.c hardening-patch-5.0.4-0.3.2/Zend/zend_execute.c +--- php-5.0.4/Zend/zend_execute.c 2005-03-21 17:22:10.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_execute.c 2005-06-28 00:08:12.000000000 +0200 +@@ -1343,6 +1343,7 @@ + efree(EX(Ts)); \ + } \ + EG(in_execution) = EX(original_in_execution); \ ++ EG(in_code_type) = EX(original_in_code_type); \ + EG(current_execute_data) = EX(prev_execute_data); \ + return 1; /* CHECK_ME */ + +@@ -1369,6 +1370,16 @@ + EX(original_in_execution) = EG(in_execution); + EX(prev_execute_data) = EG(current_execute_data); + EG(current_execute_data) = &execute_data; ++#if HARDENING_PATCH ++ EX(execute_depth) = 0; ++ ++ if (op_array->type == ZEND_EVAL_CODE && EG(in_code_type) != ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } else if (op_array->type == ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_SANDBOX_CODE; ++ op_array->type = ZEND_EVAL_CODE; ++ } ++#endif + + EG(in_execution) = 1; + if (op_array->start_op) { +@@ -1395,6 +1406,19 @@ + EX(function_state).function_symbol_table = NULL; + #endif + ++#if HARDENING_PATCH ++ if (EX(prev_execute_data) == NULL) { ++ EX(execute_depth) = 0; ++ } else { ++ EX(execute_depth) = EX(prev_execute_data)->execute_depth + 1; ++ } ++ ++ if (EG(hphp_executor_max_depth) > 0 && EX(execute_depth) > EG(hphp_executor_max_depth)) { ++ zend_security_log(S_EXECUTOR, "Maximum execution depth of %u violated", EG(hphp_executor_max_depth)); ++ zend_bailout(); ++ } ++#endif ++ + while (1) { + #ifdef ZEND_WIN32 + if (EG(timed_out)) { +@@ -3523,7 +3547,12 @@ + int dummy = 1; + zend_file_handle file_handle; + ++#if HARDENING_PATCH_INC_PROTECT ++ if (zend_is_valid_include(inc_filename) ++ && (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC))) { ++#else + if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) { ++#endif + + if (!file_handle.opened_path) { + file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len); +@@ -3548,6 +3577,11 @@ + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: ++#if HARDENING_PATCH_INC_PROTECT ++ if (!zend_is_valid_include(inc_filename)) { ++ break; ++ } ++#endif + new_op_array = compile_filename(opline->op2.u.constant.value.lval, inc_filename TSRMLS_CC); + break; + case ZEND_EVAL: { +diff -Naur php-5.0.4/Zend/zend_extensions.h hardening-patch-5.0.4-0.3.2/Zend/zend_extensions.h +--- php-5.0.4/Zend/zend_extensions.h 2004-11-25 21:26:48.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_extensions.h 2005-06-28 14:46:24.000000000 +0200 +@@ -24,10 +24,11 @@ + + #include "zend_compile.h" + +-/* The first number is the engine version and the rest is the date. ++/* The first number is a flag saying that Hardening-Patch is used ++ * the second number is the engine version and the rest is the date. + * This way engine 2 API no. is always greater than engine 1 API no.. + */ +-#define ZEND_EXTENSION_API_NO 220040412 ++#define ZEND_EXTENSION_API_NO 1220050627 + + typedef struct _zend_extension_version_info { + int zend_extension_api_no; +diff -Naur php-5.0.4/Zend/zend_globals.h hardening-patch-5.0.4-0.3.2/Zend/zend_globals.h +--- php-5.0.4/Zend/zend_globals.h 2004-11-04 00:14:31.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_globals.h 2005-06-30 12:41:57.000000000 +0200 +@@ -174,6 +174,16 @@ + + int error_reporting; + int orig_error_reporting; ++#if HARDENING_PATCH ++ int hphp_log_syslog; ++ int hphp_log_syslog_facility; ++ int hphp_log_syslog_priority; ++ int hphp_log_sapi; ++ int hphp_log_script; ++ char *hphp_log_scriptname; ++ zend_bool hphp_log_use_x_forwarded_for; ++ long hphp_executor_max_depth; ++#endif + int exit_status; + + zend_op_array *active_op_array; +@@ -191,6 +201,7 @@ + int ticks_count; + + zend_bool in_execution; ++ zend_uint in_code_type; + HashTable *in_autoload; + zend_bool bailout_set; + zend_bool full_tables_cleanup; +diff -Naur php-5.0.4/Zend/zend.h hardening-patch-5.0.4-0.3.2/Zend/zend.h +--- php-5.0.4/Zend/zend.h 2005-03-10 12:30:44.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend.h 2005-07-03 10:41:35.000000000 +0200 +@@ -290,6 +290,7 @@ + /* Variable information */ + zvalue_value value; /* value */ + zend_uint refcount; ++ zend_ushort flags; + zend_uchar type; /* active type */ + zend_uchar is_ref; + }; +@@ -359,6 +360,12 @@ + void (*on_timeout)(int seconds TSRMLS_DC); + int (*stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); + int (*vspprintf_function)(char **pbuf, size_t max_len, const char *format, va_list ap); ++#if HARDENING_PATCH ++ void (*security_log_function)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ int (*is_valid_include)(zval *z); ++#endif + } zend_utility_functions; + + +@@ -496,6 +503,16 @@ + extern void (*zend_on_timeout)(int seconds TSRMLS_DC); + extern ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); + extern int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); ++#if HARDENING_PATCH ++extern ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++extern ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ZEND_API unsigned int zend_canary(void); ++#endif + + + ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +@@ -620,6 +637,11 @@ + #define ZEND_MAX_RESERVED_RESOURCES 4 + + ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#include "php_syslog.h" ++#endif ++ + #endif /* ZEND_H */ + + /* +diff -Naur php-5.0.4/Zend/zend_hash.c hardening-patch-5.0.4-0.3.2/Zend/zend_hash.c +--- php-5.0.4/Zend/zend_hash.c 2004-07-10 09:45:49.000000000 +0200 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_hash.c 2005-06-26 22:51:36.000000000 +0200 +@@ -21,6 +21,18 @@ + + #include "zend.h" + ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int zend_hash_canary = 0x1234567; ++ zend_bool zend_hash_canary_inited = 0; ++#endif ++ ++#define CHECK_HASH_CANARY(hash) \ ++ if (zend_hash_canary != (hash)->canary) { \ ++ zend_security_log(S_MEMORY, "Zend HashTable canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++ + #define CONNECT_TO_BUCKET_DLLIST(element, list_head) \ + (element)->pNext = (list_head); \ + (element)->pLast = NULL; \ +@@ -138,6 +150,9 @@ + { + uint i = 3; + Bucket **tmp; ++#if HARDENING_PATCH_HASH_PROTECT ++ TSRMLS_FETCH(); ++#endif + + SET_INCONSISTENT(HT_OK); + +@@ -147,6 +162,13 @@ + + ht->nTableSize = 1 << i; + ht->nTableMask = ht->nTableSize - 1; ++#if HARDENING_PATCH_HASH_PROTECT ++ if (zend_hash_canary_inited==0) { ++ zend_hash_canary = zend_canary(); ++ zend_hash_canary_inited = 1; ++ } ++ ht->canary = zend_hash_canary; ++#endif + ht->pDestructor = pDestructor; + ht->arBuckets = NULL; + ht->pListHead = NULL; +@@ -226,6 +248,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -291,6 +316,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -366,6 +394,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -414,7 +445,7 @@ + IS_CONSISTENT(ht); + + if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */ +- t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); ++ t = (Bucket **) perealloc(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); + if (t) { + HANDLE_BLOCK_INTERRUPTIONS(); + ht->arBuckets = t; +@@ -424,6 +455,7 @@ + HANDLE_UNBLOCK_INTERRUPTIONS(); + return SUCCESS; + } ++ zend_error(E_ERROR, "zend_hash_do_resize - out of memory"); + return FAILURE; + } + return SUCCESS; +@@ -487,6 +519,9 @@ + ht->pInternalPointer = p->pListNext; + } + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +@@ -516,6 +551,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -542,6 +580,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -571,6 +612,9 @@ + HANDLE_BLOCK_INTERRUPTIONS(); + + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +diff -Naur php-5.0.4/Zend/zend_hash.h hardening-patch-5.0.4-0.3.2/Zend/zend_hash.h +--- php-5.0.4/Zend/zend_hash.h 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_hash.h 2005-06-26 22:20:57.000000000 +0200 +@@ -58,6 +58,9 @@ + } Bucket; + + typedef struct _hashtable { ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int canary; ++#endif + uint nTableSize; + uint nTableMask; + uint nNumOfElements; +diff -Naur php-5.0.4/Zend/zend_llist.c hardening-patch-5.0.4-0.3.2/Zend/zend_llist.c +--- php-5.0.4/Zend/zend_llist.c 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_llist.c 2005-06-26 22:51:54.000000000 +0200 +@@ -22,9 +22,34 @@ + #include "zend.h" + #include "zend_llist.h" + #include "zend_qsort.h" ++#include "zend_globals.h" ++ ++#define CHECK_LIST_CANARY(list) \ ++ if (HG(canary_3) != (list)->canary_h || HG(canary_4) != (list)->canary_t) { \ ++ zend_security_log(S_MEMORY, "linked list canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++#define CHECK_LISTELEMENT_CANARY(elem) \ ++ if (HG(canary_3) != (elem)->canary) { \ ++ zend_security_log(S_MEMORY, "linked list element canary was overwritten"); \ ++ exit(1); \ ++ } ++ + + ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ ++ if (!HG(ll_canary_inited)) { ++ HG(canary_3) = zend_canary(); ++ HG(canary_4) = zend_canary(); ++ HG(ll_canary_inited) = 1; ++ } ++ l->canary_h = HG(canary_3); ++ l->canary_t = HG(canary_4); ++#endif + l->head = NULL; + l->tail = NULL; + l->count = 0; +@@ -38,6 +63,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->prev = l->tail; + tmp->next = NULL; + if (l->tail) { +@@ -56,6 +86,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->next = l->head; + tmp->prev = NULL; + if (l->head) { +@@ -93,10 +128,20 @@ + zend_llist_element *current=l->head; + zend_llist_element *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (compare(current->data, element)) { + DEL_LLIST_ELEMENT(current, l); ++#if HARDENING_PATCH_LL_PROTECT ++ current->canary = 0; ++#endif + break; + } + current = next; +@@ -108,7 +153,14 @@ + { + zend_llist_element *current=l->head, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (l->dtor) { + l->dtor(current->data); +@@ -133,7 +185,14 @@ + zend_llist_element *old_tail; + void *data; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if ((old_tail = l->tail)) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(old_tail) ++#endif + if (l->tail->prev) { + l->tail->prev->next = NULL; + } +@@ -159,9 +218,16 @@ + { + zend_llist_element *ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(src) ++#endif + zend_llist_init(dst, src->size, src->dtor, src->persistent); + ptr = src->head; + while (ptr) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(ptr) ++#endif + zend_llist_add_element(dst, ptr->data); + ptr = ptr->next; + } +@@ -172,11 +238,21 @@ + { + zend_llist_element *element, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + element=l->head; + while (element) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + next = element->next; + if (func(element->data)) { + DEL_LLIST_ELEMENT(element, l); ++#if HARDENING_PATCH_LL_PROTECT ++ element->canary = 0; ++#endif + } + element = next; + } +@@ -187,7 +263,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data TSRMLS_CC); + } + } +@@ -199,6 +281,9 @@ + zend_llist_element **elements; + zend_llist_element *element, **ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + if (l->count <= 0) { + return; + } +@@ -208,6 +293,9 @@ + ptr = &elements[0]; + + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + *ptr++ = element; + } + +@@ -230,7 +318,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, arg TSRMLS_CC); + } + } +@@ -241,8 +335,14 @@ + zend_llist_element *element; + va_list args; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + va_start(args, num_args); + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, num_args, args TSRMLS_CC); + } + va_end(args); +@@ -251,6 +351,10 @@ + + ZEND_API int zend_llist_count(zend_llist *l) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + return l->count; + } + +@@ -259,8 +363,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->head; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -272,8 +383,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->tail; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -285,9 +403,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->next; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +@@ -299,9 +427,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->prev; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +diff -Naur php-5.0.4/Zend/zend_llist.h hardening-patch-5.0.4-0.3.2/Zend/zend_llist.h +--- php-5.0.4/Zend/zend_llist.h 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_llist.h 2005-06-26 22:17:28.000000000 +0200 +@@ -23,6 +23,9 @@ + #define ZEND_LLIST_H + + typedef struct _zend_llist_element { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary; ++#endif + struct _zend_llist_element *next; + struct _zend_llist_element *prev; + char data[1]; /* Needs to always be last in the struct */ +@@ -35,6 +38,9 @@ + typedef void (*llist_apply_func_t)(void * TSRMLS_DC); + + typedef struct _zend_llist { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_h; /* head */ ++#endif + zend_llist_element *head; + zend_llist_element *tail; + size_t count; +@@ -42,6 +48,9 @@ + llist_dtor_func_t dtor; + unsigned char persistent; + zend_llist_element *traverse_ptr; ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_t; /* tail */ ++#endif + } zend_llist; + + typedef zend_llist_element* zend_llist_position; +diff -Naur php-5.0.4/Zend/zend_modules.h hardening-patch-5.0.4-0.3.2/Zend/zend_modules.h +--- php-5.0.4/Zend/zend_modules.h 2005-03-16 00:47:12.000000000 +0100 ++++ hardening-patch-5.0.4-0.3.2/Zend/zend_modules.h 2005-06-28 14:48:10.000000000 +0200 +@@ -38,7 +38,7 @@ + extern struct _zend_arg_info fourth_arg_force_ref[5]; + extern struct _zend_arg_info all_args_by_ref[1]; + +-#define ZEND_MODULE_API_NO 20041030 ++#define ZEND_MODULE_API_NO 1020050627 + #ifdef ZTS + #define USING_ZTS 1 + #else diff --git a/0.4.2/hardening-patch-4.3.11-0.4.2.patch b/0.4.2/hardening-patch-4.3.11-0.4.2.patch new file mode 100644 index 0000000..c22d3a3 --- /dev/null +++ b/0.4.2/hardening-patch-4.3.11-0.4.2.patch @@ -0,0 +1,14426 @@ +diff -Nura php-4.3.11/acinclude.m4 hardening-patch-4.3.11-0.4.2/acinclude.m4 +--- php-4.3.11/acinclude.m4 2005-01-25 14:03:06.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/acinclude.m4 2005-09-07 18:41:00.920109032 +0200 +@@ -1173,6 +1173,36 @@ + fi + ]) + ++dnl ++dnl Check for broken realpath() ++dnl ++dnl realpath("/etc/hosts/../passwd",XXX) should not return ++dnl "/etc/passwd" ++dnl ++AC_DEFUN([PHP_AC_BROKEN_REALPATH],[ ++ AC_CACHE_CHECK(whether realpath is broken, ac_cv_broken_realpath,[ ++ AC_TRY_RUN([ ++main() { ++ char buf[4096+1]; ++ buf[0] = 0; ++ realpath("/etc/hosts/../passwd", buf); ++ exit(strcmp(buf, "/etc/passwd")==0); ++} ++ ],[ ++ ac_cv_broken_realpath=no ++ ],[ ++ ac_cv_broken_realpath=yes ++ ],[ ++ ac_cv_broken_realpath=no ++ ]) ++ ]) ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ AC_DEFINE(PHP_BROKEN_REALPATH, 1, [Whether realpath is broken]) ++ else ++ AC_DEFINE(PHP_BROKEN_REALPATH, 0, [Whether realpath is broken]) ++ fi ++]) ++ + dnl PHP_SHARED_MODULE(module-name, object-var, build-dir, cxx) + dnl + dnl Basically sets up the link-stage for building module-name +diff -Nura php-4.3.11/configure hardening-patch-4.3.11-0.4.2/configure +--- php-4.3.11/configure 2005-03-30 16:35:34.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/configure 2005-09-07 19:04:56.159919416 +0200 +@@ -394,6 +394,16 @@ + ac_default_prefix=/usr/local + # Any additions from configure.in: + ac_help="$ac_help ++ --disable-hardening-patch-mm-protect Disable the Memory Manager protection." ++ac_help="$ac_help ++ --disable-hardening-patch-ll-protect Disable the Linked List protection." ++ac_help="$ac_help ++ --disable-hardening-patch-inc-protect Disable include/require protection." ++ac_help="$ac_help ++ --disable-hardening-patch-fmt-protect Disable format string protection." ++ac_help="$ac_help ++ --disable-hardening-patch-hash-protect Disable Zend HashTable DTOR protection." ++ac_help="$ac_help + + SAPI modules: + " +@@ -846,6 +856,8 @@ + ac_help="$ac_help + --disable-tokenizer Disable tokenizer support" + ac_help="$ac_help ++ --disable-varfilter Disable Hardening-Patch's variable filter" ++ac_help="$ac_help + --enable-wddx Enable WDDX support." + ac_help="$ac_help + --disable-xml Disable XML support using bundled expat lib" +@@ -2669,6 +2681,157 @@ + + + ++# Check whether --enable-hardening-patch-mm-protect or --disable-hardening-patch-mm-protect was given. ++if test "${enable_hardening_patch_mm_protect+set}" = set; then ++ enableval="$enable_hardening_patch_mm_protect" ++ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-ll-protect or --disable-hardening-patch-ll-protect was given. ++if test "${enable_hardening_patch_ll_protect+set}" = set; then ++ enableval="$enable_hardening_patch_ll_protect" ++ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-inc-protect or --disable-hardening-patch-inc-protect was given. ++if test "${enable_hardening_patch_inc_protect+set}" = set; then ++ enableval="$enable_hardening_patch_inc_protect" ++ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-fmt-protect or --disable-hardening-patch-fmt-protect was given. ++if test "${enable_hardening_patch_fmt_protect+set}" = set; then ++ enableval="$enable_hardening_patch_fmt_protect" ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-hash-protect or --disable-hardening-patch-hash-protect was given. ++if test "${enable_hardening_patch_hash_protect+set}" = set; then ++ enableval="$enable_hardening_patch_hash_protect" ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++ ++fi ++ ++ ++echo $ac_n "checking whether to protect the Zend Memory Manager""... $ac_c" 1>&6 ++echo "configure:2725: checking whether to protect the Zend Memory Manager" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_MM_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend Linked Lists""... $ac_c" 1>&6 ++echo "configure:2729: checking whether to protect the Zend Linked Lists" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_LL_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect include/require statements""... $ac_c" 1>&6 ++echo "configure:2733: checking whether to protect include/require statements" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_INC_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect PHP Format String functions""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect PHP Format String functions" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_FMT_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend HashTable Destructors""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect the Zend HashTable Destructors" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_HASH_PROTECT" 1>&6 ++ ++ ++cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH 1 ++EOF ++ ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 0 ++EOF ++ ++fi + + + +@@ -15486,6 +15649,62 @@ + fi + + ++ echo $ac_n "checking whether realpath is broken""... $ac_c" 1>&6 ++echo "configure:14928: checking whether realpath is broken" >&5 ++if eval "test \"`echo '$''{'ac_cv_broken_realpath'+set}'`\" = set"; then ++ echo $ac_n "(cached) $ac_c" 1>&6 ++else ++ ++ if test "$cross_compiling" = yes; then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null ++then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ echo "configure: failed program was:" >&5 ++ cat conftest.$ac_ext >&5 ++ rm -fr conftest* ++ ++ ac_cv_broken_realpath=yes ++ ++fi ++rm -fr conftest* ++fi ++ ++ ++fi ++ ++echo "$ac_t""$ac_cv_broken_realpath" 1>&6 ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 1 ++EOF ++ ++ else ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 0 ++EOF ++ ++ fi ++ ++ + echo $ac_n "checking for declared timezone""... $ac_c" 1>&6 + echo "configure:15491: checking for declared timezone" >&5 + if eval "test \"`echo '$''{'ac_cv_declared_timezone'+set}'`\" = set"; then +@@ -81938,7 +82157,7 @@ + if test "$ac_cv_crypt_blowfish" = "yes"; then + ac_result=1 + else +- ac_result=0 ++ ac_result=1 + fi + cat >> confdefs.h <&6 ++echo "configure:82041: checking whether to enable Hardening-Patch's variable filter" >&5 ++# Check whether --enable-varfilter or --disable-varfilter was given. ++if test "${enable_varfilter+set}" = set; then ++ enableval="$enable_varfilter" ++ PHP_VARFILTER=$enableval ++else ++ ++ PHP_VARFILTER=yes ++ ++ if test "$PHP_ENABLE_ALL" && test "yes" = "yes"; then ++ PHP_VARFILTER=$PHP_ENABLE_ALL ++ fi ++ ++fi ++ ++ ++ ++ext_output="yes, shared" ++ext_shared=yes ++case $PHP_VARFILTER in ++shared,*) ++ PHP_VARFILTER=`echo "$PHP_VARFILTER"|sed 's/^shared,//'` ++ ;; ++shared) ++ PHP_VARFILTER=yes ++ ;; ++no) ++ ext_output=no ++ ext_shared=no ++ ;; ++*) ++ ext_output=yes ++ ext_shared=no ++ ;; ++esac ++ ++ ++ ++echo "$ac_t""$ext_output" 1>&6 ++ ++ ++ ++ ++if test "$PHP_VARFILTER" != "no"; then ++ cat >> confdefs.h <<\EOF ++#define HAVE_VARFILTER 1 ++EOF ++ ++ ++ ext_builddir=ext/varfilter ++ ext_srcdir=$abs_srcdir/ext/varfilter ++ ++ ac_extra= ++ ++ if test "$ext_shared" != "shared" && test "$ext_shared" != "yes" && test "" != "cli"; then ++ ++ ++ ++ case ext/varfilter in ++ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;; ++ /*) ac_srcdir=`echo "ext/varfilter"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;; ++ *) ac_srcdir="$abs_srcdir/ext/varfilter/"; ac_bdir="ext/varfilter/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;; ++ esac ++ ++ ++ ++ b_c_pre=$php_c_pre ++ b_cxx_pre=$php_cxx_pre ++ b_c_meta=$php_c_meta ++ b_cxx_meta=$php_cxx_meta ++ b_c_post=$php_c_post ++ b_cxx_post=$php_cxx_post ++ b_lo=$php_lo ++ ++ ++ old_IFS=$IFS ++ for ac_src in varfilter.c; do ++ ++ IFS=. ++ set $ac_src ++ ac_obj=$1 ++ IFS=$old_IFS ++ ++ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo" ++ ++ case $ac_src in ++ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;; ++ *.cpp) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;; ++ esac ++ ++ cat >>Makefile.objects<>Makefile.objects<>Makefile.objects<> confdefs.h <>Makefile.objects<>Makefile.objects<&6 +@@ -98629,7 +99107,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c; do ++ output.c memory_streams.c user_streams.c hardening_patch.c; do + + IFS=. + set $ac_src +@@ -98802,7 +99280,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c; do ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c; do + + IFS=. + set $ac_src +diff -Nura php-4.3.11/configure.in hardening-patch-4.3.11-0.4.2/configure.in +--- php-4.3.11/configure.in 2005-03-30 16:18:36.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/configure.in 2005-09-07 18:41:00.957103408 +0200 +@@ -227,7 +227,7 @@ + sinclude(Zend/acinclude.m4) + sinclude(Zend/Zend.m4) + sinclude(TSRM/tsrm.m4) +- ++sinclude(main/hardening_patch.m4) + + + divert(2) +@@ -595,6 +595,7 @@ + AC_FUNC_ALLOCA + dnl PHP_AC_BROKEN_SPRINTF + dnl PHP_AC_BROKEN_SNPRINTF ++PHP_AC_BROKEN_REALPATH + PHP_DECLARED_TIMEZONE + PHP_TIME_R_TYPE + PHP_READDIR_R_TYPE +@@ -1224,7 +1225,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c) ++ output.c memory_streams.c user_streams.c hardening_patch.c) + PHP_ADD_SOURCES(/main, internal_functions.c,, sapi) + PHP_ADD_SOURCES(/main, internal_functions_cli.c,, cli) + +@@ -1237,7 +1238,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c) ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c ) + + if test -r "$abs_srcdir/Zend/zend_objects.c"; then + PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_mm.c) +diff -Nura php-4.3.11/ext/calendar/calendar.c hardening-patch-4.3.11-0.4.2/ext/calendar/calendar.c +--- php-4.3.11/ext/calendar/calendar.c 2003-08-28 22:01:24.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/ext/calendar/calendar.c 2005-09-07 18:41:00.958103256 +0200 +@@ -300,7 +300,7 @@ + { + pval **julday; + int year, month, day; +- char date[10]; ++ char date[16]; + + if (zend_get_parameters_ex(1, &julday) != SUCCESS) { + WRONG_PARAM_COUNT; +@@ -341,7 +341,7 @@ + { + pval **julday; + int year, month, day; +- char date[10]; ++ char date[16]; + + if (zend_get_parameters_ex(1, &julday) != SUCCESS) { + WRONG_PARAM_COUNT; +@@ -453,7 +453,7 @@ + { + long julday, fl; + int year, month, day; +- char date[10], hebdate[25]; ++ char date[16], hebdate[25]; + char *dayp, *yearp; + + if (ZEND_NUM_ARGS() == 1) { +@@ -521,7 +521,7 @@ + { + pval **julday; + int year, month, day; +- char date[10]; ++ char date[16]; + + if (zend_get_parameters_ex(1, &julday) != SUCCESS) { + WRONG_PARAM_COUNT; +diff -Nura php-4.3.11/ext/fbsql/php_fbsql.c hardening-patch-4.3.11-0.4.2/ext/fbsql/php_fbsql.c +--- php-4.3.11/ext/fbsql/php_fbsql.c 2005-02-09 20:33:32.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/fbsql/php_fbsql.c 2005-09-07 18:41:00.960102952 +0200 +@@ -1797,8 +1797,24 @@ + } + else if (fbcmdErrorsFound(md)) + { ++#if HARDENING_PATCH ++ char* query_copy; ++ int i; ++#endif + FBCErrorMetaData* emd = fbcdcErrorMetaData(c, md); + char* emg = fbcemdAllErrorMessages(emd); ++#if HARDENING_PATCH ++ query_copy=estrdup(query_copy); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "fbsql error: %s - query: %s", emg, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ free(emg); ++ fbcemdRelease(emd); ++ result = 0; ++ zend_bailout(); ++ } ++#endif + if (FB_SQL_G(generateWarnings)) + { + if (emg) +diff -Nura php-4.3.11/ext/mbstring/mbstring.c hardening-patch-4.3.11-0.4.2/ext/mbstring/mbstring.c +--- php-4.3.11/ext/mbstring/mbstring.c 2005-02-21 09:03:47.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/mbstring/mbstring.c 2005-09-07 18:41:00.962102648 +0200 +@@ -1487,6 +1487,7 @@ + char *strtok_buf = NULL, **val_list; + zval *array_ptr = (zval *) arg; + int n, num, val_len, *len_list; ++ unsigned int new_val_len; + enum mbfl_no_encoding from_encoding; + mbfl_string string, resvar, resval; + mbfl_encoding_detector *identd = NULL; +@@ -1609,8 +1610,14 @@ + val_len = len_list[n]; + } + n++; +- /* add variable to symbol table */ +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ /* we need val to be emalloc()ed */ ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(info->data_type, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ /* add variable to symbol table */ ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); ++ + if (convd != NULL){ + mbfl_string_clear(&resvar); + mbfl_string_clear(&resval); +diff -Nura php-4.3.11/ext/mysql/php_mysql.c hardening-patch-4.3.11-0.4.2/ext/mysql/php_mysql.c +--- php-4.3.11/ext/mysql/php_mysql.c 2005-02-22 16:00:49.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/mysql/php_mysql.c 2005-09-07 18:41:00.963102496 +0200 +@@ -1215,6 +1215,8 @@ + { + php_mysql_conn *mysql; + MYSQL_RES *mysql_result; ++ char *copy_query; ++ int i; + + ZEND_FETCH_RESOURCE2(mysql, php_mysql_conn *, mysql_link, link_id, "MySQL-Link", le_link, le_plink); + +@@ -1265,6 +1267,13 @@ + php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #else +@@ -1272,12 +1281,20 @@ + /* check possible error */ + if (MySG(trace_mode)){ + if (mysql_errno(&mysql->conn)){ +- php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, mysql_error(&mysql->conn)); ++ php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #endif ++ + if(use_store == MYSQL_USE_RESULT) { + mysql_result=mysql_use_result(&mysql->conn); + } else { +diff -Nura php-4.3.11/ext/pgsql/pgsql.c hardening-patch-4.3.11-0.4.2/ext/pgsql/pgsql.c +--- php-4.3.11/ext/pgsql/pgsql.c 2004-05-12 18:49:56.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/ext/pgsql/pgsql.c 2005-09-07 18:41:00.965102192 +0200 +@@ -997,10 +997,28 @@ + case PGRES_EMPTY_QUERY: + case PGRES_BAD_RESPONSE: + case PGRES_NONFATAL_ERROR: +- case PGRES_FATAL_ERROR: +- PHP_PQ_ERROR("Query failed: %s", pgsql); +- PQclear(pgsql_result); +- RETURN_FALSE; ++ case PGRES_FATAL_ERROR: ++ { ++#if HARDENING_PATCH ++ int i; ++ char *query_copy; ++#endif ++ char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); ++ PQclear(pgsql_result); ++#if HARDENING_PATCH ++ query_copy = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "PgSQL error: %s - query: %s", msgbuf, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ efree(msgbuf); ++ zend_bailout(); ++ } ++#endif ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Query failed: %s", msgbuf); ++ efree(msgbuf); ++ RETURN_FALSE; ++ } + break; + case PGRES_COMMAND_OK: /* successful command that did not return rows */ + default: +diff -Nura php-4.3.11/ext/standard/array.c hardening-patch-4.3.11-0.4.2/ext/standard/array.c +--- php-4.3.11/ext/standard/array.c 2004-12-23 17:40:03.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/array.c 2005-09-07 18:41:00.967101888 +0200 +@@ -1153,6 +1153,32 @@ + } + } + } ++ ++ if (var_name[0] == 'H') { ++ if ((strcmp(var_name, "HTTP_GET_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_FILES")==0)|| ++ (strcmp(var_name, "HTTP_ENV_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(var_name, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(var_name, "HTTP_RAW_POST_DATA")==0)) { ++ return 0; ++ } ++ } else if (var_name[0] == '_') { ++ if ((strcmp(var_name, "_COOKIE")==0)|| ++ (strcmp(var_name, "_ENV")==0)|| ++ (strcmp(var_name, "_FILES")==0)|| ++ (strcmp(var_name, "_GET")==0)|| ++ (strcmp(var_name, "_POST")==0)|| ++ (strcmp(var_name, "_REQUEST")==0)|| ++ (strcmp(var_name, "_SESSION")==0)|| ++ (strcmp(var_name, "_SERVER")==0)) { ++ return 0; ++ } ++ } else if (strcmp(var_name, "GLOBALS")==0) { ++ return 0; ++ } + + return 1; + } +diff -Nura php-4.3.11/ext/standard/basic_functions.c hardening-patch-4.3.11-0.4.2/ext/standard/basic_functions.c +--- php-4.3.11/ext/standard/basic_functions.c 2005-01-18 12:01:20.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/basic_functions.c 2005-09-07 19:04:56.161919112 +0200 +@@ -118,12 +118,14 @@ + typedef struct _php_shutdown_function_entry { + zval **arguments; + int arg_count; ++ zend_bool created_by_eval; + } php_shutdown_function_entry; + + typedef struct _user_tick_function_entry { + zval **arguments; + int arg_count; + int calling; ++ zend_bool created_by_eval; + } user_tick_function_entry; + + /* some prototypes for local functions */ +@@ -306,6 +308,8 @@ + PHP_FE(get_html_translation_table, NULL) + PHP_FE(sha1, NULL) + PHP_FE(sha1_file, NULL) ++ PHP_FE(sha256, NULL) ++ PHP_FE(sha256_file, NULL) + PHP_NAMED_FE(md5,php_if_md5, NULL) + PHP_NAMED_FE(md5_file,php_if_md5_file, NULL) + PHP_NAMED_FE(crc32,php_if_crc32, NULL) +@@ -687,7 +691,7 @@ + PHP_FALIAS(socket_get_status, stream_get_meta_data, NULL) + + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +- PHP_FE(realpath, NULL) ++ PHP_STATIC_FE("realpath", zif_real_path, NULL) + #endif + + #ifdef HAVE_FNMATCH +@@ -2089,6 +2093,13 @@ + static int user_shutdown_function_call(php_shutdown_function_entry *shutdown_function_entry TSRMLS_DC) + { + zval retval; ++#if HARDENING_PATCH ++ zend_uint orig_code_type = EG(in_code_type); ++ ++ if (shutdown_function_entry->created_by_eval) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } ++#endif + + if (call_user_function( EG(function_table), NULL, + shutdown_function_entry->arguments[0], +@@ -2101,6 +2112,9 @@ + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call %s() - function does not exist", Z_STRVAL_P(shutdown_function_entry->arguments[0])); + } ++#if HARDENING_PATCH ++ EG(in_code_type) = orig_code_type; ++#endif + return 0; + } + +@@ -2108,6 +2122,13 @@ + { + zval retval; + zval *function = tick_fe->arguments[0]; ++#if HARDENING_PATCH ++ zend_uint orig_code_type = EG(in_code_type); ++ ++ if (tick_fe->created_by_eval) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } ++#endif + + /* Prevent reentrant calls to the same user ticks function */ + if (! tick_fe->calling) { +@@ -2139,6 +2160,9 @@ + + tick_fe->calling = 0; + } ++#if HARDENING_PATCH ++ EG(in_code_type) = orig_code_type; ++#endif + } + + static void run_user_tick_functions(int tick_count) +@@ -2205,6 +2229,13 @@ + if (zend_get_parameters_array(ht, shutdown_function_entry.arg_count, shutdown_function_entry.arguments) == FAILURE) { + RETURN_FALSE; + } ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ shutdown_function_entry.created_by_eval = 1; ++ } else { ++ shutdown_function_entry.created_by_eval = 0; ++ } ++#endif + + /* Prevent entering of anything but arrays/strings */ + if (Z_TYPE_P(shutdown_function_entry.arguments[0]) != IS_ARRAY) { +@@ -2737,6 +2768,13 @@ + } + + tick_fe.arguments = (zval **) safe_emalloc(sizeof(zval *), tick_fe.arg_count, 0); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ tick_fe.created_by_eval = 1; ++ } else { ++ tick_fe.created_by_eval = 0; ++ } ++#endif + + if (zend_get_parameters_array(ht, tick_fe.arg_count, tick_fe.arguments) == FAILURE) { + RETURN_FALSE; +@@ -3020,6 +3058,35 @@ + memcpy(new_key, prefix, prefix_len); + memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + ++ if (new_key[0] == 'H') { ++ if ((strcmp(new_key, "HTTP_GET_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_FILES")==0)|| ++ (strcmp(new_key, "HTTP_ENV_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(new_key, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(new_key, "HTTP_RAW_POST_DATA")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (new_key[0] == '_') { ++ if ((strcmp(new_key, "_COOKIE")==0)|| ++ (strcmp(new_key, "_ENV")==0)|| ++ (strcmp(new_key, "_FILES")==0)|| ++ (strcmp(new_key, "_GET")==0)|| ++ (strcmp(new_key, "_POST")==0)|| ++ (strcmp(new_key, "_REQUEST")==0)|| ++ (strcmp(new_key, "_SESSION")==0)|| ++ (strcmp(new_key, "_SERVER")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (strcmp(new_key, "GLOBALS")==0) { ++ efree(new_key); ++ return 0; ++ } ++ + zend_hash_del(&EG(symbol_table), new_key, new_key_len); + ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, (*var)->refcount+1, 0); + +diff -Nura php-4.3.11/ext/standard/config.m4 hardening-patch-4.3.11-0.4.2/ext/standard/config.m4 +--- php-4.3.11/ext/standard/config.m4 2004-12-30 08:02:18.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/config.m4 2005-09-07 19:04:56.161919112 +0200 +@@ -203,7 +203,7 @@ + if test "$ac_cv_crypt_blowfish" = "yes"; then + ac_result=1 + else +- ac_result=0 ++ ac_result=1 + fi + AC_DEFINE_UNQUOTED(PHP_BLOWFISH_CRYPT, $ac_result, [Whether the system supports BlowFish salt]) + ]) +@@ -419,6 +419,6 @@ + url_scanner.c var.c versioning.c assert.c strnatcmp.c levenshtein.c \ + incomplete_class.c url_scanner_ex.c ftp_fopen_wrapper.c \ + http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \ +- var_unserializer.c ftok.c aggregation.c sha1.c ) ++ var_unserializer.c ftok.c aggregation.c sha1.c sha256.c crypt_blowfish.c ) + + PHP_ADD_MAKEFILE_FRAGMENT +diff -Nura php-4.3.11/ext/standard/crypt_blowfish.c hardening-patch-4.3.11-0.4.2/ext/standard/crypt_blowfish.c +--- php-4.3.11/ext/standard/crypt_blowfish.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/crypt_blowfish.c 2005-09-07 19:04:56.163918808 +0200 +@@ -0,0 +1,748 @@ ++/* ++ * This code comes from John the Ripper password cracker, with reentrant ++ * and crypt(3) interfaces added, but optimizations specific to password ++ * cracking removed. ++ * ++ * Written by Solar Designer in 1998-2002 and ++ * placed in the public domain. ++ * ++ * There's absolutely no warranty. ++ * ++ * It is my intent that you should be able to use this on your system, ++ * as a part of a software package, or anywhere else to improve security, ++ * ensure compatibility, or for any other purpose. I would appreciate ++ * it if you give credit where it is due and keep your modifications in ++ * the public domain as well, but I don't require that in order to let ++ * you place this code and any modifications you make under a license ++ * of your choice. ++ * ++ * This implementation is compatible with OpenBSD bcrypt.c (version 2a) ++ * by Niels Provos , and uses some of his ++ * ideas. The password hashing algorithm was designed by David Mazieres ++ * . ++ * ++ * There's a paper on the algorithm that explains its design decisions: ++ * ++ * http://www.usenix.org/events/usenix99/provos.html ++ * ++ * Some of the tricks in BF_ROUND might be inspired by Eric Young's ++ * Blowfish library (I can't be sure if I would think of something if I ++ * hadn't seen his code). ++ */ ++ ++#include ++ ++#include ++#ifndef __set_errno ++#define __set_errno(val) errno = (val) ++#endif ++ ++#undef __CONST ++#ifdef __GNUC__ ++#define __CONST __const ++#else ++#define __CONST ++#endif ++ ++#ifdef __i386__ ++#define BF_ASM 0 ++#define BF_SCALE 1 ++#elif defined(__alpha__) || defined(__hppa__) ++#define BF_ASM 0 ++#define BF_SCALE 1 ++#else ++#define BF_ASM 0 ++#define BF_SCALE 0 ++#endif ++ ++typedef unsigned int BF_word; ++ ++/* Number of Blowfish rounds, this is also hardcoded into a few places */ ++#define BF_N 16 ++ ++typedef BF_word BF_key[BF_N + 2]; ++ ++typedef struct { ++ BF_word S[4][0x100]; ++ BF_key P; ++} BF_ctx; ++ ++/* ++ * Magic IV for 64 Blowfish encryptions that we do at the end. ++ * The string is "OrpheanBeholderScryDoubt" on big-endian. ++ */ ++static BF_word BF_magic_w[6] = { ++ 0x4F727068, 0x65616E42, 0x65686F6C, ++ 0x64657253, 0x63727944, 0x6F756274 ++}; ++ ++/* ++ * P-box and S-box tables initialized with digits of Pi. ++ */ ++static BF_ctx BF_init_state = { ++ { ++ { ++ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, ++ 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, ++ 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, ++ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, ++ 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, ++ 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, ++ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, ++ 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, ++ 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, ++ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, ++ 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, ++ 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, ++ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, ++ 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, ++ 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, ++ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, ++ 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, ++ 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, ++ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, ++ 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, ++ 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, ++ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, ++ 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, ++ 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, ++ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, ++ 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, ++ 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, ++ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, ++ 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, ++ 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, ++ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, ++ 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, ++ 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, ++ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, ++ 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, ++ 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, ++ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, ++ 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, ++ 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, ++ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, ++ 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, ++ 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, ++ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, ++ 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, ++ 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, ++ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, ++ 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, ++ 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, ++ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, ++ 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, ++ 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, ++ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, ++ 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, ++ 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, ++ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, ++ 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, ++ 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, ++ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, ++ 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, ++ 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, ++ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, ++ 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, ++ 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, ++ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a ++ }, { ++ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, ++ 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, ++ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, ++ 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, ++ 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, ++ 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, ++ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, ++ 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, ++ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, ++ 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, ++ 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, ++ 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, ++ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, ++ 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, ++ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, ++ 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, ++ 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, ++ 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, ++ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, ++ 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, ++ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, ++ 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, ++ 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, ++ 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, ++ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, ++ 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, ++ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, ++ 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, ++ 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, ++ 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, ++ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, ++ 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, ++ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, ++ 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, ++ 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, ++ 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, ++ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, ++ 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, ++ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, ++ 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, ++ 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, ++ 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, ++ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, ++ 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, ++ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, ++ 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, ++ 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, ++ 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, ++ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, ++ 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, ++ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, ++ 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, ++ 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, ++ 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, ++ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, ++ 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, ++ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, ++ 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, ++ 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, ++ 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, ++ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, ++ 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, ++ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, ++ 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 ++ }, { ++ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, ++ 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, ++ 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, ++ 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, ++ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, ++ 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, ++ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, ++ 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, ++ 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, ++ 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, ++ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, ++ 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, ++ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, ++ 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, ++ 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, ++ 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, ++ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, ++ 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, ++ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, ++ 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, ++ 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, ++ 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, ++ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, ++ 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, ++ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, ++ 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, ++ 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, ++ 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, ++ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, ++ 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, ++ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, ++ 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, ++ 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, ++ 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, ++ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, ++ 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, ++ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, ++ 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, ++ 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, ++ 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, ++ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, ++ 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, ++ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, ++ 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, ++ 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, ++ 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, ++ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, ++ 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, ++ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, ++ 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, ++ 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, ++ 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, ++ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, ++ 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, ++ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, ++ 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, ++ 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, ++ 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, ++ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, ++ 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, ++ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, ++ 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, ++ 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, ++ 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 ++ }, { ++ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, ++ 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, ++ 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, ++ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, ++ 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, ++ 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, ++ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, ++ 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, ++ 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, ++ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, ++ 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, ++ 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, ++ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, ++ 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, ++ 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, ++ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, ++ 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, ++ 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, ++ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, ++ 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, ++ 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, ++ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, ++ 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, ++ 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, ++ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, ++ 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, ++ 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, ++ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, ++ 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, ++ 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, ++ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, ++ 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, ++ 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, ++ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, ++ 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, ++ 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, ++ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, ++ 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, ++ 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, ++ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, ++ 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, ++ 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, ++ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, ++ 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, ++ 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, ++ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, ++ 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, ++ 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, ++ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, ++ 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, ++ 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, ++ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, ++ 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, ++ 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, ++ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, ++ 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, ++ 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, ++ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, ++ 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, ++ 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, ++ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, ++ 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, ++ 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, ++ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 ++ } ++ }, { ++ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, ++ 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, ++ 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, ++ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, ++ 0x9216d5d9, 0x8979fb1b ++ } ++}; ++ ++static unsigned char BF_itoa64[64 + 1] = ++ "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; ++ ++static unsigned char BF_atoi64[0x60] = { ++ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, ++ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64, ++ 64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ++ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64, ++ 64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, ++ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 ++}; ++ ++/* ++ * This may be optimized out if built with function inlining and no BF_ASM. ++ */ ++static void clean(void *data, int size) ++{ ++#if BF_ASM ++ extern void _BF_clean(void *data); ++#endif ++ memset(data, 0, size); ++#if BF_ASM ++ _BF_clean(data); ++#endif ++} ++ ++#define BF_safe_atoi64(dst, src) \ ++{ \ ++ tmp = (unsigned char)(src); \ ++ if (tmp == '$') break; \ ++ if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ ++ tmp = BF_atoi64[tmp]; \ ++ if (tmp > 63) return -1; \ ++ (dst) = tmp; \ ++} ++ ++static int BF_decode(BF_word *dst, __CONST char *src, int size) ++{ ++ unsigned char *dptr = (unsigned char *)dst; ++ unsigned char *end = dptr + size; ++ unsigned char *sptr = (unsigned char *)src; ++ unsigned int tmp, c1, c2, c3, c4; ++ ++ do { ++ BF_safe_atoi64(c1, *sptr++); ++ BF_safe_atoi64(c2, *sptr++); ++ *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4); ++ if (dptr >= end) break; ++ ++ BF_safe_atoi64(c3, *sptr++); ++ *dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2); ++ if (dptr >= end) break; ++ ++ BF_safe_atoi64(c4, *sptr++); ++ *dptr++ = ((c3 & 0x03) << 6) | c4; ++ } while (dptr < end); ++ ++ while (dptr < end) ++ *dptr++ = 0; ++ ++ return 0; ++} ++ ++static void BF_encode(char *dst, __CONST BF_word *src, int size) ++{ ++ unsigned char *sptr = (unsigned char *)src; ++ unsigned char *end = sptr + size; ++ unsigned char *dptr = (unsigned char *)dst; ++ unsigned int c1, c2; ++ ++ do { ++ c1 = *sptr++; ++ *dptr++ = BF_itoa64[c1 >> 2]; ++ c1 = (c1 & 0x03) << 4; ++ if (sptr >= end) { ++ *dptr++ = BF_itoa64[c1]; ++ break; ++ } ++ ++ c2 = *sptr++; ++ c1 |= c2 >> 4; ++ *dptr++ = BF_itoa64[c1]; ++ c1 = (c2 & 0x0f) << 2; ++ if (sptr >= end) { ++ *dptr++ = BF_itoa64[c1]; ++ break; ++ } ++ ++ c2 = *sptr++; ++ c1 |= c2 >> 6; ++ *dptr++ = BF_itoa64[c1]; ++ *dptr++ = BF_itoa64[c2 & 0x3f]; ++ } while (sptr < end); ++} ++ ++static void BF_swap(BF_word *x, int count) ++{ ++ static int endianness_check = 1; ++ char *is_little_endian = (char *)&endianness_check; ++ BF_word tmp; ++ ++ if (*is_little_endian) ++ do { ++ tmp = *x; ++ tmp = (tmp << 16) | (tmp >> 16); ++ *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF); ++ } while (--count); ++} ++ ++#if BF_SCALE ++/* Architectures which can shift addresses left by 2 bits with no extra cost */ ++#define BF_ROUND(L, R, N) \ ++ tmp1 = L & 0xFF; \ ++ tmp2 = L >> 8; \ ++ tmp2 &= 0xFF; \ ++ tmp3 = L >> 16; \ ++ tmp3 &= 0xFF; \ ++ tmp4 = L >> 24; \ ++ tmp1 = data.ctx.S[3][tmp1]; \ ++ tmp2 = data.ctx.S[2][tmp2]; \ ++ tmp3 = data.ctx.S[1][tmp3]; \ ++ tmp3 += data.ctx.S[0][tmp4]; \ ++ tmp3 ^= tmp2; \ ++ R ^= data.ctx.P[N + 1]; \ ++ tmp3 += tmp1; \ ++ R ^= tmp3; ++#else ++/* Architectures with no complicated addressing modes supported */ ++#define BF_INDEX(S, i) \ ++ (*((BF_word *)(((unsigned char *)S) + (i)))) ++#define BF_ROUND(L, R, N) \ ++ tmp1 = L & 0xFF; \ ++ tmp1 <<= 2; \ ++ tmp2 = L >> 6; \ ++ tmp2 &= 0x3FC; \ ++ tmp3 = L >> 14; \ ++ tmp3 &= 0x3FC; \ ++ tmp4 = L >> 22; \ ++ tmp4 &= 0x3FC; \ ++ tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \ ++ tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \ ++ tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \ ++ tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \ ++ tmp3 ^= tmp2; \ ++ R ^= data.ctx.P[N + 1]; \ ++ tmp3 += tmp1; \ ++ R ^= tmp3; ++#endif ++ ++/* ++ * Encrypt one block, BF_N is hardcoded here. ++ */ ++#define BF_ENCRYPT \ ++ L ^= data.ctx.P[0]; \ ++ BF_ROUND(L, R, 0); \ ++ BF_ROUND(R, L, 1); \ ++ BF_ROUND(L, R, 2); \ ++ BF_ROUND(R, L, 3); \ ++ BF_ROUND(L, R, 4); \ ++ BF_ROUND(R, L, 5); \ ++ BF_ROUND(L, R, 6); \ ++ BF_ROUND(R, L, 7); \ ++ BF_ROUND(L, R, 8); \ ++ BF_ROUND(R, L, 9); \ ++ BF_ROUND(L, R, 10); \ ++ BF_ROUND(R, L, 11); \ ++ BF_ROUND(L, R, 12); \ ++ BF_ROUND(R, L, 13); \ ++ BF_ROUND(L, R, 14); \ ++ BF_ROUND(R, L, 15); \ ++ tmp4 = R; \ ++ R = L; \ ++ L = tmp4 ^ data.ctx.P[BF_N + 1]; ++ ++#if BF_ASM ++#define BF_body() \ ++ _BF_body_r(&data.ctx); ++#else ++#define BF_body() \ ++ L = R = 0; \ ++ ptr = data.ctx.P; \ ++ do { \ ++ ptr += 2; \ ++ BF_ENCRYPT; \ ++ *(ptr - 2) = L; \ ++ *(ptr - 1) = R; \ ++ } while (ptr < &data.ctx.P[BF_N + 2]); \ ++\ ++ ptr = data.ctx.S[0]; \ ++ do { \ ++ ptr += 2; \ ++ BF_ENCRYPT; \ ++ *(ptr - 2) = L; \ ++ *(ptr - 1) = R; \ ++ } while (ptr < &data.ctx.S[3][0xFF]); ++#endif ++ ++static void BF_set_key(__CONST char *key, BF_key expanded, BF_key initial) ++{ ++ __CONST char *ptr = key; ++ int i, j; ++ BF_word tmp; ++ ++ for (i = 0; i < BF_N + 2; i++) { ++ tmp = 0; ++ for (j = 0; j < 4; j++) { ++ tmp <<= 8; ++ tmp |= *ptr; ++ ++ if (!*ptr) ptr = key; else ptr++; ++ } ++ ++ expanded[i] = tmp; ++ initial[i] = BF_init_state.P[i] ^ tmp; ++ } ++} ++ ++char *_crypt_blowfish_rn(__CONST char *key, __CONST char *setting, ++ char *output, int size) ++{ ++#if BF_ASM ++ extern void _BF_body_r(BF_ctx *ctx); ++#endif ++ struct { ++ BF_ctx ctx; ++ BF_key expanded_key; ++ union { ++ BF_word salt[4]; ++ BF_word output[6]; ++ } binary; ++ } data; ++ BF_word L, R; ++ BF_word tmp1, tmp2, tmp3, tmp4; ++ BF_word *ptr; ++ BF_word count; ++ int i; ++ ++ if (size < 7 + 22 + 31 + 1) { ++ __set_errno(ERANGE); ++ return NULL; ++ } ++ ++ if (setting[0] != '$' || ++ setting[1] != '2' || ++ setting[2] != 'a' || ++ setting[3] != '$' || ++ setting[4] < '0' || setting[4] > '3' || ++ setting[5] < '0' || setting[5] > '9' || ++ setting[6] != '$') { ++ __set_errno(EINVAL); ++ return NULL; ++ } ++ ++ count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); ++ if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16)) { ++ clean(data.binary.salt, sizeof(data.binary.salt)); ++ __set_errno(EINVAL); ++ return NULL; ++ } ++ ++ BF_swap(data.binary.salt, 4); ++ ++ BF_set_key(key, data.expanded_key, data.ctx.P); ++ ++ memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); ++ ++ L = R = 0; ++ for (i = 0; i < BF_N + 2; i += 2) { ++ L ^= data.binary.salt[i & 2]; ++ R ^= data.binary.salt[(i & 2) + 1]; ++ BF_ENCRYPT; ++ data.ctx.P[i] = L; ++ data.ctx.P[i + 1] = R; ++ } ++ ++ ptr = data.ctx.S[0]; ++ do { ++ ptr += 4; ++ L ^= data.binary.salt[(BF_N + 2) & 3]; ++ R ^= data.binary.salt[(BF_N + 3) & 3]; ++ BF_ENCRYPT; ++ *(ptr - 4) = L; ++ *(ptr - 3) = R; ++ ++ L ^= data.binary.salt[(BF_N + 4) & 3]; ++ R ^= data.binary.salt[(BF_N + 5) & 3]; ++ BF_ENCRYPT; ++ *(ptr - 2) = L; ++ *(ptr - 1) = R; ++ } while (ptr < &data.ctx.S[3][0xFF]); ++ ++ do { ++ data.ctx.P[0] ^= data.expanded_key[0]; ++ data.ctx.P[1] ^= data.expanded_key[1]; ++ data.ctx.P[2] ^= data.expanded_key[2]; ++ data.ctx.P[3] ^= data.expanded_key[3]; ++ data.ctx.P[4] ^= data.expanded_key[4]; ++ data.ctx.P[5] ^= data.expanded_key[5]; ++ data.ctx.P[6] ^= data.expanded_key[6]; ++ data.ctx.P[7] ^= data.expanded_key[7]; ++ data.ctx.P[8] ^= data.expanded_key[8]; ++ data.ctx.P[9] ^= data.expanded_key[9]; ++ data.ctx.P[10] ^= data.expanded_key[10]; ++ data.ctx.P[11] ^= data.expanded_key[11]; ++ data.ctx.P[12] ^= data.expanded_key[12]; ++ data.ctx.P[13] ^= data.expanded_key[13]; ++ data.ctx.P[14] ^= data.expanded_key[14]; ++ data.ctx.P[15] ^= data.expanded_key[15]; ++ data.ctx.P[16] ^= data.expanded_key[16]; ++ data.ctx.P[17] ^= data.expanded_key[17]; ++ ++ BF_body(); ++ ++ tmp1 = data.binary.salt[0]; ++ tmp2 = data.binary.salt[1]; ++ tmp3 = data.binary.salt[2]; ++ tmp4 = data.binary.salt[3]; ++ data.ctx.P[0] ^= tmp1; ++ data.ctx.P[1] ^= tmp2; ++ data.ctx.P[2] ^= tmp3; ++ data.ctx.P[3] ^= tmp4; ++ data.ctx.P[4] ^= tmp1; ++ data.ctx.P[5] ^= tmp2; ++ data.ctx.P[6] ^= tmp3; ++ data.ctx.P[7] ^= tmp4; ++ data.ctx.P[8] ^= tmp1; ++ data.ctx.P[9] ^= tmp2; ++ data.ctx.P[10] ^= tmp3; ++ data.ctx.P[11] ^= tmp4; ++ data.ctx.P[12] ^= tmp1; ++ data.ctx.P[13] ^= tmp2; ++ data.ctx.P[14] ^= tmp3; ++ data.ctx.P[15] ^= tmp4; ++ data.ctx.P[16] ^= tmp1; ++ data.ctx.P[17] ^= tmp2; ++ ++ BF_body(); ++ } while (--count); ++ ++ for (i = 0; i < 6; i += 2) { ++ L = BF_magic_w[i]; ++ R = BF_magic_w[i + 1]; ++ ++ count = 64; ++ do { ++ BF_ENCRYPT; ++ } while (--count); ++ ++ data.binary.output[i] = L; ++ data.binary.output[i + 1] = R; ++ } ++ ++ memcpy(output, setting, 7 + 22 - 1); ++ output[7 + 22 - 1] = BF_itoa64[(int) ++ BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30]; ++ ++/* This has to be bug-compatible with the original implementation, so ++ * only encode 23 of the 24 bytes. :-) */ ++ BF_swap(data.binary.output, 6); ++ BF_encode(&output[7 + 22], data.binary.output, 23); ++ output[7 + 22 + 31] = '\0'; ++ ++/* Overwrite the most obvious sensitive data we have on the stack. Note ++ * that this does not guarantee there's no sensitive data left on the ++ * stack and/or in registers; I'm not aware of portable code that does. */ ++ clean(&data, sizeof(data)); ++ ++ return output; ++} ++ ++char *_crypt_gensalt_blowfish_rn(unsigned long count, ++ __CONST char *input, int size, char *output, int output_size) ++{ ++ if (size < 16 || output_size < 7 + 22 + 1 || ++ (count && (count < 4 || count > 31))) { ++ if (output_size > 0) output[0] = '\0'; ++ __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); ++ return NULL; ++ } ++ ++ if (!count) count = 5; ++ ++ output[0] = '$'; ++ output[1] = '2'; ++ output[2] = 'a'; ++ output[3] = '$'; ++ output[4] = '0' + count / 10; ++ output[5] = '0' + count % 10; ++ output[6] = '$'; ++ ++ BF_encode(&output[7], (BF_word *)input, 16); ++ output[7 + 22] = '\0'; ++ ++ return output; ++} +diff -Nura php-4.3.11/ext/standard/crypt.c hardening-patch-4.3.11-0.4.2/ext/standard/crypt.c +--- php-4.3.11/ext/standard/crypt.c 2004-01-19 04:16:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/crypt.c 2005-09-07 19:04:56.163918808 +0200 +@@ -100,6 +100,8 @@ + return SUCCESS; + } + ++char *_crypt_blowfish_rn(char *key, char *setting, char *output, int size); ++char *_crypt_gensalt_blowfish_rn(unsigned long count, char *input, int size, char *output, int output_size); + + static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +@@ -135,7 +137,14 @@ + + /* The automatic salt generation only covers standard DES and md5-crypt */ + if(!*salt) { +-#if PHP_MD5_CRYPT ++#if PHP_BLOWFISH_CRYPT ++ char randat[16]; ++ int i; ++ ++ for (i=0; i<16; i++) randat[i] = PHP_CRYPT_RAND; ++ ++ _crypt_gensalt_blowfish_rn(5, randat, sizeof(randat), salt, sizeof(salt)); ++#elif PHP_MD5_CRYPT + strcpy(salt, "$1$"); + php_to64(&salt[3], PHP_CRYPT_RAND, 4); + php_to64(&salt[7], PHP_CRYPT_RAND, 4); +@@ -145,8 +154,24 @@ + salt[2] = '\0'; + #endif + } +- +- RETVAL_STRING(crypt(str, salt), 1); ++ ++ if (salt[0] == '$' && ++ salt[1] == '2' && ++ salt[2] == 'a' && ++ salt[3] == '$' && ++ salt[4] >= '0' && salt[4] <= '3' && ++ salt[5] >= '0' && salt[5] <= '9' && ++ salt[6] == '$') { ++ ++ char output[PHP_MAX_SALT_LEN+1]; ++ ++ output[0] = 0; ++ _crypt_blowfish_rn(str, salt, output, sizeof(output)); ++ RETVAL_STRING(output, 1); ++ ++ } else { ++ RETVAL_STRING(crypt(str, salt), 1); ++ } + } + /* }}} */ + #endif +diff -Nura php-4.3.11/ext/standard/dl.c hardening-patch-4.3.11-0.4.2/ext/standard/dl.c +--- php-4.3.11/ext/standard/dl.c 2003-01-29 16:40:24.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/dl.c 2005-09-07 18:41:00.970101432 +0200 +@@ -182,8 +182,35 @@ + RETURN_FALSE; + } + module_entry = get_module(); ++ ++ /* check if Hardening-Patch is installed */ ++ if (module_entry->zend_api < 1000000000) { ++ php_error_docref(NULL TSRMLS_CC, error_type, ++ "%s: Unable to initialize module\n" ++ "Module compiled without Hardening-Patch, module API=%d, debug=%d, thread-safety=%d\n" ++ "PHP compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "These options need to match\n", ++ module_entry->name, module_entry->zend_api, module_entry->zend_debug, module_entry->zts, ++ HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS); ++ DL_UNLOAD(handle); ++ RETURN_FALSE; ++ } ++ ++ /* check if correct Hardening-Patch is installed */ ++ if (module_entry->zend_api != HARDENING_PATCH_ZEND_MODULE_API_NO) { ++ php_error_docref(NULL TSRMLS_CC, error_type, ++ "%s: Unable to initialize module\n" ++ "Module compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "PHP compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "These options need to match\n", ++ module_entry->name, module_entry->zend_api, module_entry->real_zend_api, module_entry->zend_debug, module_entry->zts, ++ HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS); ++ DL_UNLOAD(handle); ++ RETURN_FALSE; ++ } ++ + if ((module_entry->zend_debug != ZEND_DEBUG) || (module_entry->zts != USING_ZTS) +- || (module_entry->zend_api != ZEND_MODULE_API_NO)) { ++ || (module_entry->real_zend_api != ZEND_MODULE_API_NO)) { + /* Check for pre-4.1.0 module which has a slightly different module_entry structure :( */ + struct pre_4_1_0_module_entry { + char *name; +@@ -217,7 +244,7 @@ + zts = ((struct pre_4_1_0_module_entry *)module_entry)->zts; + } else { + name = module_entry->name; +- zend_api = module_entry->zend_api; ++ zend_api = module_entry->real_zend_api; + zend_debug = module_entry->zend_debug; + zts = module_entry->zts; + } +diff -Nura php-4.3.11/ext/standard/file.c hardening-patch-4.3.11-0.4.2/ext/standard/file.c +--- php-4.3.11/ext/standard/file.c 2005-03-27 17:53:59.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/file.c 2005-09-07 18:41:00.971101280 +0200 +@@ -2469,7 +2469,7 @@ + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) + /* {{{ proto string realpath(string path) + Return the resolved path */ +-PHP_FUNCTION(realpath) ++PHP_FUNCTION(real_path) + { + zval **path; + char resolved_path_buff[MAXPATHLEN]; +diff -Nura php-4.3.11/ext/standard/file.h hardening-patch-4.3.11-0.4.2/ext/standard/file.h +--- php-4.3.11/ext/standard/file.h 2004-06-21 21:33:47.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/file.h 2005-09-07 18:41:00.971101280 +0200 +@@ -64,7 +64,7 @@ + PHP_FUNCTION(fd_set); + PHP_FUNCTION(fd_isset); + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +-PHP_FUNCTION(realpath); ++PHP_FUNCTION(real_path); + #endif + #ifdef HAVE_FNMATCH + PHP_FUNCTION(fnmatch); +diff -Nura php-4.3.11/ext/standard/ftp_fopen_wrapper.c hardening-patch-4.3.11-0.4.2/ext/standard/ftp_fopen_wrapper.c +--- php-4.3.11/ext/standard/ftp_fopen_wrapper.c 2003-08-26 00:26:37.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/ftp_fopen_wrapper.c 2005-09-07 18:41:00.972101128 +0200 +@@ -17,7 +17,7 @@ + | Hartmut Holzgraefe | + +----------------------------------------------------------------------+ + */ +-/* $Id: ftp_fopen_wrapper.c,v 1.38.2.6 2003/08/25 22:26:37 pollita Exp $ */ ++/* $Id: ftp_fopen_wrapper.c,v 1.38.2.8.2.1 2005/06/27 08:27:23 sesser Exp $ */ + + #include "php.h" + #include "php_globals.h" +@@ -142,7 +142,7 @@ + unsigned short portno; + char *scratch; + int result; +- int i, use_ssl; ++ int i, use_ssl, tmp_len; + #ifdef HAVE_OPENSSL_EXT + int use_ssl_on_data=0; + php_stream *reuseid=NULL; +@@ -243,10 +243,25 @@ + + #endif + ++#define PHP_FTP_CNTRL_CHK(val, val_len, err_msg) { \ ++ unsigned char *s = val, *e = s + val_len; \ ++ while (s < e) { \ ++ if (iscntrl(*s)) { \ ++ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, err_msg, val); \ ++ goto errexit; \ ++ } \ ++ s++; \ ++ } \ ++} ++ + /* send the user name */ + php_stream_write_string(stream, "USER "); + if (resource->user != NULL) { +- php_raw_url_decode(resource->user, strlen(resource->user)); ++ unsigned char *s, *e; ++ tmp_len = php_raw_url_decode(resource->user, strlen(resource->user)); ++ ++ PHP_FTP_CNTRL_CHK(resource->user, tmp_len, "Invalid login %s") ++ + php_stream_write_string(stream, resource->user); + } else { + php_stream_write_string(stream, "anonymous"); +@@ -262,7 +277,10 @@ + + php_stream_write_string(stream, "PASS "); + if (resource->pass != NULL) { +- php_raw_url_decode(resource->pass, strlen(resource->pass)); ++ tmp_len = php_raw_url_decode(resource->pass, strlen(resource->pass)); ++ ++ PHP_FTP_CNTRL_CHK(resource->pass, tmp_len, "Invalid password %s") ++ + php_stream_write_string(stream, resource->pass); + } else { + /* if the user has configured who they are, +diff -Nura php-4.3.11/ext/standard/head.c hardening-patch-4.3.11-0.4.2/ext/standard/head.c +--- php-4.3.11/ext/standard/head.c 2005-01-07 22:14:23.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/head.c 2005-09-07 18:41:00.972101128 +0200 +@@ -45,10 +45,31 @@ + { + zend_bool rep = 1; + sapi_header_line ctr = {0}; ++#if HARDENING_PATCH ++ int i; ++#endif + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &ctr.line, + &ctr.line_len, &rep, &ctr.response_code) == FAILURE) + return; ++ ++#if HARDENING_PATCH ++ if (!HG(hphp_multiheader)) { ++ for (i=0; i0 && (iPHP Version %s with Hardening-Patch %s\n", PHP_VERSION, HARDENING_PATCH_VERSION); ++ } else { ++ char temp_ver[40]; ++ ++ snprintf(temp_ver, sizeof(temp_ver), "%s/%s", PHP_VERSION, HARDENING_PATCH_VERSION); ++ php_info_print_table_row(2, "PHP/Hardening-Patch Version", temp_ver); ++ } ++#else + if (!sapi_module.phpinfo_as_text) { + php_printf("

PHP Version %s

\n", PHP_VERSION); + } else { + php_info_print_table_row(2, "PHP Version", PHP_VERSION); + } ++#endif + php_info_print_box_end(); + php_info_print_table_start(); + php_info_print_table_row(2, "System", php_uname ); +diff -Nura php-4.3.11/ext/standard/php_standard.h hardening-patch-4.3.11-0.4.2/ext/standard/php_standard.h +--- php-4.3.11/ext/standard/php_standard.h 2002-12-31 17:35:33.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/php_standard.h 2005-09-07 19:04:56.163918808 +0200 +@@ -28,6 +28,7 @@ + #include "php_mail.h" + #include "md5.h" + #include "sha1.h" ++#include "sha256.h" + #include "html.h" + #include "exec.h" + #include "file.h" +diff -Nura php-4.3.11/ext/standard/sha256.c hardening-patch-4.3.11-0.4.2/ext/standard/sha256.c +--- php-4.3.11/ext/standard/sha256.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/sha256.c 2005-09-07 19:04:56.164918656 +0200 +@@ -0,0 +1,398 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 5 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2004 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 3.0 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available through the world-wide-web at the following url: | ++ | http://www.php.net/license/3_0.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++*/ ++ ++/* $Id: sha256.c,v 1.9 2004/01/08 08:17:34 andi Exp $ */ ++ ++#include ++#include "php.h" ++ ++/* This code is heavily based on the PHP md5/sha1 implementations */ ++ ++#include "sha256.h" ++ ++PHPAPI void make_sha256_digest(char *sha256str, unsigned char *digest) ++{ ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ sprintf(sha256str, "%02x", digest[i]); ++ sha256str += 2; ++ } ++ ++ *sha256str = '\0'; ++} ++ ++/* {{{ proto string sha256(string str [, bool raw_output]) ++ Calculate the sha256 hash of a string */ ++PHP_FUNCTION(sha256) ++{ ++ char *arg; ++ int arg_len; ++ zend_bool raw_output = 0; ++ char sha256str[65]; ++ PHP_SHA256_CTX context; ++ unsigned char digest[32]; ++ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &arg, &arg_len, &raw_output) == FAILURE) { ++ return; ++ } ++ ++ sha256str[0] = '\0'; ++ PHP_SHA256Init(&context); ++ PHP_SHA256Update(&context, arg, arg_len); ++ PHP_SHA256Final(digest, &context); ++ if (raw_output) { ++ RETURN_STRINGL(digest, 32, 1); ++ } else { ++ make_sha256_digest(sha256str, digest); ++ RETVAL_STRING(sha256str, 1); ++ } ++ ++} ++ ++/* }}} */ ++ ++/* {{{ proto string sha256_file(string filename [, bool raw_output]) ++ Calculate the sha256 hash of given filename */ ++PHP_FUNCTION(sha256_file) ++{ ++ char *arg; ++ int arg_len; ++ zend_bool raw_output = 0; ++ char sha256str[65]; ++ unsigned char buf[1024]; ++ unsigned char digest[32]; ++ PHP_SHA256_CTX context; ++ int n; ++ FILE *fp; ++ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &arg, &arg_len, &raw_output) == FAILURE) { ++ return; ++ } ++ ++ if (PG(safe_mode) && (!php_checkuid(arg, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { ++ RETURN_FALSE; ++ } ++ ++ if (php_check_open_basedir(arg TSRMLS_CC)) { ++ RETURN_FALSE; ++ } ++ ++ if ((fp = VCWD_FOPEN(arg, "rb")) == NULL) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open file"); ++ RETURN_FALSE; ++ } ++ ++ PHP_SHA256Init(&context); ++ ++ while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { ++ PHP_SHA256Update(&context, buf, n); ++ } ++ ++ PHP_SHA256Final(digest, &context); ++ ++ if (ferror(fp)) { ++ fclose(fp); ++ RETURN_FALSE; ++ } ++ ++ fclose(fp); ++ ++ if (raw_output) { ++ RETURN_STRINGL(digest, 32, 1); ++ } else { ++ make_sha256_digest(sha256str, digest); ++ RETVAL_STRING(sha256str, 1); ++ } ++} ++/* }}} */ ++ ++ ++static void SHA256Transform(php_uint32[8], const unsigned char[64]); ++static void SHA256Encode(unsigned char *, php_uint32 *, unsigned int); ++static void SHA256Decode(php_uint32 *, const unsigned char *, unsigned int); ++ ++static unsigned char PADDING[64] = ++{ ++ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ++}; ++ ++/* F, G, H and I are basic SHA256 functions. ++ */ ++#define F(x) (ROTATE_RIGHT(x,2) ^ ROTATE_RIGHT(x,13) ^ ROTATE_RIGHT(x,22)) ++#define G(x, y, z) (((x) & (y)) | ((z) & ((y) | (x)))) ++#define H(x) (ROTATE_RIGHT(x,6) ^ ROTATE_RIGHT(x,11) ^ ROTATE_RIGHT(x,25)) ++#define I(x, y, z) (((x) & (y)) | ((~x) & z)) ++ ++/* ROTATE_RIGHT rotates x right n bits. ++ */ ++#define ROTATE_RIGHT(x, n) (((x) >> (n)) | ((x) << (32-(n)))) ++ ++/* W[i] ++ */ ++#define W(i) ( tmp1=ROTATE_RIGHT(x[(i-15)&15],7)^ROTATE_RIGHT(x[(i-15)&15],18)^(x[(i-15)&15] >> 3), \ ++ tmp2=ROTATE_RIGHT(x[(i-2)&15],17)^ROTATE_RIGHT(x[(i-2)&15],19)^(x[(i-2)&15] >> 10), \ ++ (x[i&15]=x[i&15] + tmp1 + x[(i-7)&15] + tmp2) ) ++ ++/* ROUND function of sha256 ++ */ ++ ++#define ROUND(a,b,c,d,e,f,g,h,w,k) { \ ++ t1 = (h) + H((e)) + I((e), (f), (g)) + (k) + (php_uint32)(w); \ ++ (h) = F((a)) + G((a), (b), (c)) + t1; \ ++ (d) += t1; \ ++ } ++ ++ ++/* {{{ PHP_SHA256Init ++ * SHA256 initialization. Begins an SHA256 operation, writing a new context. ++ */ ++PHPAPI void PHP_SHA256Init(PHP_SHA256_CTX * context) ++{ ++ context->count[0] = context->count[1] = 0; ++ /* Load magic initialization constants. ++ */ ++ context->state[0] = 0x6a09e667; ++ context->state[1] = 0xbb67ae85; ++ context->state[2] = 0x3c6ef372; ++ context->state[3] = 0xa54ff53a; ++ context->state[4] = 0x510e527f; ++ context->state[5] = 0x9b05688c; ++ context->state[6] = 0x1f83d9ab; ++ context->state[7] = 0x5be0cd19; ++} ++/* }}} */ ++ ++/* {{{ PHP_SHA256Update ++ SHA256 block update operation. Continues an SHA256 message-digest ++ operation, processing another message block, and updating the ++ context. ++ */ ++PHPAPI void PHP_SHA256Update(PHP_SHA256_CTX * context, const unsigned char *input, ++ unsigned int inputLen) ++{ ++ unsigned int i, index, partLen; ++ ++ /* Compute number of bytes mod 64 */ ++ index = (unsigned int) ((context->count[0] >> 3) & 0x3F); ++ ++ /* Update number of bits */ ++ if ((context->count[0] += ((php_uint32) inputLen << 3)) ++ < ((php_uint32) inputLen << 3)) ++ context->count[1]++; ++ context->count[1] += ((php_uint32) inputLen >> 29); ++ ++ partLen = 64 - index; ++ ++ /* Transform as many times as possible. ++ */ ++ if (inputLen >= partLen) { ++ memcpy ++ ((unsigned char*) & context->buffer[index], (unsigned char*) input, partLen); ++ SHA256Transform(context->state, context->buffer); ++ ++ for (i = partLen; i + 63 < inputLen; i += 64) ++ SHA256Transform(context->state, &input[i]); ++ ++ index = 0; ++ } else ++ i = 0; ++ ++ /* Buffer remaining input */ ++ memcpy ++ ((unsigned char*) & context->buffer[index], (unsigned char*) & input[i], ++ inputLen - i); ++} ++/* }}} */ ++ ++/* {{{ PHP_SHA256Final ++ SHA256 finalization. Ends an SHA256 message-digest operation, writing the ++ the message digest and zeroizing the context. ++ */ ++PHPAPI void PHP_SHA256Final(unsigned char digest[32], PHP_SHA256_CTX * context) ++{ ++ unsigned char bits[8]; ++ unsigned int index, padLen; ++ ++ /* Save number of bits */ ++ bits[7] = context->count[0] & 0xFF; ++ bits[6] = (context->count[0] >> 8) & 0xFF; ++ bits[5] = (context->count[0] >> 16) & 0xFF; ++ bits[4] = (context->count[0] >> 24) & 0xFF; ++ bits[3] = context->count[1] & 0xFF; ++ bits[2] = (context->count[1] >> 8) & 0xFF; ++ bits[1] = (context->count[1] >> 16) & 0xFF; ++ bits[0] = (context->count[1] >> 24) & 0xFF; ++ ++ /* Pad out to 56 mod 64. ++ */ ++ index = (unsigned int) ((context->count[0] >> 3) & 0x3f); ++ padLen = (index < 56) ? (56 - index) : (120 - index); ++ PHP_SHA256Update(context, PADDING, padLen); ++ ++ /* Append length (before padding) */ ++ PHP_SHA256Update(context, bits, 8); ++ ++ /* Store state in digest */ ++ SHA256Encode(digest, context->state, 32); ++ ++ /* Zeroize sensitive information. ++ */ ++ memset((unsigned char*) context, 0, sizeof(*context)); ++} ++/* }}} */ ++ ++/* {{{ SHA256Transform ++ * SHA256 basic transformation. Transforms state based on block. ++ */ ++static void SHA256Transform(state, block) ++php_uint32 state[8]; ++const unsigned char block[64]; ++{ ++ php_uint32 a = state[0], b = state[1], c = state[2]; ++ php_uint32 d = state[3], e = state[4], f = state[5]; ++ php_uint32 g = state[6], h = state[7], x[16], tmp1, tmp2, t1; ++ ++ SHA256Decode(x, block, 64); ++ ++ ROUND(a, b, c, d, e, f, g, h, x[0], 0x428a2f98) ++ ROUND(h, a, b, c, d, e, f, g, x[1], 0x71374491) ++ ROUND(g, h, a, b, c, d, e, f, x[2], 0xb5c0fbcf) ++ ROUND(f, g, h, a, b, c, d, e, x[3], 0xe9b5dba5) ++ ROUND(e, f, g, h, a, b, c, d, x[4], 0x3956c25b) ++ ROUND(d, e, f, g, h, a, b, c, x[5], 0x59f111f1) ++ ROUND(c, d, e, f, g, h, a, b, x[6], 0x923f82a4) ++ ROUND(b, c, d, e, f, g, h, a, x[7], 0xab1c5ed5) ++ ROUND(a, b, c, d, e, f, g, h, x[8], 0xd807aa98) ++ ROUND(h, a, b, c, d, e, f, g, x[9], 0x12835b01) ++ ROUND(g, h, a, b, c, d, e, f, x[10], 0x243185be) ++ ROUND(f, g, h, a, b, c, d, e, x[11], 0x550c7dc3) ++ ROUND(e, f, g, h, a, b, c, d, x[12], 0x72be5d74) ++ ROUND(d, e, f, g, h, a, b, c, x[13], 0x80deb1fe) ++ ROUND(c, d, e, f, g, h, a, b, x[14], 0x9bdc06a7) ++ ROUND(b, c, d, e, f, g, h, a, x[15], 0xc19bf174) ++ ROUND(a, b, c, d, e, f, g, h, W(16), 0xe49b69c1) ++ ROUND(h, a, b, c, d, e, f, g, W(17), 0xefbe4786) ++ ROUND(g, h, a, b, c, d, e, f, W(18), 0x0fc19dc6) ++ ROUND(f, g, h, a, b, c, d, e, W(19), 0x240ca1cc) ++ ROUND(e, f, g, h, a, b, c, d, W(20), 0x2de92c6f) ++ ROUND(d, e, f, g, h, a, b, c, W(21), 0x4a7484aa) ++ ROUND(c, d, e, f, g, h, a, b, W(22), 0x5cb0a9dc) ++ ROUND(b, c, d, e, f, g, h, a, W(23), 0x76f988da) ++ ROUND(a, b, c, d, e, f, g, h, W(24), 0x983e5152) ++ ROUND(h, a, b, c, d, e, f, g, W(25), 0xa831c66d) ++ ROUND(g, h, a, b, c, d, e, f, W(26), 0xb00327c8) ++ ROUND(f, g, h, a, b, c, d, e, W(27), 0xbf597fc7) ++ ROUND(e, f, g, h, a, b, c, d, W(28), 0xc6e00bf3) ++ ROUND(d, e, f, g, h, a, b, c, W(29), 0xd5a79147) ++ ROUND(c, d, e, f, g, h, a, b, W(30), 0x06ca6351) ++ ROUND(b, c, d, e, f, g, h, a, W(31), 0x14292967) ++ ROUND(a, b, c, d, e, f, g, h, W(32), 0x27b70a85) ++ ROUND(h, a, b, c, d, e, f, g, W(33), 0x2e1b2138) ++ ROUND(g, h, a, b, c, d, e, f, W(34), 0x4d2c6dfc) ++ ROUND(f, g, h, a, b, c, d, e, W(35), 0x53380d13) ++ ROUND(e, f, g, h, a, b, c, d, W(36), 0x650a7354) ++ ROUND(d, e, f, g, h, a, b, c, W(37), 0x766a0abb) ++ ROUND(c, d, e, f, g, h, a, b, W(38), 0x81c2c92e) ++ ROUND(b, c, d, e, f, g, h, a, W(39), 0x92722c85) ++ ROUND(a, b, c, d, e, f, g, h, W(40), 0xa2bfe8a1) ++ ROUND(h, a, b, c, d, e, f, g, W(41), 0xa81a664b) ++ ROUND(g, h, a, b, c, d, e, f, W(42), 0xc24b8b70) ++ ROUND(f, g, h, a, b, c, d, e, W(43), 0xc76c51a3) ++ ROUND(e, f, g, h, a, b, c, d, W(44), 0xd192e819) ++ ROUND(d, e, f, g, h, a, b, c, W(45), 0xd6990624) ++ ROUND(c, d, e, f, g, h, a, b, W(46), 0xf40e3585) ++ ROUND(b, c, d, e, f, g, h, a, W(47), 0x106aa070) ++ ROUND(a, b, c, d, e, f, g, h, W(48), 0x19a4c116) ++ ROUND(h, a, b, c, d, e, f, g, W(49), 0x1e376c08) ++ ROUND(g, h, a, b, c, d, e, f, W(50), 0x2748774c) ++ ROUND(f, g, h, a, b, c, d, e, W(51), 0x34b0bcb5) ++ ROUND(e, f, g, h, a, b, c, d, W(52), 0x391c0cb3) ++ ROUND(d, e, f, g, h, a, b, c, W(53), 0x4ed8aa4a) ++ ROUND(c, d, e, f, g, h, a, b, W(54), 0x5b9cca4f) ++ ROUND(b, c, d, e, f, g, h, a, W(55), 0x682e6ff3) ++ ROUND(a, b, c, d, e, f, g, h, W(56), 0x748f82ee) ++ ROUND(h, a, b, c, d, e, f, g, W(57), 0x78a5636f) ++ ROUND(g, h, a, b, c, d, e, f, W(58), 0x84c87814) ++ ROUND(f, g, h, a, b, c, d, e, W(59), 0x8cc70208) ++ ROUND(e, f, g, h, a, b, c, d, W(60), 0x90befffa) ++ ROUND(d, e, f, g, h, a, b, c, W(61), 0xa4506ceb) ++ ROUND(c, d, e, f, g, h, a, b, W(62), 0xbef9a3f7) ++ ROUND(b, c, d, e, f, g, h, a, W(63), 0xc67178f2) ++ ++ state[0] += a; ++ state[1] += b; ++ state[2] += c; ++ state[3] += d; ++ state[4] += e; ++ state[5] += f; ++ state[6] += g; ++ state[7] += h; ++ ++ /* Zeroize sensitive information. */ ++ memset((unsigned char*) x, 0, sizeof(x)); ++} ++/* }}} */ ++ ++/* {{{ SHA256Encode ++ Encodes input (php_uint32) into output (unsigned char). Assumes len is ++ a multiple of 4. ++ */ ++static void SHA256Encode(output, input, len) ++unsigned char *output; ++php_uint32 *input; ++unsigned int len; ++{ ++ unsigned int i, j; ++ ++ for (i = 0, j = 0; j < len; i++, j += 4) { ++ output[j] = (unsigned char) ((input[i] >> 24) & 0xff); ++ output[j + 1] = (unsigned char) ((input[i] >> 16) & 0xff); ++ output[j + 2] = (unsigned char) ((input[i] >> 8) & 0xff); ++ output[j + 3] = (unsigned char) (input[i] & 0xff); ++ } ++} ++/* }}} */ ++ ++/* {{{ SHA256Decode ++ Decodes input (unsigned char) into output (php_uint32). Assumes len is ++ a multiple of 4. ++ */ ++static void SHA256Decode(output, input, len) ++php_uint32 *output; ++const unsigned char *input; ++unsigned int len; ++{ ++ unsigned int i, j; ++ ++ for (i = 0, j = 0; j < len; i++, j += 4) ++ output[i] = ((php_uint32) input[j + 3]) | (((php_uint32) input[j + 2]) << 8) | ++ (((php_uint32) input[j + 1]) << 16) | (((php_uint32) input[j]) << 24); ++} ++/* }}} */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-4.3.11/ext/standard/sha256.h hardening-patch-4.3.11-0.4.2/ext/standard/sha256.h +--- php-4.3.11/ext/standard/sha256.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/sha256.h 2005-09-07 19:04:56.164918656 +0200 +@@ -0,0 +1,40 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 5 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2004 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 3.0 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available through the world-wide-web at the following url: | ++ | http://www.php.net/license/3_0.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++*/ ++ ++/* $Id: sha256.h,v 1.4 2004/01/08 17:32:52 sniper Exp $ */ ++ ++#ifndef SHA256_H ++#define SHA256_H ++ ++#include "ext/standard/basic_functions.h" ++ ++/* SHA1 context. */ ++typedef struct { ++ php_uint32 state[8]; /* state (ABCD) */ ++ php_uint32 count[2]; /* number of bits, modulo 2^64 (lsb first) */ ++ unsigned char buffer[64]; /* input buffer */ ++} PHP_SHA256_CTX; ++ ++PHPAPI void PHP_SHA256Init(PHP_SHA256_CTX *); ++PHPAPI void PHP_SHA256Update(PHP_SHA256_CTX *, const unsigned char *, unsigned int); ++PHPAPI void PHP_SHA256Final(unsigned char[32], PHP_SHA256_CTX *); ++ ++PHP_FUNCTION(sha256); ++PHP_FUNCTION(sha256_file); ++ ++#endif +diff -Nura php-4.3.11/ext/standard/syslog.c hardening-patch-4.3.11-0.4.2/ext/standard/syslog.c +--- php-4.3.11/ext/standard/syslog.c 2004-07-30 16:38:29.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/ext/standard/syslog.c 2005-09-07 18:41:00.974100824 +0200 +@@ -42,6 +42,7 @@ + */ + PHP_MINIT_FUNCTION(syslog) + { ++#if !HARDENING_PATCH + /* error levels */ + REGISTER_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ + REGISTER_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ +@@ -97,7 +98,7 @@ + /* AIX doesn't have LOG_PERROR */ + REGISTER_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ + #endif +- ++#endif + return SUCCESS; + } + /* }}} */ +diff -Nura php-4.3.11/ext/varfilter/config.m4 hardening-patch-4.3.11-0.4.2/ext/varfilter/config.m4 +--- php-4.3.11/ext/varfilter/config.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/varfilter/config.m4 2005-09-07 18:41:00.974100824 +0200 +@@ -0,0 +1,11 @@ ++dnl ++dnl $Id: config.m4,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++dnl ++ ++PHP_ARG_ENABLE(varfilter, whether to enable Hardening-Patch's variable filter, ++[ --disable-varfilter Disable Hardening-Patch's variable filter], yes) ++ ++if test "$PHP_VARFILTER" != "no"; then ++ AC_DEFINE(HAVE_VARFILTER, 1, [ ]) ++ PHP_NEW_EXTENSION(varfilter, varfilter.c, $ext_shared) ++fi +diff -Nura php-4.3.11/ext/varfilter/CREDITS hardening-patch-4.3.11-0.4.2/ext/varfilter/CREDITS +--- php-4.3.11/ext/varfilter/CREDITS 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/varfilter/CREDITS 2005-09-07 18:41:00.974100824 +0200 +@@ -0,0 +1,2 @@ ++varfilter ++Stefan Esser +\ Kein Zeilenumbruch am Dateiende. +diff -Nura php-4.3.11/ext/varfilter/php_varfilter.h hardening-patch-4.3.11-0.4.2/ext/varfilter/php_varfilter.h +--- php-4.3.11/ext/varfilter/php_varfilter.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/varfilter/php_varfilter.h 2005-09-07 18:41:00.975100672 +0200 +@@ -0,0 +1,111 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: php_varfilter.h,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifndef PHP_VARFILTER_H ++#define PHP_VARFILTER_H ++ ++extern zend_module_entry varfilter_module_entry; ++#define phpext_varfilter_ptr &varfilter_module_entry ++ ++#ifdef PHP_WIN32 ++#define PHP_VARFILTER_API __declspec(dllexport) ++#else ++#define PHP_VARFILTER_API ++#endif ++ ++#ifdef ZTS ++#include "TSRM.h" ++#endif ++ ++#include "SAPI.h" ++ ++#include "php_variables.h" ++ ++ ++PHP_MINIT_FUNCTION(varfilter); ++PHP_MSHUTDOWN_FUNCTION(varfilter); ++PHP_RINIT_FUNCTION(varfilter); ++PHP_RSHUTDOWN_FUNCTION(varfilter); ++PHP_MINFO_FUNCTION(varfilter); ++ ++ ++ZEND_BEGIN_MODULE_GLOBALS(varfilter) ++/* request variables */ ++ long max_request_variables; ++ long cur_request_variables; ++ long max_varname_length; ++ long max_totalname_length; ++ long max_value_length; ++ long max_array_depth; ++ long max_array_index_length; ++/* cookie variables */ ++ long max_cookie_vars; ++ long cur_cookie_vars; ++ long max_cookie_name_length; ++ long max_cookie_totalname_length; ++ long max_cookie_value_length; ++ long max_cookie_array_depth; ++ long max_cookie_array_index_length; ++/* get variables */ ++ long max_get_vars; ++ long cur_get_vars; ++ long max_get_name_length; ++ long max_get_totalname_length; ++ long max_get_value_length; ++ long max_get_array_depth; ++ long max_get_array_index_length; ++/* post variables */ ++ long max_post_vars; ++ long cur_post_vars; ++ long max_post_name_length; ++ long max_post_totalname_length; ++ long max_post_value_length; ++ long max_post_array_depth; ++ long max_post_array_index_length; ++/* fileupload */ ++ long max_uploads; ++ long cur_uploads; ++ zend_bool disallow_elf_files; ++ char *verification_script; ++ ++ZEND_END_MODULE_GLOBALS(varfilter) ++ ++ ++#ifdef ZTS ++#define VARFILTER_G(v) TSRMG(varfilter_globals_id, zend_varfilter_globals *, v) ++#else ++#define VARFILTER_G(v) (varfilter_globals.v) ++#endif ++ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter); ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter); ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter); ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter); ++ ++#endif /* PHP_VARFILTER_H */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * indent-tabs-mode: t ++ * End: ++ */ +diff -Nura php-4.3.11/ext/varfilter/varfilter.c hardening-patch-4.3.11-0.4.2/ext/varfilter/varfilter.c +--- php-4.3.11/ext/varfilter/varfilter.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/ext/varfilter/varfilter.c 2005-09-07 19:04:56.164918656 +0200 +@@ -0,0 +1,602 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: varfilter.c,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "php.h" ++#include "php_ini.h" ++#include "ext/standard/info.h" ++#include "php_varfilter.h" ++#include "hardening_patch.h" ++ ++ZEND_DECLARE_MODULE_GLOBALS(varfilter) ++ ++/* True global resources - no need for thread safety here */ ++static int le_varfilter; ++ ++/* {{{ varfilter_module_entry ++ */ ++zend_module_entry varfilter_module_entry = { ++#if ZEND_MODULE_API_NO >= 20010901 ++ STANDARD_MODULE_HEADER, ++#endif ++ "varfilter", ++ NULL, ++ PHP_MINIT(varfilter), ++ PHP_MSHUTDOWN(varfilter), ++ PHP_RINIT(varfilter), /* Replace with NULL if there's nothing to do at request start */ ++ PHP_RSHUTDOWN(varfilter), /* Replace with NULL if there's nothing to do at request end */ ++ PHP_MINFO(varfilter), ++#if ZEND_MODULE_API_NO >= 20010901 ++ "0.3.2", /* Replace with version number for your extension */ ++#endif ++ STANDARD_MODULE_PROPERTIES ++}; ++/* }}} */ ++ ++#ifdef COMPILE_DL_VARFILTER ++ZEND_GET_MODULE(varfilter) ++#endif ++ ++/* {{{ PHP_INI ++ */ ++PHP_INI_BEGIN() ++ /* for backward compatibility */ ++ STD_PHP_INI_ENTRY("varfilter.max_request_variables", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.request.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.cookie.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_cookie_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_value_length", "10000", PHP_INI_PERDIR, OnUpdateLong, max_cookie_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.get.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_get_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_get_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_value_length", "512", PHP_INI_PERDIR, OnUpdateLong, max_get_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_depth", "50", PHP_INI_PERDIR, OnUpdateLong, max_get_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.post.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_post_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_post_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_post_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_post_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.upload.max_uploads", "25", PHP_INI_PERDIR, OnUpdateLong, max_uploads, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.disallow_elf_files", "1", PHP_INI_SYSTEM, OnUpdateBool, disallow_elf_files, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.verification_script", NULL, PHP_INI_SYSTEM, OnUpdateString, verification_script, zend_varfilter_globals, varfilter_globals) ++ ++ ++PHP_INI_END() ++/* }}} */ ++ ++/* {{{ php_varfilter_init_globals ++ */ ++static void php_varfilter_init_globals(zend_varfilter_globals *varfilter_globals) ++{ ++ varfilter_globals->max_request_variables = 200; ++ varfilter_globals->max_varname_length = 64; ++ varfilter_globals->max_value_length = 10000; ++ varfilter_globals->max_array_depth = 100; ++ varfilter_globals->max_totalname_length = 256; ++ varfilter_globals->max_array_index_length = 64; ++ ++ varfilter_globals->max_cookie_vars = 100; ++ varfilter_globals->max_cookie_name_length = 64; ++ varfilter_globals->max_cookie_totalname_length = 256; ++ varfilter_globals->max_cookie_value_length = 10000; ++ varfilter_globals->max_cookie_array_depth = 100; ++ varfilter_globals->max_cookie_array_index_length = 64; ++ ++ varfilter_globals->max_get_vars = 100; ++ varfilter_globals->max_get_name_length = 64; ++ varfilter_globals->max_get_totalname_length = 256; ++ varfilter_globals->max_get_value_length = 512; ++ varfilter_globals->max_get_array_depth = 50; ++ varfilter_globals->max_get_array_index_length = 64; ++ ++ varfilter_globals->max_post_vars = 200; ++ varfilter_globals->max_post_name_length = 64; ++ varfilter_globals->max_post_totalname_length = 256; ++ varfilter_globals->max_post_value_length = 65000; ++ varfilter_globals->max_post_array_depth = 100; ++ varfilter_globals->max_post_array_index_length = 64; ++ ++ varfilter_globals->max_uploads = 25; ++ varfilter_globals->disallow_elf_files = 1; ++ varfilter_globals->verification_script = NULL; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINIT_FUNCTION ++ */ ++PHP_MINIT_FUNCTION(varfilter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(varfilter, php_varfilter_init_globals, NULL); ++ REGISTER_INI_ENTRIES(); ++ ++ sapi_register_input_filter(varfilter_input_filter); ++ sapi_register_pre_upload_filter(varfilter_pre_upload_filter); ++ sapi_register_upload_content_filter(varfilter_upload_content_filter); ++ sapi_register_post_upload_filter(varfilter_post_upload_filter); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MSHUTDOWN_FUNCTION ++ */ ++PHP_MSHUTDOWN_FUNCTION(varfilter) ++{ ++ UNREGISTER_INI_ENTRIES(); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request start */ ++/* {{{ PHP_RINIT_FUNCTION ++ */ ++PHP_RINIT_FUNCTION(varfilter) ++{ ++ VARFILTER_G(cur_request_variables) = 0; ++ VARFILTER_G(cur_get_vars) = 0; ++ VARFILTER_G(cur_post_vars) = 0; ++ VARFILTER_G(cur_cookie_vars) = 0; ++ ++ VARFILTER_G(cur_uploads) = 0; ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request end */ ++/* {{{ PHP_RSHUTDOWN_FUNCTION ++ */ ++PHP_RSHUTDOWN_FUNCTION(varfilter) ++{ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINFO_FUNCTION ++ */ ++PHP_MINFO_FUNCTION(varfilter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_header(2, "Hardening-Patch's variable filter support", "enabled"); ++ php_info_print_table_end(); ++ ++ DISPLAY_INI_ENTRIES(); ++} ++/* }}} */ ++ ++/* {{{ normalize_varname ++ */ ++static void normalize_varname(char *varname) ++{ ++ char *s=varname, *index=NULL, *indexend=NULL, *p; ++ ++ /* overjump leading space */ ++ while (*s == ' ') { ++ s++; ++ } ++ ++ /* and remove it */ ++ if (s != varname) { ++ memmove(varname, s, strlen(s)+1); ++ } ++ ++ for (p=varname; *p && *p != '['; p++) { ++ switch(*p) { ++ case ' ': ++ case '.': ++ *p='_'; ++ break; ++ } ++ } ++ ++ /* find index */ ++ index = strchr(varname, '['); ++ if (index) { ++ index++; ++ s=index; ++ } else { ++ return; ++ } ++ ++ /* done? */ ++ while (index) { ++ ++ while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') { ++ index++; ++ } ++ indexend = strchr(index, ']'); ++ indexend = indexend ? indexend + 1 : index + strlen(index); ++ ++ if (s != index) { ++ memmove(s, index, strlen(index)+1); ++ s += indexend-index; ++ } else { ++ s = indexend; ++ } ++ ++ if (*s == '[') { ++ s++; ++ index = s; ++ } else { ++ index = NULL; ++ } ++ } ++ *s++='\0'; ++} ++/* }}} */ ++ ++/* {{{ SAPI_PRE_UPLOAD_FILTER_FUNC ++ */ ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter) ++{ ++ /* Drop this fileupload if the limit is reached */ ++ if (VARFILTER_G(max_uploads) && VARFILTER_G(max_uploads) <= VARFILTER_G(cur_uploads)) { ++ php_security_log(S_FILES, "configured fileupload limit exceeded - file dropped"); ++ return FAILURE; ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_UPLOAD_CONTENT_FILTER_FUNC ++ */ ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter) ++{ ++ ++ if (VARFILTER_G(disallow_elf_files)) { ++ ++ if (offset == 0 && buffer_len > 10) { ++ ++ if (buffer[0] == 0x7F && buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F') { ++ php_security_log(S_FILES, "uploaded file is an ELF executable - file dropped"); ++ return FAILURE; ++ } ++ } ++ ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_POST_UPLOAD_FILTER_FUNC ++ */ ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter) ++{ ++ int retval = SUCCESS; ++ ++ if (VARFILTER_G(verification_script)) { ++ char cmd[8192]; ++ FILE *in; ++ int first=1; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s", VARFILTER_G(verification_script), tmpfilename); ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_FILES, "unable to execute fileupload verification script %s - file dropped", VARFILTER_G(verification_script)); ++ return FAILURE; ++ } ++ ++ retval = FAILURE; ++ ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ if (first) { ++ retval = atoi(cmd) == 1 ? SUCCESS : FAILURE; ++ first = 0; ++ } ++ } ++ pclose(in); ++ } ++ ++ if (retval != SUCCESS) { ++ php_security_log(S_FILES, "fileupload verification script disallows file - file dropped"); ++ return FAILURE; ++ } ++ ++ VARFILTER_G(cur_uploads)++; ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_INPUT_FILTER_FUNC ++ */ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter) ++{ ++ char *index, *prev_index = NULL, *copy_var; ++ unsigned int var_len, total_len, depth = 0, rv; ++ ++ /* Drop this variable if the limit is reached */ ++ if (VARFILTER_G(max_request_variables) && VARFILTER_G(max_request_variables) <= VARFILTER_G(cur_request_variables)) { ++ php_security_log(S_VARS, "configured request variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_vars) && VARFILTER_G(max_get_vars) <= VARFILTER_G(cur_get_vars)) { ++ php_security_log(S_VARS, "configured GET variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_vars) && VARFILTER_G(max_cookie_vars) <= VARFILTER_G(cur_cookie_vars)) { ++ php_security_log(S_VARS, "configured COOKIE variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_vars) && VARFILTER_G(max_post_vars) <= VARFILTER_G(cur_post_vars)) { ++ php_security_log(S_VARS, "configured POST variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ ++ /* Drop this variable if it exceeds the value length limit */ ++ if (VARFILTER_G(max_value_length) && VARFILTER_G(max_value_length) < val_len) { ++ php_security_log(S_VARS, "configured request variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_value_length) && VARFILTER_G(max_get_value_length) < val_len) { ++ php_security_log(S_VARS, "configured GET variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_value_length) && VARFILTER_G(max_cookie_value_length) < val_len) { ++ php_security_log(S_VARS, "configured COOKIE variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_value_length) && VARFILTER_G(max_post_value_length) < val_len) { ++ php_security_log(S_VARS, "configured POST variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Normalize the variable name */ ++ normalize_varname(var); ++ ++ /* Find length of variable name */ ++ index = strchr(var, '['); ++ total_len = strlen(var); ++ var_len = index ? index-var : total_len; ++ ++ /* Drop this variable if it exceeds the varname/total length limit */ ++ if (VARFILTER_G(max_varname_length) && VARFILTER_G(max_varname_length) < var_len) { ++ php_security_log(S_VARS, "configured request variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_totalname_length) && VARFILTER_G(max_totalname_length) < total_len) { ++ php_security_log(S_VARS, "configured request variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_name_length) && VARFILTER_G(max_get_name_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_get_totalname_length) && VARFILTER_G(max_get_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_name_length) && VARFILTER_G(max_cookie_name_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_cookie_totalname_length) && VARFILTER_G(max_cookie_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_name_length) && VARFILTER_G(max_post_name_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_post_totalname_length) && VARFILTER_G(max_post_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Find out array depth */ ++ while (index) { ++ unsigned int index_length; ++ ++ depth++; ++ index = strchr(index+1, '['); ++ ++ if (prev_index) { ++ index_length = index ? index - 1 - prev_index - 1: strlen(prev_index); ++ ++ if (VARFILTER_G(max_array_index_length) && VARFILTER_G(max_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured request variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_index_length) && VARFILTER_G(max_get_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured GET variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_index_length) && VARFILTER_G(max_cookie_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured COOKIE variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_index_length) && VARFILTER_G(max_post_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured POST variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ prev_index = index; ++ } ++ ++ } ++ ++ /* Drop this variable if it exceeds the array depth limit */ ++ if (VARFILTER_G(max_array_depth) && VARFILTER_G(max_array_depth) < depth) { ++ php_security_log(S_VARS, "configured request variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_depth) && VARFILTER_G(max_get_array_depth) < depth) { ++ php_security_log(S_VARS, "configured GET variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_depth) && VARFILTER_G(max_cookie_array_depth) < depth) { ++ php_security_log(S_VARS, "configured COOKIE variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_depth) && VARFILTER_G(max_post_array_depth) < depth) { ++ php_security_log(S_VARS, "configured POST variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Drop this variable if it is one of GLOBALS, _GET, _POST, ... */ ++ /* This is to protect several silly scripts that do globalizing themself */ ++ ++ switch (var_len) { ++ case 18: ++ if (memcmp(var, "HTTP_RAW_POST_DATA", 18)==0) goto protected_varname; ++ break; ++ case 17: ++ if (memcmp(var, "HTTP_SESSION_VARS", 17)==0) goto protected_varname; ++ break; ++ case 16: ++ if (memcmp(var, "HTTP_SERVER_VARS", 16)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_COOKIE_VARS", 16)==0) goto protected_varname; ++ break; ++ case 15: ++ if (memcmp(var, "HTTP_POST_FILES", 15)==0) goto protected_varname; ++ break; ++ case 14: ++ if (memcmp(var, "HTTP_POST_VARS", 14)==0) goto protected_varname; ++ break; ++ case 13: ++ if (memcmp(var, "HTTP_GET_VARS", 13)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_ENV_VARS", 13)==0) goto protected_varname; ++ break; ++ case 8: ++ if (memcmp(var, "_SESSION", 8)==0) goto protected_varname; ++ if (memcmp(var, "_REQUEST", 8)==0) goto protected_varname; ++ break; ++ case 7: ++ if (memcmp(var, "GLOBALS", 7)==0) goto protected_varname; ++ if (memcmp(var, "_COOKIE", 7)==0) goto protected_varname; ++ if (memcmp(var, "_SERVER", 7)==0) goto protected_varname; ++ break; ++ case 6: ++ if (memcmp(var, "_FILES", 6)==0) goto protected_varname; ++ break; ++ case 5: ++ if (memcmp(var, "_POST", 5)==0) goto protected_varname; ++ break; ++ case 4: ++ if (memcmp(var, "_ENV", 4)==0) goto protected_varname; ++ if (memcmp(var, "_GET", 4)==0) goto protected_varname; ++ break; ++ } ++ ++ /* Okay let PHP register this variable */ ++ VARFILTER_G(cur_request_variables)++; ++ switch (arg) { ++ case PARSE_GET: ++ VARFILTER_G(cur_get_vars)++; ++ break; ++ case PARSE_COOKIE: ++ VARFILTER_G(cur_cookie_vars)++; ++ break; ++ case PARSE_POST: ++ VARFILTER_G(cur_post_vars)++; ++ break; ++ } ++ ++ if (new_val_len) { ++ *new_val_len = val_len; ++ } ++ ++ return 1; ++protected_varname: ++ php_security_log(S_VARS, "tried to register forbidden variable '%s' through %s variables", var, arg == PARSE_GET ? "GET" : arg == PARSE_POST ? "POST" : "COOKIE"); ++ return 0; ++} ++/* }}} */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: noet sw=4 ts=4 fdm=marker ++ * vim<600: noet sw=4 ts=4 ++ */ ++ ++ +diff -Nura php-4.3.11/main/fopen_wrappers.c hardening-patch-4.3.11-0.4.2/main/fopen_wrappers.c +--- php-4.3.11/main/fopen_wrappers.c 2005-02-03 00:44:07.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/main/fopen_wrappers.c 2005-09-07 18:41:00.976100520 +0200 +@@ -166,6 +166,21 @@ + char *pathbuf; + char *ptr; + char *end; ++ char path_copy[MAXPATHLEN]; ++ int path_len; ++ ++ /* Special case path ends with a trailing slash */ ++ path_len = strlen(path); ++ if (path_len >= MAXPATHLEN) { ++ errno = EPERM; /* we deny permission to open it */ ++ return -1; ++ } ++ if (path_len > 0 && path[path_len-1] == PHP_DIR_SEPARATOR) { ++ memcpy(path_copy, path, path_len+1); ++ while (path_len > 0 && path_copy[path_len-1] == PHP_DIR_SEPARATOR) path_len--; ++ path_copy[path_len] = '\0'; ++ path = (const char *)&path_copy; ++ } + + pathbuf = estrdup(PG(open_basedir)); + +diff -Nura php-4.3.11/main/hardened_globals.h hardening-patch-4.3.11-0.4.2/main/hardened_globals.h +--- php-4.3.11/main/hardened_globals.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/main/hardened_globals.h 2005-09-07 18:41:00.977100368 +0200 +@@ -0,0 +1,60 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_GLOBALS_H ++#define HARDENED_GLOBALS_H ++ ++typedef struct _hardened_globals hardened_globals_struct; ++ ++#ifdef ZTS ++# define HG(v) TSRMG(hardened_globals_id, hardened_globals_struct *, v) ++extern int hardened_globals_id; ++#else ++# define HG(v) (hardened_globals.v) ++extern struct _hardened_globals hardened_globals; ++#endif ++ ++ ++struct _hardened_globals { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_1; ++ unsigned int canary_2; ++#endif ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_3; ++ unsigned int canary_4; ++ unsigned int ll_canary_inited; ++#endif ++ zend_bool hphp_sql_bailout_on_error; ++ zend_bool hphp_multiheader; ++ HashTable *eval_whitelist; ++ HashTable *eval_blacklist; ++ HashTable *func_whitelist; ++ HashTable *func_blacklist; ++ unsigned int dummy; ++}; ++ ++ ++#endif /* HARDENED_GLOBALS_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nura php-4.3.11/main/hardening_patch.c hardening-patch-4.3.11-0.4.2/main/hardening_patch.c +--- php-4.3.11/main/hardening_patch.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/main/hardening_patch.c 2005-09-07 19:04:56.164918656 +0200 +@@ -0,0 +1,323 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: hardening_patch.c,v 1.2 2004/11/21 09:38:52 ionic Exp $ */ ++ ++#include "php.h" ++ ++#include ++#include ++ ++#if HAVE_UNISTD_H ++#include ++#endif ++#include "SAPI.h" ++#include "php_globals.h" ++ ++#if HARDENING_PATCH ++ ++#ifdef HAVE_SYS_SOCKET_H ++#include ++#endif ++ ++#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE) ++#undef AF_UNIX ++#endif ++ ++#if defined(AF_UNIX) ++#include ++#endif ++ ++#define SYSLOG_PATH "/dev/log" ++ ++#include "snprintf.h" ++ ++#include "hardening_patch.h" ++ ++#ifdef ZTS ++#include "hardened_globals.h" ++int hardened_globals_id; ++#else ++struct _hardened_globals hardened_globals; ++#endif ++ ++static void hardened_globals_ctor(hardened_globals_struct *hardened_globals TSRMLS_DC) ++{ ++ memset(hardened_globals, 0, sizeof(*hardened_globals)); ++} ++ ++ ++PHPAPI void hardened_startup() ++{ ++#ifdef ZTS ++ ts_allocate_id(&hardened_globals_id, sizeof(hardened_globals_struct), (ts_allocate_ctor) hardened_globals_ctor, NULL); ++#else ++ hardened_globals_ctor(&hardened_globals TSRMLS_CC); ++#endif ++} ++ ++char *loglevel2string(int loglevel) ++{ ++ switch (loglevel) { ++ case S_FILES: ++ return "FILES"; ++ case S_INCLUDE: ++ return "INCLUDE"; ++ case S_MEMORY: ++ return "MEMORY"; ++ case S_MISC: ++ return "MISC"; ++ case S_SQL: ++ return "SQL"; ++ case S_EXECUTOR: ++ return "EXECUTOR"; ++ case S_VARS: ++ return "VARS"; ++ default: ++ return "UNKNOWN"; ++ } ++} ++ ++PHPAPI void php_security_log(int loglevel, char *fmt, ...) ++{ ++#if defined(AF_UNIX) ++ int s, r, i=0; ++ struct sockaddr_un saun; ++ char buf[4096+64]; ++ char error[4096+100]; ++ char *ip_address; ++ char *fname; ++ int lineno; ++ va_list ap; ++ TSRMLS_FETCH(); ++ ++ if (EG(hphp_log_use_x_forwarded_for)) { ++ ip_address = sapi_getenv("HTTP_X_FORWARDED_FOR", 20 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "X-FORWARDED-FOR not set"; ++ } ++ } else { ++ ip_address = sapi_getenv("REMOTE_ADDR", 11 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "REMOTE_ADDR not set"; ++ } ++ } ++ ++ ++ va_start(ap, fmt); ++ ap_php_vsnprintf(error, sizeof(error), fmt, ap); ++ va_end(ap); ++ while (error[i]) { ++ if (error[i] < 32) error[i] = '.'; ++ i++; ++ } ++ ++ if (zend_is_executing(TSRMLS_C)) { ++ lineno = zend_get_executed_lineno(TSRMLS_C); ++ fname = zend_get_executed_filename(TSRMLS_C); ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s', line %u)", error, ip_address, fname, lineno); ++ } else { ++ fname = sapi_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC); ++ if (fname==NULL) { ++ fname = "unknown"; ++ } ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s')", error, ip_address, fname); ++ } ++ ++ /* Syslog-Logging disabled? */ ++ if ((EG(hphp_log_syslog) & loglevel)==0) { ++ goto log_sapi; ++ } ++ ++ ap_php_snprintf(error, sizeof(error), "<%u>hphp[%u]: %s\n", EG(hphp_log_syslog_facility)|EG(hphp_log_syslog_priority),getpid(),buf); ++ ++ s = socket(AF_UNIX, SOCK_DGRAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ s = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ goto log_sapi; ++ } ++ } ++ send(s, error, strlen(error), 0); ++ ++ close(s); ++ ++log_sapi: ++ /* SAPI Logging activated? */ ++ if ((EG(hphp_log_syslog) & loglevel)!=0) { ++ sapi_module.log_message(buf); ++ } ++ ++log_script: ++ /* script logging activaed? */ ++ if (((EG(hphp_log_script) & loglevel)!=0) && EG(hphp_log_scriptname)!=NULL) { ++ char cmd[8192], *cmdpos, *bufpos; ++ FILE *in; ++ int space; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s \'", EG(hphp_log_scriptname), loglevel2string(loglevel)); ++ space = sizeof(cmd) - strlen(cmd); ++ cmdpos = cmd + strlen(cmd); ++ bufpos = buf; ++ if (space <= 1) return; ++ while (space > 2 && *bufpos) { ++ if (*bufpos == '\'') { ++ if (space<=5) break; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\\'; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\''; ++ bufpos++; ++ space-=4; ++ } else { ++ *cmdpos++ = *bufpos++; ++ space--; ++ } ++ } ++ *cmdpos++ = '\''; ++ *cmdpos = 0; ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_INTERNAL, "Unable to execute logging shell script: %s", EG(hphp_log_scriptname)); ++ return; ++ } ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ } ++ pclose(in); ++ } ++ ++#endif ++} ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++PHPAPI unsigned int php_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++ ++PHPAPI int php_is_valid_include(zval *z) ++{ ++ char *filename; ++ int len, i; ++ TSRMLS_FETCH(); ++ ++ /* must be of type string */ ++ if (z->type != IS_STRING || z->value.str.val == NULL) { ++ return (0); ++ } ++ ++ /* short cut */ ++ filename = z->value.str.val; ++ len = z->value.str.len; ++ ++ /* 1. must be shorter than MAXPATHLEN */ ++ if (len > MAXPATHLEN) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') longer than MAXPATHLEN chars", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 2. must not be cutted */ ++ if (len != strlen(filename)) { ++ char *fname = estrndup(filename, len); ++ for (i=0; fname[i]; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename truncated by a \\0 after '%s'", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 3. must not be a URL */ ++ if (strstr(filename, "://")) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') is an URL", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 4. must not be an uploaded file */ ++ if (SG(rfc1867_uploaded_files)) { ++ if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, len+1)) { ++ php_security_log(S_INCLUDE, "Include filename is an uploaded file"); ++ return (0); ++ } ++ } ++ ++ /* passed all tests */ ++ return (1); ++} ++ ++#endif ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-4.3.11/main/hardening_patch.h hardening-patch-4.3.11-0.4.2/main/hardening_patch.h +--- php-4.3.11/main/hardening_patch.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/main/hardening_patch.h 2005-09-07 19:04:56.165918504 +0200 +@@ -0,0 +1,46 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENING_PATCH_H ++#define HARDENING_PATCH_H ++ ++#include "zend.h" ++ ++#if HARDENING_PATCH ++PHPAPI void php_security_log(int loglevel, char *fmt, ...); ++PHPAPI void hardened_startup(); ++#define HARDENING_PATCH_VERSION "0.4.2" ++ ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++PHPAPI unsigned int php_canary(); ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++PHPAPI int php_is_valid_include(zval *z); ++#endif ++ ++#endif /* HARDENING_PATCH_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nura php-4.3.11/main/hardening_patch.m4 hardening-patch-4.3.11-0.4.2/main/hardening_patch.m4 +--- php-4.3.11/main/hardening_patch.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/main/hardening_patch.m4 2005-09-07 18:41:00.979100064 +0200 +@@ -0,0 +1,95 @@ ++dnl ++dnl $Id: hardening_patch.m4,v 1.1 2004/11/14 13:24:24 ionic Exp $ ++dnl ++dnl This file contains Hardening Patch for PHP specific autoconf functions. ++dnl ++ ++AC_ARG_ENABLE(hardening-patch-mm-protect, ++[ --disable-hardening-patch-mm-protect Disable the Memory Manager protection.],[ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-ll-protect, ++[ --disable-hardening-patch-ll-protect Disable the Linked List protection.],[ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-inc-protect, ++[ --disable-hardening-patch-inc-protect Disable include/require protection.],[ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-fmt-protect, ++[ --disable-hardening-patch-fmt-protect Disable format string protection.],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-hash-protect, ++[ --disable-hardening-patch-hash-protect Disable HashTable destructor protection.],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++]) ++ ++AC_MSG_CHECKING(whether to protect the Zend Memory Manager) ++AC_MSG_RESULT($DO_HARDENING_PATCH_MM_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the Zend Linked Lists) ++AC_MSG_RESULT($DO_HARDENING_PATCH_LL_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect include/require statements) ++AC_MSG_RESULT($DO_HARDENING_PATCH_INC_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect PHP Format String functions) ++AC_MSG_RESULT($DO_HARDENING_PATCH_FMT_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the destructor of Zend HashTables) ++AC_MSG_RESULT($DO_HARDENING_PATCH_HASH_PROTECT) ++ ++ ++AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 1, [Memory Manager Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 0, [Memory Manager Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 1, [Linked List Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 0, [Linked List Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 1, [Include/Require Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 0, [Include/Require Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 1, [Fmt String Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 0, [Fmt String Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 1, [HashTable DTOR Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 0, [HashTable DTOR Protection]) ++fi ++ +diff -Nura php-4.3.11/main/main.c hardening-patch-4.3.11-0.4.2/main/main.c +--- php-4.3.11/main/main.c 2005-03-08 22:45:51.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/main/main.c 2005-09-07 18:41:00.980099912 +0200 +@@ -100,6 +100,10 @@ + PHPAPI int core_globals_id; + #endif + ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#endif ++ + #define ERROR_BUF_LEN 1024 + + typedef struct { +@@ -150,10 +154,33 @@ + */ + static PHP_INI_MH(OnChangeMemoryLimit) + { ++#if HARDENING_PATCH ++ long orig_memory_limit; ++ ++ if (entry->modified) { ++ orig_memory_limit = zend_atoi(entry->orig_value, entry->orig_value_length); ++ } else { ++ orig_memory_limit = 1<<30; ++ } ++ if (orig_memory_limit < 0 || orig_memory_limit > (1<<30)) { ++ orig_memory_limit = 1<<30; ++ } ++#endif + if (new_value) { + PG(memory_limit) = zend_atoi(new_value, new_value_length); ++#if HARDENING_PATCH ++ if (PG(memory_limit) > orig_memory_limit) { ++ PG(memory_limit) = orig_memory_limit; ++ php_security_log(S_MISC, "script tried to increase memory_limit above allowed value"); ++ return FAILURE; ++ } ++#endif + } else { ++#if HARDENING_PATCH ++ PG(memory_limit) = orig_memory_limit; ++#else + PG(memory_limit) = 1<<30; /* effectively, no limit */ ++#endif + } + return zend_set_memory_limit(PG(memory_limit)); + } +@@ -1092,6 +1119,10 @@ + tsrm_ls = ts_resource(0); + #endif + ++#if HARDENING_PATCH ++ hardened_startup(); ++#endif ++ + sapi_initialize_empty_request(TSRMLS_C); + sapi_activate(TSRMLS_C); + +@@ -1104,6 +1135,12 @@ + php_output_startup(); + php_output_activate(TSRMLS_C); + ++#if HARDENING_PATCH_INC_PROTECT ++ zuf.is_valid_include = php_is_valid_include; ++#endif ++#if HARDENING_PATCH ++ zuf.security_log_function = php_security_log; ++#endif + zuf.error_function = php_error_cb; + zuf.printf_function = php_printf; + zuf.write_function = php_body_write_wrapper; +@@ -1205,6 +1242,10 @@ + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, sizeof(PHP_CONFIG_FILE_PATH)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("HARDENING_PATCH", 1, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_STRINGL_CONSTANT("HARDENING_PATCH_VERSION", HARDENING_PATCH_VERSION, sizeof(HARDENING_PATCH_VERSION)-1, CONST_PERSISTENT | CONST_CS); ++#endif + REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS); + php_output_register_constants(TSRMLS_C); + php_rfc1867_register_constants(TSRMLS_C); +@@ -1310,7 +1351,7 @@ + */ + static inline void php_register_server_variables(TSRMLS_D) + { +- zval *array_ptr=NULL; ++ zval *array_ptr=NULL, *vptr; + + ALLOC_ZVAL(array_ptr); + array_init(array_ptr); +@@ -1320,6 +1361,16 @@ + /* Server variables */ + if (sapi_module.register_server_variables) { + sapi_module.register_server_variables(array_ptr TSRMLS_CC); ++ if (zend_hash_find(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA"), (void **)&vptr)==SUCCESS) { ++ char *str; ++ if (vptr->type != IS_STRING) { ++ str = "Array"; ++ } else { ++ str = vptr->value.str.val; ++ } ++ php_security_log(S_VARS, "Attacker tried to overwrite HTTP_RAW_POST_DATA with '%s' through a HTTP header", str); ++ zend_hash_del(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA")); ++ } + } + + /* PHP Authentication support */ +diff -Nura php-4.3.11/main/php_config.h.in hardening-patch-4.3.11-0.4.2/main/php_config.h.in +--- php-4.3.11/main/php_config.h.in 2005-03-30 16:35:47.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/main/php_config.h.in 2005-09-07 18:41:00.981099760 +0200 +@@ -839,6 +839,39 @@ + /* Enabling BIND8 compatibility for Panther */ + #undef BIND_8_COMPAT + ++/* Hardening-Patch */ ++#undef HARDENING_PATCH ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ + /* Whether you have AOLserver */ + #undef HAVE_AOLSERVER + +@@ -1122,6 +1155,12 @@ + /* Define if you have the getaddrinfo function */ + #undef HAVE_GETADDRINFO + ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ + /* Whether system headers declare timezone */ + #undef HAVE_DECLARED_TIMEZONE + +diff -Nura php-4.3.11/main/php_content_types.c hardening-patch-4.3.11-0.4.2/main/php_content_types.c +--- php-4.3.11/main/php_content_types.c 2002-12-31 17:26:14.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/main/php_content_types.c 2005-09-07 18:41:00.981099760 +0200 +@@ -77,6 +77,7 @@ + sapi_register_post_entries(php_post_entries); + sapi_register_default_post_reader(php_default_post_reader); + sapi_register_treat_data(php_default_treat_data); ++ sapi_register_input_filter(php_default_input_filter); + return SUCCESS; + } + /* }}} */ +diff -Nura php-4.3.11/main/php.h hardening-patch-4.3.11-0.4.2/main/php.h +--- php-4.3.11/main/php.h 2005-03-08 22:45:51.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/main/php.h 2005-09-07 18:41:00.982099608 +0200 +@@ -35,11 +35,19 @@ + #include "zend_qsort.h" + #include "php_compat.h" + ++ + #include "zend_API.h" + + #undef sprintf + #define sprintf php_sprintf + ++#if HARDENING_PATCH ++#if HAVE_REALPATH ++#undef realpath ++#define realpath php_realpath ++#endif ++#endif ++ + /* PHP's DEBUG value must match Zend's ZEND_DEBUG value */ + #undef PHP_DEBUG + #define PHP_DEBUG ZEND_DEBUG +@@ -436,6 +444,10 @@ + #endif + #endif /* !XtOffsetOf */ + ++#if HARDENING_PATCH ++#include "hardening_patch.h" ++#endif ++ + #endif + + /* +diff -Nura php-4.3.11/main/php_variables.c hardening-patch-4.3.11-0.4.2/main/php_variables.c +--- php-4.3.11/main/php_variables.c 2004-10-18 17:08:46.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/main/php_variables.c 2005-09-07 18:41:00.982099608 +0200 +@@ -211,17 +211,28 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(PARSE_POST, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, "&", &strtok_buf); + } + } + ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter) ++{ ++ /* TODO: check .ini setting here and apply user-defined input filter */ ++ *new_val_len = val_len; ++ return 1; ++} ++ + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) + { + char *res = NULL, *var, *val, *separator=NULL; +@@ -299,15 +310,26 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } else { ++ unsigned int val_len, new_val_len; ++ + php_url_decode(var, strlen(var)); +- php_register_variable_safe(var, "", 0, array_ptr TSRMLS_CC); ++ val_len = 0; ++ val = estrndup("", 0); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, separator, &strtok_buf); + } +diff -Nura php-4.3.11/main/rfc1867.c hardening-patch-4.3.11-0.4.2/main/rfc1867.c +--- php-4.3.11/main/rfc1867.c 2005-02-15 01:28:39.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/main/rfc1867.c 2005-09-07 18:41:00.983099456 +0200 +@@ -127,6 +127,7 @@ + #define UPLOAD_ERROR_C 3 /* Partially uploaded */ + #define UPLOAD_ERROR_D 4 /* No file uploaded */ + #define UPLOAD_ERROR_E 6 /* Missing /tmp or similar directory */ ++#define UPLOAD_ERROR_F 7 /* Filter forbids upload */ + + void php_rfc1867_register_constants(TSRMLS_D) + { +@@ -136,6 +137,7 @@ + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL", UPLOAD_ERROR_C, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE", UPLOAD_ERROR_D, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FILTER", UPLOAD_ERROR_F, CONST_CS | CONST_PERSISTENT); + } + + static void normalize_protected_variable(char *varname TSRMLS_DC) +@@ -844,6 +846,7 @@ + char buff[FILLUNIT]; + char *cd=NULL,*param=NULL,*filename=NULL, *tmp=NULL; + int blen=0, wlen=0; ++ unsigned long offset; + + zend_llist_clean(&header); + +@@ -891,21 +894,24 @@ + if (!filename && param) { + + char *value = multipart_buffer_read_body(mbuff TSRMLS_CC); ++ unsigned int new_val_len; /* Dummy variable */ + + if (!value) { + value = estrdup(""); + } + ++ if (sapi_module.input_filter(PARSE_POST, param, &value, strlen(value), &new_val_len TSRMLS_CC)) { + #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) +- if (php_mb_encoding_translation(TSRMLS_C)) { +- php_mb_gpc_stack_variable(param, value, &val_list, &len_list, +- &num_vars, &num_vars_max TSRMLS_CC); +- } else { +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); +- } ++ if (php_mb_encoding_translation(TSRMLS_C)) { ++ php_mb_gpc_stack_variable(param, value, &val_list, &len_list, ++ &num_vars, &num_vars_max TSRMLS_CC); ++ } else { ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ } + #else +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); + #endif ++ } + if (!strcasecmp(param, "MAX_FILE_SIZE")) { + max_file_size = atol(value); + } +@@ -981,6 +987,11 @@ + cancel_upload = UPLOAD_ERROR_D; + } + ++ if (sapi_module.pre_upload_filter && sapi_module.pre_upload_filter(param, filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ ++ offset = 0; + while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff) TSRMLS_CC))) + { + if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize)) { +@@ -990,6 +1001,11 @@ + sapi_module.sapi_error(E_WARNING, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename); + cancel_upload = UPLOAD_ERROR_B; + } else if (blen > 0) { ++ ++ if (sapi_module.upload_content_filter && sapi_module.upload_content_filter(offset, buff, blen, &blen TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ + wlen = fwrite(buff, 1, blen, fp); + + if (wlen < blen) { +@@ -997,6 +1013,7 @@ + cancel_upload = UPLOAD_ERROR_C; + } else { + total_bytes += wlen; ++ offset += wlen; + } + } + } +@@ -1011,6 +1028,10 @@ + } + #endif + ++ if (!cancel_upload && sapi_module.post_upload_filter && sapi_module.post_upload_filter(temp_filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ + if (cancel_upload) { + if (temp_filename) { + if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */ +diff -Nura php-4.3.11/main/SAPI.c hardening-patch-4.3.11-0.4.2/main/SAPI.c +--- php-4.3.11/main/SAPI.c 2005-02-22 15:46:24.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/main/SAPI.c 2005-09-07 18:41:00.984099304 +0200 +@@ -831,6 +831,31 @@ + return SUCCESS; + } + ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) ++{ ++ sapi_module.input_filter = input_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)) ++{ ++ sapi_module.pre_upload_filter = pre_upload_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)) ++{ ++ sapi_module.upload_content_filter = upload_content_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)) ++{ ++ sapi_module.post_upload_filter = post_upload_filter; ++ return SUCCESS; ++} ++ ++ + + SAPI_API int sapi_flush(TSRMLS_D) + { +diff -Nura php-4.3.11/main/SAPI.h hardening-patch-4.3.11-0.4.2/main/SAPI.h +--- php-4.3.11/main/SAPI.h 2003-04-09 22:27:55.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/main/SAPI.h 2005-09-07 18:41:00.985099152 +0200 +@@ -101,9 +101,10 @@ + char *current_user; + int current_user_length; + +- /* this is necessary for CLI module */ +- int argc; +- char **argv; ++ /* this is necessary for CLI module */ ++ int argc; ++ char **argv; ++ + } sapi_request_info; + + +@@ -177,6 +178,10 @@ + SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry); + SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D)); + SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC)); ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)); ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)); ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)); ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)); + + SAPI_API int sapi_flush(TSRMLS_D); + SAPI_API struct stat *sapi_get_stat(TSRMLS_D); +@@ -238,8 +243,15 @@ + int (*get_target_uid)(uid_t * TSRMLS_DC); + int (*get_target_gid)(gid_t * TSRMLS_DC); + ++ unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); ++ ++ unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC); ++ unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC); ++ unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC); ++ + void (*ini_defaults)(HashTable *configuration_hash); + int phpinfo_as_text; ++ + }; + + +@@ -262,16 +274,26 @@ + + #define SAPI_DEFAULT_MIMETYPE "text/html" + #define SAPI_DEFAULT_CHARSET "" ++ ++#if HARDENING_PATCH ++#define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION " with Hardening-Patch" ++#else + #define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION ++#endif + + #define SAPI_POST_READER_FUNC(post_reader) void post_reader(TSRMLS_D) + #define SAPI_POST_HANDLER_FUNC(post_handler) void post_handler(char *content_type_dup, void *arg TSRMLS_DC) + + #define SAPI_TREAT_DATA_FUNC(treat_data) void treat_data(int arg, char *str, zval* destArray TSRMLS_DC) ++#define SAPI_INPUT_FILTER_FUNC(input_filter) unsigned int input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) ++#define SAPI_PRE_UPLOAD_FILTER_FUNC(pre_upload_filter) unsigned int pre_upload_filter(char *varname, char *filename TSRMLS_DC) ++#define SAPI_UPLOAD_CONTENT_FILTER_FUNC(upload_content_filter) unsigned int upload_content_filter(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC) ++#define SAPI_POST_UPLOAD_FILTER_FUNC(post_upload_filter) unsigned int post_upload_filter(char *tmpfilename TSRMLS_DC) + + SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data); + SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader); + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data); ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter); + + #define STANDARD_SAPI_MODULE_PROPERTIES + +diff -Nura php-4.3.11/main/snprintf.c hardening-patch-4.3.11-0.4.2/main/snprintf.c +--- php-4.3.11/main/snprintf.c 2004-11-16 00:27:26.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/main/snprintf.c 2005-09-07 18:41:00.985099152 +0200 +@@ -850,7 +850,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Nura php-4.3.11/main/spprintf.c hardening-patch-4.3.11-0.4.2/main/spprintf.c +--- php-4.3.11/main/spprintf.c 2003-09-29 03:09:36.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/main/spprintf.c 2005-09-07 18:41:00.986099000 +0200 +@@ -531,7 +531,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Nura php-4.3.11/pear/go-pear-list.php hardening-patch-4.3.11-0.4.2/pear/go-pear-list.php +--- php-4.3.11/pear/go-pear-list.php 2005-03-18 02:58:20.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/pear/go-pear-list.php 2005-09-07 19:04:56.234908016 +0200 +@@ -8,7 +8,7 @@ + $packages = array( + // required packages for the installer + "PEAR" => "1.3.5", +-"XML_RPC" => "1.2.2", ++"XML_RPC" => "1.4.0", + "Console_Getopt" => "1.2", + "Archive_Tar" => "1.3.1", + +diff -Nura php-4.3.11/pear/packages/XML_RPC-1.2.2.tar hardening-patch-4.3.11-0.4.2/pear/packages/XML_RPC-1.2.2.tar +--- php-4.3.11/pear/packages/XML_RPC-1.2.2.tar 2005-03-28 19:02:28.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/pear/packages/XML_RPC-1.2.2.tar 1970-01-01 01:00:00.000000000 +0100 +@@ -1,3393 +0,0 @@ +-package2.xml100666 0 0 24326 10213112551 6327 +- +- XML_RPC +- pear.php.net +- PHP implementation of the XML-RPC protocol +- A PEAR-ified version of Useful Inc's XML-RPC for PHP. +- +-It has support for HTTP/HTTPS transport, proxies and authentication. +- +- Stig Bakken +- ssb +- stig@php.net +- no +- +- +- Daniel Convissor +- danielc +- danielc@php.net +- yes +- +- 2005-03-07 +- +- +- 1.2.2 +- 1.2.0 +- +- +- stable +- stable +- +- PHP License +- * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- PEAR +- pear.php.net +- 1.4.0a1 +- 1.4.0a4 +- +- +- +- +- 4.2.0 +- 6.0.0 +- +- +- 1.4.0a1 +- +- +- +- +- +- +- +- 1.2.1 +- 1.2.0 +- +- +- stable +- stable +- +- 2005-03-01 +- PHP License +- * Add isset() check before examining the dispatch map. Bug 3658. +- +- +- +- 1.2.0 +- 1.2.0 +- +- +- stable +- stable +- +- 2005-02-27 +- PHP License +- * Provide the "stable" release. +-* Add package2.xml for compatibility with PEAR 1.4.0. +-* For changes since 1.1.0, see the changelogs for the various RC releases. +- +- +- +- 1.2.0RC7 +- 1.2.0RC7 +- +- +- beta +- beta +- +- 2005-02-22 +- PHP License +- * Add the setSendEncoding() method and $send_encoding +- property to XML_RPC_Message. Request 3537. +-* Allow class methods to be mapped using either syntax: +- 'function' => 'hello::sayHello', +- or +- 'function' => array('hello', 'sayhello'), +- Bug 3363. +-* Use 8192 instead of 32768 for bytes in fread() +- in parseResponseFile(). Bug 3340. +- +- +- +- 1.2.0RC6 +- 1.2.0RC6 +- +- +- beta +- beta +- +- 2005-01-25 +- PHP License +- * Don't put the protocol in the Host field of the POST data. (danielc) +- +- +- +- 1.2.0RC5 +- 1.2.0RC5 +- +- +- beta +- beta +- +- 2005-01-24 +- PHP License +- * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. +- +- +- +- 1.2.0RC4 +- 1.2.0RC4 +- +- +- beta +- beta +- +- 2005-01-24 +- PHP License +- * When a connection attempt fails, have the method return 0. (danielc) +-* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) +-* Add tests for setting the client properties. (danielc) +-* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) +-* Bundle the tests with the package. (danielc) +- +- +- +- 1.2.0RC3 +- 1.2.0RC3 +- +- +- beta +- beta +- +- 2005-01-19 +- PHP License +- * ssl uses port 443, not 445. +- +- +- +- 1.2.0RC2 +- 1.2.0RC2 +- +- +- beta +- beta +- +- 2005-01-11 +- PHP License +- * Handle ssl:// in the $server string. (danielc) +-* Also default to port 445 for ssl:// requests as well. (danielc) +-* Enhance debugging in the server. (danielc) +- +- +- +- 1.2.0RC1 +- 1.2.0RC1 +- +- +- beta +- beta +- +- 2004-12-30 +- PHP License +- * Make things work with SSL. Bug 2489. (nkukard lbsd net) +-* Allow array function callbacks (Matt Kane) +-* Some minor speed-ups (Matt Kane) +-* Add Dump.php to the package (Christian Weiske) +-* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) +-* Silence fsockopen() errors. Bug 1714. (danielc) +-* Encode empty arrays as an array. Bug 1493. (danielc) +-* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) +-* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) +-* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) +-* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) +-* Allow raiseError() to be called statically. (danielc) +-* Stop double escaping of character entities. Bug 987. (danielc) +- NOTICE: the following have been removed: +- * XML_RPC_dh() +- * $GLOBALS['XML_RPC_entities'] +- * XML_RPC_entity_decode() +- * XML_RPC_lookup_entity() +-* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) +- +- +- +- 1.1.0 +- 1.1.0 +- +- +- stable +- stable +- +- 2004-03-15 +- PHP License +- * Added support for sequential arrays to XML_RPC_encode() (mroch) +-* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) +-* Remove "require_once 'PEAR.php'", include only when needed to raise an error +-* Replace echo and error_log() with raiseError() (mroch) +-* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) +-* be tolerant of junk after methodResponse (Luca Mariano, mroch) +-* Silent notice even in the error log (pierre) +-* fix include of shared xml extension on win32 (pierre) +- +- +- +- 1.0.4 +- 1.0.4 +- +- +- stable +- stable +- +- 2002-10-02 +- PHP License +- * added HTTP proxy authorization support (thanks to Arnaud Limbourg) +- +- +- +- 1.0.3 +- 1.0.3 +- +- +- stable +- stable +- +- 2002-05-19 +- PHP License +- * fix bug when parsing responses with boolean types +- +- +- +- 1.0.2 +- 1.0.2 +- +- +- stable +- stable +- +- 2002-04-16 +- PHP License +- * E_ALL fixes +-* fix HTTP response header parsing +- +- +- +- 1.0.1 +- 1.0.1 +- +- +- stable +- stable +- +- 2001-09-25 +- PHP License +- This is a PEAR-ified version of Useful Inc's 1.0.1 release. +-Includes an urgent security fix identified by Dan Libby <dan@libby.com>. +- +- +-XML_RPC-1.2.2/tests/protoport.php100666 0 0 25543 10213112550 11656 +- * @copyright 2005 The PHP Group +- * @license http://www.php.net/license/3_0.txt PHP License +- * @version CVS: $Id: protoport.php,v 1.4 2005/01/24 17:48:47 danielc Exp $ +- * @link http://pear.php.net/package/XML_RPC +- * @since File available since Release 1.2 +- */ +- +-/* +- * If the package version number is found in the left hand +- * portion of the if() expression below, that means this file has +- * come from the PEAR installer. Therefore, let's test the +- * installed version of XML_RPC which should be in the include path. +- * +- * If the version has not been substituted in the if() expression, +- * this file has likely come from a CVS checkout or a .tar file. +- * Therefore, we'll assume the tests should use the version of +- * XML_RPC that has come from there as well. +- */ +-if ('1.2.2' != '@'.'package_version'.'@') { +- /** +- * Get the needed class from the PEAR installation +- */ +- require_once 'XML/RPC.php'; +-} else { +- /** +- * Get the needed class from the parent directory +- */ +- require_once '../RPC.php'; +-} +- +-/** +- * Compare the test result to the expected result +- * +- * If the test fails, echo out the results. +- * +- * @param array $expect the array of object properties you expect +- * from the test +- * @param object $actual the object results from the test +- * @param string $test_name the name of the test +- * +- * @return void +- */ +-function compare($expect, $actual, $test_name) { +- $actual = get_object_vars($actual); +- if (count(array_diff($actual, $expect))) { +- echo "$test_name failed.\nExpect: "; +- print_r($expect); +- echo "Actual: "; +- print_r($actual); +- echo "\n"; +- } +-} +- +-if (php_sapi_name() != 'cli') { +- echo "
\n";
+-}
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver');
+-compare($x, $c, 'defaults');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver');
+-compare($x, $c, 'defaults with http');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver');
+-compare($x, $c, 'defaults with https');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver');
+-compare($x, $c, 'defaults with ssl');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 65);
+-compare($x, $c, 'port 65');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 65);
+-compare($x, $c, 'port 65 with http');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 65);
+-compare($x, $c, 'port 65 with https');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65);
+-compare($x, $c, 'port 65 with ssl');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 0,
+-                        'theproxy');
+-compare($x, $c, 'defaults proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 0,
+-                        'http://theproxy');
+-compare($x, $c, 'defaults with http proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 0,
+-                        'https://theproxy');
+-compare($x, $c, 'defaults with https proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 0,
+-                        'ssl://theproxy');
+-compare($x, $c, 'defaults with ssl proxy');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 65,
+-                        'theproxy', 6565);
+-compare($x, $c, 'port 65 proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 65,
+-                        'http://theproxy', 6565);
+-compare($x, $c, 'port 65 with http proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 65,
+-                        'https://theproxy', 6565);
+-compare($x, $c, 'port 65 with https proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65,
+-                        'ssl://theproxy', 6565);
+-compare($x, $c, 'port 65 with ssl proxy 6565');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 443,
+-                        'theproxy', 443);
+-compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 0,
+-                        'ssl://theproxy', 6565);
+-compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
+-XML_RPC-1.2.2/tests/test_Dump.php100666      0      0        3042 10213112550  11520 new XML_RPC_Value('das ist der Titel', 'string'),
+-    'startDate'=>new XML_RPC_Value(mktime(0,0,0,13,11,2004), 'dateTime.iso8601'),
+-    'endDate'  =>new XML_RPC_Value(mktime(0,0,0,15,11,2004), 'dateTime.iso8601'),
+-    'error'    =>'string',
+-    'arkey'    => new XML_RPC_Value( array(
+-        new XML_RPC_Value('simple string'),
+-        new XML_RPC_Value(12345, 'int')
+-        ), 'array')
+-    )
+-    ,'struct');
+-
+-XML_RPC_Dump($val);
+-
+-echo '==============' . "\r\n";
+-$val2 = new XML_RPC_Value(44353, 'int');
+-XML_RPC_Dump($val2);
+-
+-echo '==============' . "\r\n";
+-$val3 = new XML_RPC_Value('this should be a string', 'string');
+-XML_RPC_Dump($val3);
+-
+-echo '==============' . "\r\n";
+-$val4 = new XML_RPC_Value(true, 'boolean');
+-XML_RPC_Dump($val4);
+-XML_RPC-1.2.2/Dump.php100666      0      0       12074 10213112550   7344 
+- * @version    CVS: $Id: Dump.php,v 1.7 2005/01/24 03:47:55 danielc Exp $
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-
+-
+-/**
+- * Pull in the XML_RPC class
+- */
+-require_once 'XML/RPC.php';
+-
+-
+-/**
+- * Generates the dump of the XML_RPC_Value and echoes it
+- *
+- * @param object $value  the XML_RPC_Value object to dump
+- *
+- * @return void
+- */
+-function XML_RPC_Dump($value)
+-{
+-    $dumper = new XML_RPC_Dump();
+-    echo $dumper->generateDump($value);
+-}
+-
+-
+-/**
+- * Class which generates a dump of a XML_RPC_Value object
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Christian Weiske 
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Dump
+-{
+-    /**
+-     * The indentation array cache
+-     * @var array
+-     */
+-    var $arIndent      = array();
+-
+-    /**
+-     * The spaces used for indenting the XML
+-     * @var string
+-     */
+-    var $strBaseIndent = '    ';
+-
+-    /**
+-     * Returns the dump in XML format without printing it out
+-     *
+-     * @param object $value   the XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  the dump
+-     */
+-    function generateDump($value, $nLevel = 0)
+-    {
+-        if (!is_object($value) && get_class($value) != 'xml_rpc_value') {
+-            require_once 'PEAR.php';
+-            PEAR::raiseError('Tried to dump non-XML_RPC_Value variable' . "\r\n",
+-                             0, PEAR_ERROR_PRINT);
+-            if (is_object($value)) {
+-                $strType = get_class($value);
+-            } else {
+-                $strType = gettype($value);
+-            }
+-            return $this->getIndent($nLevel) . 'NOT A XML_RPC_Value: '
+-                   . $strType . "\r\n";
+-        }
+-
+-        switch ($value->kindOf()) {
+-        case 'struct':
+-            $ret = $this->genStruct($value, $nLevel);
+-            break;
+-        case 'array':
+-            $ret = $this->genArray($value, $nLevel);
+-            break;
+-        case 'scalar':
+-            $ret = $this->genScalar($value->scalarval(), $nLevel);
+-            break;
+-        default:
+-            require_once 'PEAR.php';
+-            PEAR::raiseError('Illegal type "' . $value->kindOf()
+-                             . '" in XML_RPC_Value' . "\r\n", 0,
+-                             PEAR_ERROR_PRINT);
+-        }
+-
+-        return $ret;
+-    }
+-
+-    /**
+-     * Returns the scalar value dump
+-     *
+-     * @param object $value   the scalar XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genScalar($value, $nLevel)
+-    {
+-        if (gettype($value) == 'object') {
+-            $strClass = ' ' . get_class($value);
+-        } else {
+-            $strClass = '';
+-        }
+-        return $this->getIndent($nLevel) . gettype($value) . $strClass
+-               . ' ' . $value . "\r\n";
+-    }
+-
+-    /**
+-     * Returns the dump of a struct
+-     *
+-     * @param object $value   the struct XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genStruct($value, $nLevel)
+-    {
+-        $value->structreset();
+-        $strOutput = $this->getIndent($nLevel) . 'struct' . "\r\n";
+-        while (list($key, $keyval) = $value->structeach()) {
+-            $strOutput .= $this->getIndent($nLevel + 1) . $key . "\r\n";
+-            $strOutput .= $this->generateDump($keyval, $nLevel + 2);
+-        }
+-        return $strOutput;
+-    }
+-
+-    /**
+-     * Returns the dump of an array
+-     *
+-     * @param object $value   the array XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genArray($value, $nLevel)
+-    {
+-        $nSize     = $value->arraysize();
+-        $strOutput = $this->getIndent($nLevel) . 'array' . "\r\n";
+-        for($nA = 0; $nA < $nSize; $nA++) {
+-            $strOutput .= $this->getIndent($nLevel + 1) . $nA . "\r\n";
+-            $strOutput .= $this->generateDump($value->arraymem($nA),
+-                                              $nLevel + 2);
+-        }
+-        return $strOutput;
+-    }
+-
+-    /**
+-     * Returns the indent for a specific level and caches it for faster use
+-     *
+-     * @param int $nLevel  the level
+-     *
+-     * @return string  the indented string
+-     */
+-    function getIndent($nLevel)
+-    {
+-        if (!isset($this->arIndent[$nLevel])) {
+-            $this->arIndent[$nLevel] = str_repeat($this->strBaseIndent, $nLevel);
+-        }
+-        return $this->arIndent[$nLevel];
+-    }
+-}
+-
+-/*
+- * Local variables:
+- * tab-width: 4
+- * c-basic-offset: 4
+- * c-hanging-comment-ender-p: nil
+- * End:
+- */
+-
+-?>
+-XML_RPC-1.2.2/RPC.php100666      0      0      141000 10213112550   7073 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    CVS: $Id: RPC.php,v 1.60 2005/03/07 17:45:08 danielc Exp $
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-
+-
+-if (!function_exists('xml_parser_create')) {
+-    // Win 32 fix. From: "Leo West" 
+-    if ($WINDIR) {
+-        dl('php_xml.dll');
+-    } else {
+-        dl('xml.so');
+-    }
+-}
+-
+-/**#@+
+- * Error constants
+- */
+-define('XML_RPC_ERROR_INVALID_TYPE',        101);
+-define('XML_RPC_ERROR_NON_NUMERIC_FOUND',   102);
+-define('XML_RPC_ERROR_CONNECTION_FAILED',   103);
+-define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
+-/**#@-*/
+-
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_I4']
+- */
+-$GLOBALS['XML_RPC_I4'] = 'i4';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Int']
+- */
+-$GLOBALS['XML_RPC_Int'] = 'int';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Boolean']
+- */
+-$GLOBALS['XML_RPC_Boolean'] = 'boolean';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Double']
+- */
+-$GLOBALS['XML_RPC_Double'] = 'double';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_String']
+- */
+-$GLOBALS['XML_RPC_String'] = 'string';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_DateTime']
+- */
+-$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Base64']
+- */
+-$GLOBALS['XML_RPC_Base64'] = 'base64';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Array']
+- */
+-$GLOBALS['XML_RPC_Array'] = 'array';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Struct']
+- */
+-$GLOBALS['XML_RPC_Struct'] = 'struct';
+-
+-
+-/**
+- * Data type meta-types
+- * @global array $GLOBALS['XML_RPC_Types']
+- */
+-$GLOBALS['XML_RPC_Types'] = array(
+-    $GLOBALS['XML_RPC_I4']       => 1,
+-    $GLOBALS['XML_RPC_Int']      => 1,
+-    $GLOBALS['XML_RPC_Boolean']  => 1,
+-    $GLOBALS['XML_RPC_String']   => 1,
+-    $GLOBALS['XML_RPC_Double']   => 1,
+-    $GLOBALS['XML_RPC_DateTime'] => 1,
+-    $GLOBALS['XML_RPC_Base64']   => 1,
+-    $GLOBALS['XML_RPC_Array']    => 2,
+-    $GLOBALS['XML_RPC_Struct']   => 3,
+-);
+-
+-
+-/**
+- * Error message numbers
+- * @global array $GLOBALS['XML_RPC_err']
+- */
+-$GLOBALS['XML_RPC_err'] = array(
+-    'unknown_method'      => 1,
+-    'invalid_return'      => 2,
+-    'incorrect_params'    => 3,
+-    'introspect_unknown'  => 4,
+-    'http_error'          => 5,
+-);
+-
+-/**
+- * Error message strings
+- * @global array $GLOBALS['XML_RPC_str']
+- */
+-$GLOBALS['XML_RPC_str'] = array(
+-    'unknown_method'      => 'Unknown method',
+-    'invalid_return'      => 'Invalid return payload: enable debugging to examine incoming payload',
+-    'incorrect_params'    => 'Incorrect parameters passed to method',
+-    'introspect_unknown'  => 'Can\'t introspect: method unknown',
+-    'http_error'          => 'Didn\'t receive 200 OK from remote server.',
+-);
+-
+-
+-/**
+- * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
+- * @global string $GLOBALS['XML_RPC_defencoding']
+- */
+-$GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
+-
+-/**
+- * User error codes start at 800
+- * @global int $GLOBALS['XML_RPC_erruser']
+- */
+-$GLOBALS['XML_RPC_erruser'] = 800;
+-
+-/**
+- * XML parse error codes start at 100
+- * @global int $GLOBALS['XML_RPC_errxml']
+- */
+-$GLOBALS['XML_RPC_errxml'] = 100;
+-
+-
+-/**
+- * Compose backslashes for escaping regexp
+- * @global string $GLOBALS['XML_RPC_backslash']
+- */
+-$GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
+-
+-
+-/**
+- * Stores state during parsing
+- *
+- * quick explanation of components:
+- *   + st     = builds up a string for evaluation
+- *   + ac     = accumulates values
+- *   + qt     = decides if quotes are needed for evaluation
+- *   + cm     = denotes struct or array (comma needed)
+- *   + isf    = indicates a fault
+- *   + lv     = indicates "looking for a value": implements the logic
+- *               to allow values with no types to be strings
+- *   + params = stores parameters in method calls
+- *   + method = stores method name
+- *
+- * @global array $GLOBALS['XML_RPC_xh']
+- */
+-$GLOBALS['XML_RPC_xh'] = array();
+-
+-
+-/**
+- * Start element handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_se($parser, $name, $attrs)
+-{
+-    global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String;
+-
+-    switch ($name) {
+-    case 'STRUCT':
+-    case 'ARRAY':
+-        $XML_RPC_xh[$parser]['st'] .= 'array(';
+-        $XML_RPC_xh[$parser]['cm']++;
+-        // this last line turns quoting off
+-        // this means if we get an empty array we'll
+-        // simply get a bit of whitespace in the eval
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'NAME':
+-        $XML_RPC_xh[$parser]['st'] .= "'";
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        break;
+-
+-    case 'FAULT':
+-        $XML_RPC_xh[$parser]['isf'] = 1;
+-        break;
+-
+-    case 'PARAM':
+-        $XML_RPC_xh[$parser]['st'] = '';
+-        break;
+-
+-    case 'VALUE':
+-        $XML_RPC_xh[$parser]['st'] .= 'new XML_RPC_Value(';
+-        $XML_RPC_xh[$parser]['lv'] = 1;
+-        $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        // look for a value: if this is still 1 by the
+-        // time we reach the first data segment then the type is string
+-        // by implication and we need to add in a quote
+-        break;
+-
+-    case 'I4':
+-    case 'INT':
+-    case 'STRING':
+-    case 'BOOLEAN':
+-    case 'DOUBLE':
+-    case 'DATETIME.ISO8601':
+-    case 'BASE64':
+-        $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
+-
+-        if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
+-            $XML_RPC_xh[$parser]['qt'] = 1;
+-
+-            if ($name == 'DATETIME.ISO8601') {
+-                $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
+-            }
+-
+-        } elseif ($name == 'BASE64') {
+-            $XML_RPC_xh[$parser]['qt'] = 2;
+-        } else {
+-            // No quoting is required here -- but
+-            // at the end of the element we must check
+-            // for data format errors.
+-            $XML_RPC_xh[$parser]['qt'] = 0;
+-        }
+-        break;
+-
+-    case 'MEMBER':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-    }
+-
+-    if ($name != 'VALUE') {
+-        $XML_RPC_xh[$parser]['lv'] = 0;
+-    }
+-}
+-
+-/**
+- * End element handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_ee($parser, $name)
+-{
+-    global $XML_RPC_xh, $XML_RPC_Types, $XML_RPC_String;
+-
+-    switch ($name) {
+-    case 'STRUCT':
+-    case 'ARRAY':
+-        if ($XML_RPC_xh[$parser]['cm']
+-            && substr($XML_RPC_xh[$parser]['st'], -1) == ',')
+-        {
+-            $XML_RPC_xh[$parser]['st'] = substr($XML_RPC_xh[$parser]['st'], 0, -1);
+-        }
+-
+-        $XML_RPC_xh[$parser]['st'] .= ')';
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-        $XML_RPC_xh[$parser]['cm']--;
+-        break;
+-
+-    case 'NAME':
+-        $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'] . "' => ";
+-        break;
+-
+-    case 'BOOLEAN':
+-        // special case here: we translate boolean 1 or 0 into PHP
+-        // constants true or false
+-        if ($XML_RPC_xh[$parser]['ac'] == '1') {
+-            $XML_RPC_xh[$parser]['ac'] = 'true';
+-        } else {
+-            $XML_RPC_xh[$parser]['ac'] = 'false';
+-        }
+-
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-        // Drop through intentionally.
+-
+-    case 'I4':
+-    case 'INT':
+-    case 'STRING':
+-    case 'DOUBLE':
+-    case 'DATETIME.ISO8601':
+-    case 'BASE64':
+-        if ($XML_RPC_xh[$parser]['qt'] == 1) {
+-            // we use double quotes rather than single so backslashification works OK
+-            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
+-        } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
+-            $XML_RPC_xh[$parser]['st'] .= "base64_decode('"
+-                                        . $XML_RPC_xh[$parser]['ac'] . "')";
+-        } elseif ($name == 'BOOLEAN') {
+-            $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
+-        } else {
+-            // we have an I4, INT or a DOUBLE
+-            // we must check that only 0123456789-. are characters here
+-            if (!ereg("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
+-                XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
+-                                         XML_RPC_ERROR_NON_NUMERIC_FOUND);
+-                $XML_RPC_xh[$parser]['st'] .= 'XML_RPC_ERROR_NON_NUMERIC_FOUND';
+-            } else {
+-                // it's ok, add it on
+-                $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
+-            }
+-        }
+-
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
+-        break;
+-
+-    case 'VALUE':
+-        // deal with a string value
+-        if (strlen($XML_RPC_xh[$parser]['ac']) > 0 &&
+-            $XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
+-
+-            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
+-        }
+-
+-        // This if () detects if no scalar was inside 
+-        // and pads an empty "".
+-        if ($XML_RPC_xh[$parser]['st'][strlen($XML_RPC_xh[$parser]['st'])-1] == '(') {
+-            $XML_RPC_xh[$parser]['st'] .= '""';
+-        }
+-        $XML_RPC_xh[$parser]['st'] .= ", '" . $XML_RPC_xh[$parser]['vt'] . "')";
+-        if ($XML_RPC_xh[$parser]['cm']) {
+-            $XML_RPC_xh[$parser]['st'] .= ',';
+-        }
+-        break;
+-
+-    case 'MEMBER':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'DATA':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'PARAM':
+-        $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['st'];
+-        break;
+-
+-    case 'METHODNAME':
+-        $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", '',
+-                                                      $XML_RPC_xh[$parser]['ac']);
+-        break;
+-
+-    case 'BOOLEAN':
+-        // special case here: we translate boolean 1 or 0 into PHP
+-        // constants true or false
+-        if ($XML_RPC_xh[$parser]['ac'] == '1') {
+-            $XML_RPC_xh[$parser]['ac'] = 'true';
+-        } else {
+-            $XML_RPC_xh[$parser]['ac'] = 'false';
+-        }
+-
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-    }
+-
+-    // if it's a valid type name, set the type
+-    if (isset($XML_RPC_Types[strtolower($name)])) {
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-    }
+-}
+-
+-/**
+- * Character data handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_cd($parser, $data)
+-{
+-    global $XML_RPC_xh, $XML_RPC_backslash;
+-
+-    if ($XML_RPC_xh[$parser]['lv'] != 3) {
+-        // "lookforvalue==3" means that we've found an entire value
+-        // and should discard any further character data
+-
+-        if ($XML_RPC_xh[$parser]['lv'] == 1) {
+-            // if we've found text and we're just in a  then
+-            // turn quoting on, as this will be a string
+-            $XML_RPC_xh[$parser]['qt'] = 1;
+-            // and say we've found a value
+-            $XML_RPC_xh[$parser]['lv'] = 2;
+-        }
+-
+-        // replace characters that eval would
+-        // do special things with
+-        if (!isset($XML_RPC_xh[$parser]['ac'])) {
+-            $XML_RPC_xh[$parser]['ac'] = '';
+-        }
+-        $XML_RPC_xh[$parser]['ac'] .= str_replace('$', '\$',
+-            str_replace('"', '\"', str_replace(chr(92),
+-            $XML_RPC_backslash, $data)));
+-    }
+-}
+-
+-/**
+- * Base class
+- *
+- * This class provides common functions for all of the XML_RPC classes.
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Base {
+-
+-    /**
+-     * PEAR Error handling
+-     *
+-     * @return object  PEAR_Error object
+-     */
+-    function raiseError($msg, $code)
+-    {
+-        include_once 'PEAR.php';
+-        if (is_object(@$this)) {
+-            return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
+-        } else {
+-            return PEAR::raiseError('XML_RPC: ' . $msg, $code);
+-        }
+-    }
+-
+-    /**
+-     * Tell whether something is a PEAR_Error object
+-     *
+-     * @param mixed $value  the item to check
+-     *
+-     * @return bool  whether $value is a PEAR_Error object or not
+-     *
+-     * @access public
+-     */
+-    function isError($value)
+-    {
+-        return is_a($value, 'PEAR_Error');
+-    }
+-}
+-
+-/**
+- *
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Client extends XML_RPC_Base {
+-
+-    /**
+-     * The path and name of the RPC server script you want the request to go to
+-     * @var string
+-     */
+-    var $path = '';
+-
+-    /**
+-     * The name of the remote server to connect to
+-     * @var string
+-     */
+-    var $server = '';
+-
+-    /**
+-     * The protocol to use in contacting the remote server
+-     * @var string
+-     */
+-    var $protocol = 'http://';
+-
+-    /**
+-     * The port for connecting to the remote server
+-     *
+-     * The default is 80 for http:// connections
+-     * and 443 for https:// and ssl:// connections.
+-     *
+-     * @var integer
+-     */
+-    var $port = 80;
+-
+-    /**
+-     * A user name for accessing the RPC server
+-     * @var string
+-     * @see XML_RPC_Client::setCredentials()
+-     */
+-    var $username = '';
+-
+-    /**
+-     * A password for accessing the RPC server
+-     * @var string
+-     * @see XML_RPC_Client::setCredentials()
+-     */
+-    var $password = '';
+-
+-    /**
+-     * The name of the proxy server to use, if any
+-     * @var string
+-     */
+-    var $proxy = '';
+-
+-    /**
+-     * The protocol to use in contacting the proxy server, if any
+-     * @var string
+-     */
+-    var $proxy_protocol = 'http://';
+-
+-    /**
+-     * The port for connecting to the proxy server
+-     *
+-     * The default is 8080 for http:// connections
+-     * and 443 for https:// and ssl:// connections.
+-     *
+-     * @var integer
+-     */
+-    var $proxy_port = 8080;
+-
+-    /**
+-     * A user name for accessing the proxy server
+-     * @var string
+-     */
+-    var $proxy_user = '';
+-
+-    /**
+-     * A password for accessing the proxy server
+-     * @var string
+-     */
+-    var $proxy_pass = '';
+-
+-    /**
+-     * The error number, if any
+-     * @var integer
+-     */
+-    var $errno = 0;
+-
+-    /**
+-     * The error message, if any
+-     * @var string
+-     */
+-    var $errstring = '';
+-
+-    /**
+-     * The current debug mode (1 = on, 0 = off)
+-     * @var integer
+-     */
+-    var $debug = 0;
+-
+-
+-    /**
+-     * Sets the object's properties
+-     *
+-     * @param string  $path        the path and name of the RPC server script
+-     *                              you want the request to go to
+-     * @param string  $server      the URL of the remote server to connect to.
+-     *                              If this parameter doesn't specify a
+-     *                              protocol and $port is 443, ssl:// is
+-     *                              assumed.
+-     * @param integer $port        a port for connecting to the remote server.
+-     *                              Defaults to 80 for http:// connections and
+-     *                              443 for https:// and ssl:// connections.
+-     * @param string  $proxy       the URL of the proxy server to use, if any.
+-     *                              If this parameter doesn't specify a
+-     *                              protocol and $port is 443, ssl:// is
+-     *                              assumed.
+-     * @param integer $proxy_port  a port for connecting to the remote server.
+-     *                              Defaults to 8080 for http:// connections and
+-     *                              443 for https:// and ssl:// connections.
+-     * @param string  $proxy_user  a user name for accessing the proxy server
+-     * @param string  $proxy_pass  a password for accessing the proxy server
+-     *
+-     * @return void
+-     */
+-    function XML_RPC_Client($path, $server, $port = 0,
+-                            $proxy = '', $proxy_port = 0,
+-                            $proxy_user = '', $proxy_pass = '')
+-    {
+-        $this->path       = $path;
+-        $this->proxy_user = $proxy_user;
+-        $this->proxy_pass = $proxy_pass;
+-
+-        preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match);
+-        if ($match[1] == '') {
+-            if ($port == 443) {
+-                $this->server   = $match[2];
+-                $this->protocol = 'ssl://';
+-                $this->port     = 443;
+-            } else {
+-                $this->server = $match[2];
+-                if ($port) {
+-                    $this->port = $port;
+-                }
+-            }
+-        } elseif ($match[1] == 'http://') {
+-            $this->server = $match[2];
+-            if ($port) {
+-                $this->port = $port;
+-            }
+-        } else {
+-            $this->server   = $match[2];
+-            $this->protocol = 'ssl://';
+-            if ($port) {
+-                $this->port = $port;
+-            } else {
+-                $this->port = 443;
+-            }
+-        }
+-
+-        if ($proxy) {
+-            preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match);
+-            if ($match[1] == '') {
+-                if ($proxy_port == 443) {
+-                    $this->proxy          = $match[2];
+-                    $this->proxy_protocol = 'ssl://';
+-                    $this->proxy_port     = 443;
+-                } else {
+-                    $this->proxy = $match[2];
+-                    if ($proxy_port) {
+-                        $this->proxy_port = $proxy_port;
+-                    }
+-                }
+-            } elseif ($match[1] == 'http://') {
+-                $this->proxy = $match[2];
+-                if ($proxy_port) {
+-                    $this->proxy_port = $proxy_port;
+-                }
+-            } else {
+-                $this->proxy          = $match[2];
+-                $this->proxy_protocol = 'ssl://';
+-                if ($proxy_port) {
+-                    $this->proxy_port = $proxy_port;
+-                } else {
+-                    $this->proxy_port = 443;
+-                }
+-            }
+-        }
+-    }
+-
+-    /**
+-     * Change the current debug mode
+-     *
+-     * @param int $in  where 1 = on, 0 = off
+-     *
+-     * @return void
+-     */
+-    function setDebug($in)
+-    {
+-        if ($in) {
+-            $this->debug = 1;
+-        } else {
+-            $this->debug = 0;
+-        }
+-    }
+-
+-    /**
+-     * Set username and password properties for connecting to the RPC server
+-     *
+-     * @param string $u  the user name
+-     * @param string $p  the password
+-     *
+-     * @return void
+-     *
+-     * @see XML_RPC_Client::$username, XML_RPC_Client::$password
+-     */
+-    function setCredentials($u, $p)
+-    {
+-        $this->username = $u;
+-        $this->password = $p;
+-    }
+-
+-    /**
+-     * Transmit the RPC request via HTTP 1.0 protocol
+-     *
+-     * @param object $msg       the XML_RPC_Message object
+-     * @param int    $timeout   how many seconds to wait for the request
+-     *
+-     * @return object  an XML_RPC_Response object.  0 is returned if any
+-     *                  problems happen.
+-     *
+-     * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
+-     *      XML_RPC_Client::setCredentials()
+-     */
+-    function send($msg, $timeout = 0)
+-    {
+-        $msg->debug = $this->debug;
+-        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
+-                                        $timeout, $this->username,
+-                                        $this->password);
+-    }
+-
+-    /**
+-     * Transmit the RPC request via HTTP 1.0 protocol
+-     *
+-     * Requests should be sent using XML_RPC_Client send() rather than
+-     * calling this method directly.
+-     *
+-     * @param object $msg       the XML_RPC_Message object
+-     * @param string $server    the server to send the request to
+-     * @param int    $port      the server port send the request to
+-     * @param int    $timeout   how many seconds to wait for the request
+-     *                           before giving up
+-     * @param string $username  a user name for accessing the RPC server
+-     * @param string $password  a password for accessing the RPC server
+-     *
+-     * @return object  an XML_RPC_Response object.  0 is returned if any
+-     *                  problems happen.
+-     *
+-     * @see XML_RPC_Client::send()
+-     */
+-    function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
+-                               $username = '', $password = '')
+-    {
+-        /*
+-         * If we're using a proxy open a socket to the proxy server
+-         * instead to the xml-rpc server
+-         */
+-        if ($this->proxy) {
+-            if ($this->proxy_protocol == 'http://') {
+-                $protocol = '';
+-            } else {
+-                $protocol = $this->proxy_protocol;
+-            }
+-            if ($timeout > 0) {
+-                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
+-                                 $this->errno, $this->errstr, $timeout);
+-            } else {
+-                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
+-                                 $this->errno, $this->errstr);
+-            }
+-        } else {
+-            if ($this->protocol == 'http://') {
+-                $protocol = '';
+-            } else {
+-                $protocol = $this->protocol;
+-            }
+-            if ($timeout > 0) {
+-                $fp = @fsockopen($protocol . $server, $port,
+-                                 $this->errno, $this->errstr, $timeout);
+-            } else {
+-                $fp = @fsockopen($protocol . $server, $port,
+-                                 $this->errno, $this->errstr);
+-            }
+-        }
+-
+-        /*
+-         * Just raising the error without returning it is strange,
+-         * but keep it here for backwards compatibility.
+-         */
+-        if (!$fp && $this->proxy) {
+-            $this->raiseError('Connection to proxy server '
+-                              . $this->proxy . ':' . $this->proxy_port
+-                              . ' failed. ' . $this->errstr,
+-                              XML_RPC_ERROR_CONNECTION_FAILED);
+-            return 0;
+-        } elseif (!$fp) {
+-            $this->raiseError('Connection to RPC server '
+-                              . $server . ':' . $port
+-                              . ' failed. ' . $this->errstr,
+-                              XML_RPC_ERROR_CONNECTION_FAILED);
+-            return 0;
+-        }
+-
+-        // Only create the payload if it was not created previously
+-        if (empty($msg->payload)) {
+-            $msg->createPayload();
+-        }
+-
+-        // thanks to Grant Rauscher  for this
+-        $credentials = '';
+-        if ($username != '') {
+-            $credentials = 'Authorization: Basic ' .
+-                base64_encode($username . ':' . $password) . "\r\n";
+-        }
+-
+-        if ($this->proxy) {
+-            $op = 'POST ' . $this->protocol . $server;
+-            if ($this->proxy_port) {
+-                $op .= ':' . $this->port;
+-            }
+-        } else {
+-           $op = 'POST ';
+-        }
+-
+-        $op .= $this->path. " HTTP/1.0\r\n" .
+-               "User-Agent: PEAR XML_RPC\r\n" .
+-               'Host: ' . $server . "\r\n";
+-        if ($this->proxy && $this->proxy_user != '') {
+-            $op .= 'Proxy-Authorization: Basic ' .
+-                base64_encode($this->proxy_user . ':' . $this->proxy_pass) .
+-                "\r\n";
+-        }
+-        $op .= $credentials .
+-               "Content-Type: text/xml\r\n" .
+-               'Content-Length: ' . strlen($msg->payload) . "\r\n\r\n" .
+-               $msg->payload;
+-
+-        if (!fputs($fp, $op, strlen($op))) {
+-            $this->errstr = 'Write error';
+-            return 0;
+-        }
+-        $resp = $msg->parseResponseFile($fp);
+-        fclose($fp);
+-        return $resp;
+-    }
+-}
+-
+-/**
+- *
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Response extends XML_RPC_Base
+-{
+-    var $xv;
+-    var $fn;
+-    var $fs;
+-    var $hdrs;
+-
+-    /**
+-     * @return void
+-     */
+-    function XML_RPC_Response($val, $fcode = 0, $fstr = '')
+-    {
+-        if ($fcode != 0) {
+-            $this->fn = $fcode;
+-            $this->fs = htmlspecialchars($fstr);
+-        } else {
+-            $this->xv = $val;
+-        }
+-    }
+-
+-    /**
+-     * @return int  the error code
+-     */
+-    function faultCode()
+-    {
+-        if (isset($this->fn)) {
+-            return $this->fn;
+-        } else {
+-            return 0;
+-        }
+-    }
+-
+-    /**
+-     * @return string  the error string
+-     */
+-    function faultString()
+-    {
+-        return $this->fs;
+-    }
+-
+-    /**
+-     * @return mixed  the value
+-     */
+-    function value()
+-    {
+-        return $this->xv;
+-    }
+-
+-    /**
+-     * @return string  the error message in XML format
+-     */
+-    function serialize()
+-    {
+-        $rs = "\n";
+-        if ($this->fn) {
+-            $rs .= "
+-  
+-    
+-      
+-        faultCode
+-        " . $this->fn . "
+-      
+-      
+-        faultString
+-        " . $this->fs . "
+-      
+-    
+-  
+-";
+-        } else {
+-            $rs .= "\n\n" . $this->xv->serialize() .
+-        "\n";
+-        }
+-        $rs .= "\n";
+-        return $rs;
+-    }
+-}
+-
+-/**
+- *
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill
+- * @version    Release: 1.2.2
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Message extends XML_RPC_Base
+-{
+-    /**
+-     * The current debug mode (1 = on, 0 = off)
+-     * @var integer
+-     */
+-    var $debug = 0;
+-
+-    /**
+-     * The encoding to be used for outgoing messages
+-     *
+-     * Defaults to the value of $GLOBALS['XML_RPC_defencoding']
+-     *
+-     * @var string
+-     * @see XML_RPC_Message::setSendEncoding(),
+-     *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
+-     */
+-    var $send_encoding = '';
+-
+-    /**
+-     * The method presently being evaluated
+-     * @var string
+-     */
+-    var $methodname = '';
+-
+-    /**
+-     * @var array
+-     */
+-    var $params = array();
+-
+-    /**
+-     * The XML message being generated
+-     * @var string
+-     */
+-    var $payload = '';
+-
+-    /**
+-     * @return void
+-     */
+-    function XML_RPC_Message($meth, $pars = 0)
+-    {
+-        $this->methodname = $meth;
+-        if (is_array($pars) && sizeof($pars) > 0) {
+-            for ($i = 0; $i < sizeof($pars); $i++) {
+-                $this->addParam($pars[$i]);
+-            }
+-        }
+-    }
+-
+-    /**
+-     * Produces the XML declaration including the encoding attribute
+-     *
+-     * The encoding is determined by this class' $send_encoding
+-     * property.  If the $send_encoding property is not set, use
+-     * $GLOBALS['XML_RPC_defencoding'].
+-     *
+-     * @return string  the XML declaration and  element
+-     *
+-     * @see XML_RPC_Message::setSendEncoding(),
+-     *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
+-     */
+-    function xml_header()
+-    {
+-        global $XML_RPC_defencoding;
+-        if (!$this->send_encoding) {
+-            $this->send_encoding = $XML_RPC_defencoding;
+-        }
+-        return 'send_encoding . '"?>'
+-               . "\n\n";
+-    }
+-
+-    /**
+-     * @return string  the closing  tag
+-     */
+-    function xml_footer()
+-    {
+-        return "\n";
+-    }
+-
+-    /**
+-     * @return void
+-     *
+-     * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
+-     */
+-    function createPayload()
+-    {
+-        $this->payload = $this->xml_header();
+-        $this->payload .= '' . $this->methodname . "\n";
+-        $this->payload .= "\n";
+-        for ($i = 0; $i < sizeof($this->params); $i++) {
+-            $p = $this->params[$i];
+-            $this->payload .= "\n" . $p->serialize() . "\n";
+-        }
+-        $this->payload .= "\n";
+-        $this->payload .= $this->xml_footer();
+-        $this->payload = ereg_replace("[\r\n]+", "\r\n", $this->payload);
+-    }
+-
+-    /**
+-     * @return string  the name of the method
+-     */
+-    function method($meth = '')
+-    {
+-        if ($meth != '') {
+-            $this->methodname = $meth;
+-        }
+-        return $this->methodname;
+-    }
+-
+-    /**
+-     * @return string  the payload
+-     */
+-    function serialize()
+-    {
+-        $this->createPayload();
+-        return $this->payload;
+-    }
+-
+-    /**
+-     * @return void
+-     */
+-    function addParam($par)
+-    {
+-        $this->params[] = $par;
+-    }
+-
+-    /**
+-     * @return void
+-     */
+-    function getParam($i)
+-    {
+-        return $this->params[$i];
+-    }
+-
+-    /**
+-     * @return int  the number of parameters
+-     */
+-    function getNumParams()
+-    {
+-        return sizeof($this->params);
+-    }
+-
+-    /**
+-     * Sets the XML declaration's encoding attribute
+-     *
+-     * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
+-     *
+-     * @return void
+-     *
+-     * @see XML_RPC_Message::$send_encoding, XML_RPC_Message::xml_header()
+-     * @since Method available since Release 1.2.0
+-     */
+-    function setSendEncoding($type)
+-    {
+-        $this->send_encoding = $type;
+-    }
+-
+-    /**
+-     * Determine the XML's encoding via the encoding attribute
+-     * in the XML declaration
+-     *
+-     * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
+-     * or US-ASCII, $XML_RPC_defencoding will be returned.
+-     *
+-     * @param string $data  the XML that will be parsed
+-     *
+-     * @return string  the encoding to be used
+-     *
+-     * @link   http://php.net/xml_parser_create
+-     * @since  Method available since Release 1.2.0
+-     */
+-    function getEncoding($data)
+-    {
+-        global $XML_RPC_defencoding;
+-
+-        if (preg_match('/<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]/i',
+-                       $data, $match))
+-        {
+-            $match[1] = trim(strtoupper($match[1]));
+-            switch ($match[1]) {
+-                case 'ISO-8859-1':
+-                case 'UTF-8':
+-                case 'US-ASCII':
+-                    return $match[1];
+-                    break;
+-
+-                default:
+-                    return $XML_RPC_defencoding;
+-            }
+-        } else {
+-            return $XML_RPC_defencoding;
+-        }
+-    }
+-
+-    /**
+-     * @return object  a new XML_RPC_Response object
+-     */
+-    function parseResponseFile($fp)
+-    {
+-        $ipd = '';
+-        while ($data = @fread($fp, 8192)) {
+-            $ipd .= $data;
+-        }
+-        return $this->parseResponse($ipd);
+-    }
+-
+-    /**
+-     * @return object  a new XML_RPC_Response object
+-     */
+-    function parseResponse($data = '')
+-    {
+-        global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
+-
+-        $encoding = $this->getEncoding($data);
+-        $parser = xml_parser_create($encoding);
+-
+-        $XML_RPC_xh[$parser] = array();
+-
+-        $XML_RPC_xh[$parser]['st'] = '';
+-        $XML_RPC_xh[$parser]['cm'] = 0;
+-        $XML_RPC_xh[$parser]['isf'] = 0;
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = '';
+-
+-        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true);
+-        xml_set_element_handler($parser, 'XML_RPC_se', 'XML_RPC_ee');
+-        xml_set_character_data_handler($parser, 'XML_RPC_cd');
+-
+-        $hdrfnd = 0;
+-        if ($this->debug) {
+-            print "
---GOT---\n";
+-            print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
+-            print "\n---END---\n
"; +- } +- +- // see if we got an HTTP 200 OK, else bomb +- // but only do this if we're using the HTTP protocol. +- if (ereg('^HTTP', $data) && +- !ereg('^HTTP/[0-9\.]+ 200 ', $data)) { +- $errstr = substr($data, 0, strpos($data, "\n") - 1); +- error_log('HTTP error, got response: ' . $errstr); +- $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], +- $XML_RPC_str['http_error'] . ' (' . +- $errstr . ')'); +- xml_parser_free($parser); +- return $r; +- } +- // gotta get rid of headers here +- +- +- if ((!$hdrfnd) && ($brpos = strpos($data,"\r\n\r\n"))) { +- $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos); +- $data = substr($data, $brpos + 4); +- $hdrfnd = 1; +- } +- +- /* +- * be tolerant of junk after methodResponse +- * (e.g. javascript automatically inserted by free hosts) +- * thanks to Luca Mariano +- */ +- $data = substr($data, 0, strpos($data, "") + 17); +- +- if (!xml_parse($parser, $data, sizeof($data))) { +- // thanks to Peter Kocks +- if ((xml_get_current_line_number($parser)) == 1) { +- $errstr = 'XML error at line 1, check URL'; +- } else { +- $errstr = sprintf('XML error: %s at line %d', +- xml_error_string(xml_get_error_code($parser)), +- xml_get_current_line_number($parser)); +- } +- error_log($errstr); +- $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], +- $XML_RPC_str['invalid_return']); +- xml_parser_free($parser); +- return $r; +- } +- xml_parser_free($parser); +- if ($this->debug) { +- print '
---EVALING---[' .
+-            strlen($XML_RPC_xh[$parser]['st']) . " chars]---\n" .
+-            htmlspecialchars($XML_RPC_xh[$parser]['st']) . ";\n---END---
"; +- } +- if (strlen($XML_RPC_xh[$parser]['st']) == 0) { +- // then something odd has happened +- // and it's time to generate a client side error +- // indicating something odd went on +- $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], +- $XML_RPC_str['invalid_return']); +- } else { +- eval('$v=' . $XML_RPC_xh[$parser]['st'] . '; $allOK=1;'); +- if ($XML_RPC_xh[$parser]['isf']) { +- $f = $v->structmem('faultCode'); +- $fs = $v->structmem('faultString'); +- $r = new XML_RPC_Response($v, $f->scalarval(), +- $fs->scalarval()); +- } else { +- $r = new XML_RPC_Response($v); +- } +- } +- $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]); +- return $r; +- } +-} +- +-/** +- * +- * +- * @category Web Services +- * @package XML_RPC +- * @author Edd Dumbill +- * @author Stig Bakken +- * @author Martin Jansen +- * @copyright 1999-2001 Edd Dumbill +- * @version Release: 1.2.2 +- * @link http://pear.php.net/package/XML_RPC +- */ +-class XML_RPC_Value extends XML_RPC_Base +-{ +- var $me = array(); +- var $mytype = 0; +- +- /** +- * @return void +- */ +- function XML_RPC_Value($val = -1, $type = '') +- { +- global $XML_RPC_Types; +- $this->me = array(); +- $this->mytype = 0; +- if ($val != -1 || $type != '') { +- if ($type == '') { +- $type = 'string'; +- } +- if (!array_key_exists($type, $XML_RPC_Types)) { +- // XXX +- // need some way to report this error +- } elseif ($XML_RPC_Types[$type] == 1) { +- $this->addScalar($val, $type); +- } elseif ($XML_RPC_Types[$type] == 2) { +- $this->addArray($val); +- } elseif ($XML_RPC_Types[$type] == 3) { +- $this->addStruct($val); +- } +- } +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addScalar($val, $type = 'string') +- { +- global $XML_RPC_Types, $XML_RPC_Boolean; +- +- if ($this->mytype == 1) { +- $this->raiseError('Scalar can have only one value', +- XML_RPC_ERROR_INVALID_TYPE); +- return 0; +- } +- $typeof = $XML_RPC_Types[$type]; +- if ($typeof != 1) { +- $this->raiseError("Not a scalar type (${typeof})", +- XML_RPC_ERROR_INVALID_TYPE); +- return 0; +- } +- +- if ($type == $XML_RPC_Boolean) { +- if (strcasecmp($val, 'true') == 0 +- || $val == 1 +- || ($val == true && strcasecmp($val, 'false'))) +- { +- $val = 1; +- } else { +- $val = 0; +- } +- } +- +- if ($this->mytype == 2) { +- // we're adding to an array here +- $ar = $this->me['array']; +- $ar[] = new XML_RPC_Value($val, $type); +- $this->me['array'] = $ar; +- } else { +- // a scalar, so set the value and remember we're scalar +- $this->me[$type] = $val; +- $this->mytype = $typeof; +- } +- return 1; +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addArray($vals) +- { +- global $XML_RPC_Types; +- if ($this->mytype != 0) { +- $this->raiseError( +- 'Already initialized as a [' . $this->kindOf() . ']', +- XML_RPC_ERROR_ALREADY_INITIALIZED); +- return 0; +- } +- $this->mytype = $XML_RPC_Types['array']; +- $this->me['array'] = $vals; +- return 1; +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addStruct($vals) +- { +- global $XML_RPC_Types; +- if ($this->mytype != 0) { +- $this->raiseError( +- 'Already initialized as a [' . $this->kindOf() . ']', +- XML_RPC_ERROR_ALREADY_INITIALIZED); +- return 0; +- } +- $this->mytype = $XML_RPC_Types['struct']; +- $this->me['struct'] = $vals; +- return 1; +- } +- +- /** +- * @return void +- */ +- function dump($ar) +- { +- reset($ar); +- while (list($key, $val) = each($ar)) { +- echo "$key => $val
"; +- if ($key == 'array') { +- while (list($key2, $val2) = each($val)) { +- echo "-- $key2 => $val2
"; +- } +- } +- } +- } +- +- /** +- * @return string the data type of the current value +- */ +- function kindOf() +- { +- switch ($this->mytype) { +- case 3: +- return 'struct'; +- +- case 2: +- return 'array'; +- +- case 1: +- return 'scalar'; +- +- default: +- return 'undef'; +- } +- } +- +- /** +- * @return string the data in XML format +- */ +- function serializedata($typ, $val) +- { +- $rs = ''; +- global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean; +- if (!array_key_exists($typ, $XML_RPC_Types)) { +- // XXX +- // need some way to report this error +- return; +- } +- switch ($XML_RPC_Types[$typ]) { +- case 3: +- // struct +- $rs .= "\n"; +- reset($val); +- while (list($key2, $val2) = each($val)) { +- $rs .= "${key2}\n"; +- $rs .= $this->serializeval($val2); +- $rs .= "\n"; +- } +- $rs .= ''; +- break; +- +- case 2: +- // array +- $rs .= "\n\n"; +- for ($i = 0; $i < sizeof($val); $i++) { +- $rs .= $this->serializeval($val[$i]); +- } +- $rs .= "\n"; +- break; +- +- case 1: +- switch ($typ) { +- case $XML_RPC_Base64: +- $rs .= "<${typ}>" . base64_encode($val) . ""; +- break; +- case $XML_RPC_Boolean: +- $rs .= "<${typ}>" . ($val ? '1' : '0') . ""; +- break; +- case $XML_RPC_String: +- $rs .= "<${typ}>" . htmlspecialchars($val). ""; +- break; +- default: +- $rs .= "<${typ}>${val}"; +- } +- } +- return $rs; +- } +- +- /** +- * @return string the data in XML format +- */ +- function serialize() +- { +- return $this->serializeval($this); +- } +- +- /** +- * @return string the data in XML format +- */ +- function serializeval($o) +- { +- $rs = ''; +- $ar = $o->me; +- reset($ar); +- list($typ, $val) = each($ar); +- $rs .= ''; +- $rs .= $this->serializedata($typ, $val); +- $rs .= "\n"; +- return $rs; +- } +- +- /** +- * @return mixed the contents of the element requested +- */ +- function structmem($m) +- { +- return $this->me['struct'][$m]; +- } +- +- /** +- * @return void +- */ +- function structreset() +- { +- reset($this->me['struct']); +- } +- +- /** +- * @return the key/value pair of the struct's current element +- */ +- function structeach() +- { +- return each($this->me['struct']); +- } +- +- /** +- * @return mixed the current value +- */ +- function getval() { +- // UNSTABLE +- global $XML_RPC_BOOLEAN, $XML_RPC_Base64; +- +- reset($this->me); +- list($a, $b) = each($this->me); +- +- // contributed by I Sofer, 2001-03-24 +- // add support for nested arrays to scalarval +- // i've created a new method here, so as to +- // preserve back compatibility +- +- if (is_array($b)) { +- foreach ($b as $id => $cont) { +- $b[$id] = $cont->scalarval(); +- } +- } +- +- // add support for structures directly encoding php objects +- if (is_object($b)) { +- $t = get_object_vars($b); +- foreach ($t as $id => $cont) { +- $t[$id] = $cont->scalarval(); +- } +- foreach ($t as $id => $cont) { +- eval('$b->'.$id.' = $cont;'); +- } +- } +- +- // end contrib +- return $b; +- } +- +- /** +- * @return mixed +- */ +- function scalarval() +- { +- global $XML_RPC_Boolean, $XML_RPC_Base64; +- reset($this->me); +- list($a, $b) = each($this->me); +- return $b; +- } +- +- /** +- * @return string +- */ +- function scalartyp() +- { +- global $XML_RPC_I4, $XML_RPC_Int; +- reset($this->me); +- list($a, $b) = each($this->me); +- if ($a == $XML_RPC_I4) { +- $a = $XML_RPC_Int; +- } +- return $a; +- } +- +- /** +- * @return mixed the struct's current element +- */ +- function arraymem($m) +- { +- return $this->me['array'][$m]; +- } +- +- /** +- * @return int the number of elements in the array +- */ +- function arraysize() +- { +- reset($this->me); +- list($a, $b) = each($this->me); +- return sizeof($b); +- } +-} +- +-/** +- * Return an ISO8601 encoded string +- * +- * While timezones ought to be supported, the XML-RPC spec says: +- * +- * "Don't assume a timezone. It should be specified by the server in its +- * documentation what assumptions it makes about timezones." +- * +- * This routine always assumes localtime unless $utc is set to 1, in which +- * case UTC is assumed and an adjustment for locale is made when encoding. +- * +- * @return string the formatted date +- */ +-function XML_RPC_iso8601_encode($timet, $utc = 0) { +- if (!$utc) { +- $t = strftime('%Y%m%dT%H:%M:%S', $timet); +- } else { +- if (function_exists('gmstrftime')) { +- // gmstrftime doesn't exist in some versions +- // of PHP +- $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); +- } else { +- $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); +- } +- } +- return $t; +-} +- +-/** +- * Convert a datetime string into a Unix timestamp +- * +- * While timezones ought to be supported, the XML-RPC spec says: +- * +- * "Don't assume a timezone. It should be specified by the server in its +- * documentation what assumptions it makes about timezones." +- * +- * This routine always assumes localtime unless $utc is set to 1, in which +- * case UTC is assumed and an adjustment for locale is made when encoding. +- * +- * @return int the unix timestamp of the date submitted +- */ +-function XML_RPC_iso8601_decode($idate, $utc = 0) { +- $t = 0; +- if (ereg('([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})', $idate, $regs)) { +- if ($utc) { +- $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +- } else { +- $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +- } +- } +- return $t; +-} +- +-/** +- * Takes a message in PHP XML_RPC object format and translates it into +- * native PHP types +- * +- * @return mixed +- * +- * @author Dan Libby +- */ +-function XML_RPC_decode($XML_RPC_val) +-{ +- $kind = $XML_RPC_val->kindOf(); +- +- if ($kind == 'scalar') { +- return $XML_RPC_val->scalarval(); +- +- } elseif ($kind == 'array') { +- $size = $XML_RPC_val->arraysize(); +- $arr = array(); +- for ($i = 0; $i < $size; $i++) { +- $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i)); +- } +- return $arr; +- +- } elseif ($kind == 'struct') { +- $XML_RPC_val->structreset(); +- $arr = array(); +- while (list($key, $value) = $XML_RPC_val->structeach()) { +- $arr[$key] = XML_RPC_decode($value); +- } +- return $arr; +- } +-} +- +-/** +- * Takes native php types and encodes them into XML_RPC PHP object format +- * +- * Feature creep -- could support more types via optional type argument. +- * +- * @return string +- * +- * @author Dan Libby +- */ +-function XML_RPC_encode($php_val) { +- global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double, $XML_RPC_String, +- $XML_RPC_Array, $XML_RPC_Struct; +- +- $type = gettype($php_val); +- $XML_RPC_val = new XML_RPC_Value; +- +- switch ($type) { +- case 'array': +- if (empty($php_val)) { +- $XML_RPC_val->addArray($php_val); +- break; +- } +- $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); +- if (empty($tmp)) { +- $arr = array(); +- foreach ($php_val as $k => $v) { +- $arr[$k] = XML_RPC_encode($v); +- } +- $XML_RPC_val->addArray($arr); +- break; +- } +- // fall though if it's not an enumerated array +- +- case 'object': +- $arr = array(); +- foreach ($php_val as $k => $v) { +- $arr[$k] = XML_RPC_encode($v); +- } +- $XML_RPC_val->addStruct($arr); +- break; +- +- case 'integer': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Int); +- break; +- +- case 'double': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Double); +- break; +- +- case 'string': +- case 'NULL': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_String); +- break; +- +- case 'boolean': +- // Add support for encoding/decoding of booleans, since they +- // are supported in PHP +- // by +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean); +- break; +- +- case 'unknown type': +- default: +- $XML_RPC_val = false; +- } +- return $XML_RPC_val; +-} +- +-/* +- * Local variables: +- * tab-width: 4 +- * c-basic-offset: 4 +- * c-hanging-comment-ender-p: nil +- * End: +- */ +- +-?> +-XML_RPC-1.2.2/Server.php100666 0 0 36235 10213112551 7713 +- * @author Stig Bakken +- * @author Martin Jansen +- * @copyright 1999-2001 Edd Dumbill +- * @version CVS: $Id: Server.php,v 1.17 2005/03/01 17:09:49 danielc Exp $ +- * @link http://pear.php.net/package/XML_RPC +- */ +- +- +-/** +- * Pull in the XML_RPC class +- */ +-require_once 'XML/RPC.php'; +- +- +-/** +- * listMethods: either a string, or nothing +- * @global array $GLOBALS['XML_RPC_Server_listMethods_sig'] +- */ +-$GLOBALS['XML_RPC_Server_listMethods_sig'] = array( +- array($GLOBALS['XML_RPC_Array'], +- $GLOBALS['XML_RPC_String'] +- ), +- array($GLOBALS['XML_RPC_Array']) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_listMethods_doc'] +- */ +-$GLOBALS['XML_RPC_Server_listMethods_doc'] = 'This method lists all the' +- . ' methods that the XML-RPC server knows how to dispatch'; +- +-/** +- * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig'] +- */ +-$GLOBALS['XML_RPC_Server_methodSignature_sig'] = array( +- array($GLOBALS['XML_RPC_Array'], +- $GLOBALS['XML_RPC_String'] +- ) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc'] +- */ +-$GLOBALS['XML_RPC_Server_methodSignature_doc'] = 'Returns an array of known' +- . ' signatures (an array of arrays) for the method name passed. If' +- . ' no signatures are known, returns a none-array (test for type !=' +- . ' array to detect missing signature)'; +- +-/** +- * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig'] +- */ +-$GLOBALS['XML_RPC_Server_methodHelp_sig'] = array( +- array($GLOBALS['XML_RPC_String'], +- $GLOBALS['XML_RPC_String'] +- ) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc'] +- */ +-$GLOBALS['XML_RPC_Server_methodHelp_doc'] = 'Returns help text if defined' +- . ' for the method passed, otherwise returns an empty string'; +- +-/** +- * @global array $GLOBALS['XML_RPC_Server_dmap'] +- */ +-$GLOBALS['XML_RPC_Server_dmap'] = array( +- 'system.listMethods' => array( +- 'function' => 'XML_RPC_Server_listMethods', +- 'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc'] +- ), +- 'system.methodHelp' => array( +- 'function' => 'XML_RPC_Server_methodHelp', +- 'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc'] +- ), +- 'system.methodSignature' => array( +- 'function' => 'XML_RPC_Server_methodSignature', +- 'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc'] +- ) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_debuginfo'] +- */ +-$GLOBALS['XML_RPC_Server_debuginfo'] = ''; +- +- +-/** +- * Lists all the methods that the XML-RPC server knows how to dispatch +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_listMethods($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $v = new XML_RPC_Value(); +- $dmap = $server->dmap; +- $outAr = array(); +- for (reset($dmap); list($key, $val) = each($dmap); ) { +- $outAr[] = new XML_RPC_Value($key, 'string'); +- } +- $dmap = $XML_RPC_Server_dmap; +- for (reset($dmap); list($key, $val) = each($dmap); ) { +- $outAr[] = new XML_RPC_Value($key, 'string'); +- } +- $v->addArray($outAr); +- return new XML_RPC_Response($v); +-} +- +-/** +- * Returns an array of known signatures (an array of arrays) +- * for the given method +- * +- * If no signatures are known, returns a none-array +- * (test for type != array to detect missing signature) +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_methodSignature($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $methName = $m->getParam(0); +- $methName = $methName->scalarval(); +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $server->dmap; +- $sysCall = 0; +- } +- // print "\n"; +- if (isset($dmap[$methName])) { +- if ($dmap[$methName]['signature']) { +- $sigs = array(); +- $thesigs = $dmap[$methName]['signature']; +- for ($i = 0; $i < sizeof($thesigs); $i++) { +- $cursig = array(); +- $inSig = $thesigs[$i]; +- for ($j = 0; $j < sizeof($inSig); $j++) { +- $cursig[] = new XML_RPC_Value($inSig[$j], 'string'); +- } +- $sigs[] = new XML_RPC_Value($cursig, 'array'); +- } +- $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array')); +- } else { +- $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string')); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], +- $XML_RPC_str['introspect_unknown']); +- } +- return $r; +-} +- +-/** +- * Returns help text if defined for the method passed, otherwise returns +- * an empty string +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_methodHelp($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $methName = $m->getParam(0); +- $methName = $methName->scalarval(); +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $server->dmap; +- $sysCall = 0; +- } +- // print "\n"; +- if (isset($dmap[$methName])) { +- if ($dmap[$methName]['docstring']) { +- $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']), +- 'string'); +- } else { +- $r = new XML_RPC_Response(new XML_RPC_Value('', 'string')); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], +- $XML_RPC_str['introspect_unknown']); +- } +- return $r; +-} +- +-/** +- * @return void +- */ +-function XML_RPC_Server_debugmsg($m) +-{ +- global $XML_RPC_Server_debuginfo; +- $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n"; +-} +- +- +-/** +- * +- * +- * @category Web Services +- * @package XML_RPC +- * @author Edd Dumbill +- * @author Stig Bakken +- * @author Martin Jansen +- * @copyright 1999-2001 Edd Dumbill +- * @version Release: 1.2.2 +- * @link http://pear.php.net/package/XML_RPC +- */ +-class XML_RPC_Server +-{ +- var $dmap = array(); +- var $encoding = ''; +- var $debug = 0; +- +- /** +- * @return void +- */ +- function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) +- { +- global $HTTP_RAW_POST_DATA; +- +- if ($debug) { +- $this->debug = 1; +- } else { +- $this->debug = 0; +- } +- +- // dispMap is a despatch array of methods +- // mapped to function names and signatures +- // if a method +- // doesn't appear in the map then an unknown +- // method error is generated +- $this->dmap = $dispMap; +- if ($serviceNow) { +- $this->service(); +- } +- } +- +- /** +- * @return string the debug information if debug debug mode is on +- */ +- function serializeDebug() +- { +- global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA; +- +- if ($this->debug) { +- XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n" +- . $HTTP_RAW_POST_DATA +- . "\n" . '^^^ END POST DATA ^^^'); +- } +- +- if ($XML_RPC_Server_debuginfo != '') { +- return "\n"; +- } else { +- return ''; +- } +- } +- +- /** +- * Print out the result +- * +- * The encoding and content-type are determined by +- * XML_RPC_Message::getEncoding() +- * +- * @return void +- * +- * @see XML_RPC_Message::getEncoding() +- */ +- function service() +- { +- $r = $this->parseRequest(); +- $payload = 'encoding . '"?>' . "\n" +- . $this->serializeDebug() +- . $r->serialize(); +- header('Content-Length: ' . strlen($payload)); +- header('Content-Type: text/xml; charset=' . $this->encoding); +- print $payload; +- } +- +- /** +- * @return array +- */ +- function verifySignature($in, $sig) +- { +- for ($i = 0; $i < sizeof($sig); $i++) { +- // check each possible signature in turn +- $cursig = $sig[$i]; +- if (sizeof($cursig) == $in->getNumParams() + 1) { +- $itsOK = 1; +- for ($n = 0; $n < $in->getNumParams(); $n++) { +- $p = $in->getParam($n); +- // print "\n"; +- if ($p->kindOf() == 'scalar') { +- $pt = $p->scalartyp(); +- } else { +- $pt = $p->kindOf(); +- } +- // $n+1 as first type of sig is return type +- if ($pt != $cursig[$n+1]) { +- $itsOK = 0; +- $pno = $n+1; +- $wanted = $cursig[$n+1]; +- $got = $pt; +- break; +- } +- } +- if ($itsOK) { +- return array(1); +- } +- } +- } +- return array(0, "Wanted ${wanted}, got ${got} at param ${pno})"); +- } +- +- /** +- * @return object a new XML_RPC_Response object +- */ +- function parseRequest($data = '') +- { +- global $XML_RPC_xh, $HTTP_RAW_POST_DATA, +- $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml, +- $XML_RPC_defencoding, $XML_RPC_Server_dmap; +- +- if ($data == '') { +- $data = $HTTP_RAW_POST_DATA; +- } +- +- $this->encoding = XML_RPC_Message::getEncoding($data); +- $parser = xml_parser_create($this->encoding); +- +- $XML_RPC_xh[$parser] = array(); +- $XML_RPC_xh[$parser]['st'] = ''; +- $XML_RPC_xh[$parser]['cm'] = 0; +- $XML_RPC_xh[$parser]['isf'] = 0; +- $XML_RPC_xh[$parser]['params'] = array(); +- $XML_RPC_xh[$parser]['method'] = ''; +- +- $plist = ''; +- +- // decompose incoming XML into request structure +- +- xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, true); +- xml_set_element_handler($parser, 'XML_RPC_se', 'XML_RPC_ee'); +- xml_set_character_data_handler($parser, 'XML_RPC_cd'); +- if (!xml_parse($parser, $data, 1)) { +- // return XML error as a faultCode +- $r = new XML_RPC_Response(0, +- $XML_RPC_errxml+xml_get_error_code($parser), +- sprintf('XML error: %s at line %d', +- xml_error_string(xml_get_error_code($parser)), +- xml_get_current_line_number($parser))); +- xml_parser_free($parser); +- } else { +- xml_parser_free($parser); +- $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']); +- // now add parameters in +- for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) { +- // print '\n"; +- $plist .= "$i - " . $XML_RPC_xh[$parser]['params'][$i] . " \n"; +- eval('$m->addParam(' . $XML_RPC_xh[$parser]['params'][$i] . ');'); +- } +- XML_RPC_Server_debugmsg($plist); +- +- // now to deal with the method +- $methName = $XML_RPC_xh[$parser]['method']; +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $this->dmap; +- $sysCall = 0; +- } +- +- if (isset($dmap[$methName]['function']) +- && is_string($dmap[$methName]['function']) +- && strpos($dmap[$methName]['function'], '::') !== false) +- { +- $dmap[$methName]['function'] = +- explode('::', $dmap[$methName]['function']); +- } +- +- if (isset($dmap[$methName]['function']) +- && is_callable($dmap[$methName]['function'])) +- { +- // dispatch if exists +- if (isset($dmap[$methName]['signature'])) { +- $sr = $this->verifySignature($m, +- $dmap[$methName]['signature'] ); +- } +- if ( (!isset($dmap[$methName]['signature'])) || $sr[0]) { +- // if no signature or correct signature +- if ($sysCall) { +- $r = call_user_func($dmap[$methName]['function'], $this, $m); +- } else { +- $r = call_user_func($dmap[$methName]['function'], $m); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], +- $XML_RPC_str['incorrect_params'] +- . ': ' . $sr[1]); +- } +- } else { +- // else prepare error response +- $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'], +- $XML_RPC_str['unknown_method']); +- } +- } +- return $r; +- } +- +- /** +- * Echos back the input packet as a string value +- * +- * @return void +- * +- * Useful for debugging. +- */ +- function echoInput() { +- global $HTTP_RAW_POST_DATA; +- +- $r = new XML_RPC_Response(0); +- $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); +- print $r->serialize(); +- } +-} +- +-/* +- * Local variables: +- * tab-width: 4 +- * c-basic-offset: 4 +- * c-hanging-comment-ender-p: nil +- * End: +- */ +- +-?> +-package.xml100666 0 0 15556 10213112551 6252 +- +- +- XML_RPC +- PHP implementation of the XML-RPC protocol +- A PEAR-ified version of Useful Inc's XML-RPC for PHP. +- +-It has support for HTTP/HTTPS transport, proxies and authentication. +- +- +- +- ssb +- Stig Bakken +- stig@php.net +- lead +- +- +- danielc +- Daniel Convissor +- danielc@php.net +- lead +- +- +- +- 1.2.2 +- 2005-03-07 +- PHP License +- stable +- * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- 1.2.1 +- 2005-03-01 +- stable +- * Add isset() check before examining the dispatch map. Bug 3658. +- +- +- +- 1.2.0 +- 2005-02-27 +- stable +- * Provide the "stable" release. +-* Add package2.xml for compatibility with PEAR 1.4.0. +-* For changes since 1.1.0, see the changelogs for the various RC releases. +- +- +- +- 1.2.0RC7 +- 2005-02-22 +- beta +- * Add the setSendEncoding() method and $send_encoding +- property to XML_RPC_Message. Request 3537. +-* Allow class methods to be mapped using either syntax: +- 'function' => 'hello::sayHello', +- or +- 'function' => array('hello', 'sayhello'), +- Bug 3363. +-* Use 8192 instead of 32768 for bytes in fread() +- in parseResponseFile(). Bug 3340. +- +- +- +- 1.2.0RC6 +- 2005-01-25 +- beta +- * Don't put the protocol in the Host field of the POST data. (danielc) +- +- +- +- 1.2.0RC5 +- 2005-01-24 +- beta +- * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. +- +- +- +- 1.2.0RC4 +- 2005-01-24 +- beta +- * When a connection attempt fails, have the method return 0. (danielc) +-* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) +-* Add tests for setting the client properties. (danielc) +-* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) +-* Bundle the tests with the package. (danielc) +- +- +- +- 1.2.0RC3 +- 2005-01-19 +- beta +- * ssl uses port 443, not 445. +- +- +- +- 1.2.0RC2 +- 2005-01-11 +- beta +- * Handle ssl:// in the $server string. (danielc) +-* Also default to port 445 for ssl:// requests as well. (danielc) +-* Enhance debugging in the server. (danielc) +- +- +- +- 1.2.0RC1 +- 2004-12-30 +- beta +- * Make things work with SSL. Bug 2489. (nkukard lbsd net) +-* Allow array function callbacks (Matt Kane) +-* Some minor speed-ups (Matt Kane) +-* Add Dump.php to the package (Christian Weiske) +-* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) +-* Silence fsockopen() errors. Bug 1714. (danielc) +-* Encode empty arrays as an array. Bug 1493. (danielc) +-* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) +-* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) +-* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) +-* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) +-* Allow raiseError() to be called statically. (danielc) +-* Stop double escaping of character entities. Bug 987. (danielc) +- NOTICE: the following have been removed: +- * XML_RPC_dh() +- * $GLOBALS['XML_RPC_entities'] +- * XML_RPC_entity_decode() +- * XML_RPC_lookup_entity() +-* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) +- +- +- +- 1.1.0 +- 2004-03-15 +- stable +- * Added support for sequential arrays to XML_RPC_encode() (mroch) +-* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) +-* Remove "require_once 'PEAR.php'", include only when needed to raise an error +-* Replace echo and error_log() with raiseError() (mroch) +-* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) +-* be tolerant of junk after methodResponse (Luca Mariano, mroch) +-* Silent notice even in the error log (pierre) +-* fix include of shared xml extension on win32 (pierre) +- +- +- +- 1.0.4 +- 2002-10-02 +- stable +- * added HTTP proxy authorization support (thanks to Arnaud Limbourg) +- +- +- +- 1.0.3 +- 2002-05-19 +- stable +- * fix bug when parsing responses with boolean types +- +- +- +- 1.0.2 +- 2002-04-16 +- stable +- * E_ALL fixes +-* fix HTTP response header parsing +- +- +- +- 1.0.1 +- 2001-09-25 +- stable +- This is a PEAR-ified version of Useful Inc's 1.0.1 release. +-Includes an urgent security fix identified by Dan Libby <dan@libby.com>. +- +- +- +- +- +\ Kein Zeilenumbruch am Dateiende. +diff -Nura php-4.3.11/pear/packages/XML_RPC-1.4.0.tar hardening-patch-4.3.11-0.4.2/pear/packages/XML_RPC-1.4.0.tar +--- php-4.3.11/pear/packages/XML_RPC-1.4.0.tar 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/pear/packages/XML_RPC-1.4.0.tar 2005-09-07 19:04:56.246906192 +0200 +@@ -0,0 +1,3933 @@ ++package2.xml100666 0 0 37144 10277724746 6362 ++ ++ XML_RPC ++ pear.php.net ++ PHP implementation of the XML-RPC protocol ++ A PEAR-ified version of Useful Inc's XML-RPC for PHP. ++ ++It has support for HTTP/HTTPS transport, proxies and authentication. ++ ++ Stig Bakken ++ ssb ++ stig@php.net ++ no ++ ++ ++ Daniel Convissor ++ danielc ++ danielc@php.net ++ yes ++ ++ 2005-08-14 ++ ++ ++ 1.4.0 ++ 1.4.0 ++ ++ ++ stable ++ stable ++ ++ PHP License ++ * MAJOR SECURITY FIX: eliminate use of eval(). ++* Using socket_get_status() because stream_get_meta_data() was introduced in 4.3.0, but we need to support 4.2.0. Bug 4805. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ PEAR ++ pear.php.net ++ 1.4.0a1 ++ 1.4.0a12 ++ ++ ++ ++ ++ 4.2.0 ++ 6.0.0 ++ ++ ++ 1.4.0a1 ++ ++ ++ ++ ++ ++ ++ ++ 1.3.3 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ 2005-07-15 ++ PHP License ++ * Eliminate memory leak by resetting $XML_RPC_xh each time parseResponse() is called. Bug 4780. ++* Using socket_set_timeout() because stream_set_timeout() was introduced in 4.3.0, but we need to support 4.2.0. Bug 4805. ++ ++ ++ ++ 1.3.2 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ 2005-07-07 ++ PHP License ++ * Eliminate path disclosure vulnerabilities by suppressing error messages when eval()'ing. ++* Eliminate path disclosure vulnerability by catching bogus parameters submitted to XML_RPC_Value::serializeval(). ++* In XML_RPC_Server::service(), only call createServerPayload() and createServerHeaders() if necessary. Fixes compatibility issue introduced in Release 1.3.0RC1 for users who set the $serviceNow parameter of XML_RPC_Server() to 0. Bug 4757. ++* Change "var $errstring" to "var $errstr". Bug 4582. Was put into CVS version 1.75 of RPC.php but didn't make it into RELEASE_1_3_1. ++ ++ ++ ++ 1.3.1 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ 2005-06-29 ++ PHP License ++ * Security fix. Update highly recommended! ++ ++ ++ ++ 1.3.0 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ 2005-06-13 ++ PHP License ++ * Stable release. See earlier releases for changes since 1.2.2. ++ ++ ++ ++ 1.3.0RC3 ++ 1.3.0 ++ ++ ++ beta ++ stable ++ ++ 2005-05-10 ++ PHP License ++ * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. ++* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. ++* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. ++* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. ++* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). ++* Use <br /> instead of <br> in XML_RPC_Value::dump(). ++ ++ ++ ++ 1.3.0RC2 ++ 1.3.0 ++ ++ ++ beta ++ beta ++ ++ 2005-05-05 ++ PHP License ++ * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. ++* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. ++* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. ++* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. ++ ++ ++ ++ 1.3.0RC1 ++ 1.3.0 ++ ++ ++ beta ++ beta ++ ++ 2005-04-07 ++ PHP License ++ * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. ++* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. ++* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. ++* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. ++* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. ++* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. ++ ++ ++ ++ 1.2.2 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-03-07 ++ PHP License ++ * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. ++ ++ ++ ++ 1.2.1 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-03-01 ++ PHP License ++ * Add isset() check before examining the dispatch map. Bug 3658. ++ ++ ++ ++ 1.2.0 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-02-27 ++ PHP License ++ * Provide the "stable" release. ++* Add package2.xml for compatibility with PEAR 1.4.0. ++* For changes since 1.1.0, see the changelogs for the various RC releases. ++ ++ ++ ++ 1.2.0RC7 ++ 1.2.0RC7 ++ ++ ++ beta ++ beta ++ ++ 2005-02-22 ++ PHP License ++ * Add the setSendEncoding() method and $send_encoding ++ property to XML_RPC_Message. Request 3537. ++* Allow class methods to be mapped using either syntax: ++ 'function' => 'hello::sayHello', ++ or ++ 'function' => array('hello', 'sayhello'), ++ Bug 3363. ++* Use 8192 instead of 32768 for bytes in fread() ++ in parseResponseFile(). Bug 3340. ++ ++ ++ ++ 1.2.0RC6 ++ 1.2.0RC6 ++ ++ ++ beta ++ beta ++ ++ 2005-01-25 ++ PHP License ++ * Don't put the protocol in the Host field of the POST data. (danielc) ++ ++ ++ ++ 1.2.0RC5 ++ 1.2.0RC5 ++ ++ ++ beta ++ beta ++ ++ 2005-01-24 ++ PHP License ++ * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. ++ ++ ++ ++ 1.2.0RC4 ++ 1.2.0RC4 ++ ++ ++ beta ++ beta ++ ++ 2005-01-24 ++ PHP License ++ * When a connection attempt fails, have the method return 0. (danielc) ++* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) ++* Add tests for setting the client properties. (danielc) ++* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) ++* Bundle the tests with the package. (danielc) ++ ++ ++ ++ 1.2.0RC3 ++ 1.2.0RC3 ++ ++ ++ beta ++ beta ++ ++ 2005-01-19 ++ PHP License ++ * ssl uses port 443, not 445. ++ ++ ++ ++ 1.2.0RC2 ++ 1.2.0RC2 ++ ++ ++ beta ++ beta ++ ++ 2005-01-11 ++ PHP License ++ * Handle ssl:// in the $server string. (danielc) ++* Also default to port 445 for ssl:// requests as well. (danielc) ++* Enhance debugging in the server. (danielc) ++ ++ ++ ++ 1.2.0RC1 ++ 1.2.0RC1 ++ ++ ++ beta ++ beta ++ ++ 2004-12-30 ++ PHP License ++ * Make things work with SSL. Bug 2489. (nkukard lbsd net) ++* Allow array function callbacks (Matt Kane) ++* Some minor speed-ups (Matt Kane) ++* Add Dump.php to the package (Christian Weiske) ++* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) ++* Silence fsockopen() errors. Bug 1714. (danielc) ++* Encode empty arrays as an array. Bug 1493. (danielc) ++* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) ++* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) ++* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) ++* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) ++* Allow raiseError() to be called statically. (danielc) ++* Stop double escaping of character entities. Bug 987. (danielc) ++ NOTICE: the following have been removed: ++ * XML_RPC_dh() ++ * $GLOBALS['XML_RPC_entities'] ++ * XML_RPC_entity_decode() ++ * XML_RPC_lookup_entity() ++* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) ++ ++ ++ ++ 1.1.0 ++ 1.1.0 ++ ++ ++ stable ++ stable ++ ++ 2004-03-15 ++ PHP License ++ * Added support for sequential arrays to XML_RPC_encode() (mroch) ++* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) ++* Remove "require_once 'PEAR.php'", include only when needed to raise an error ++* Replace echo and error_log() with raiseError() (mroch) ++* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) ++* be tolerant of junk after methodResponse (Luca Mariano, mroch) ++* Silent notice even in the error log (pierre) ++* fix include of shared xml extension on win32 (pierre) ++ ++ ++ ++ 1.0.4 ++ 1.0.4 ++ ++ ++ stable ++ stable ++ ++ 2002-10-02 ++ PHP License ++ * added HTTP proxy authorization support (thanks to Arnaud Limbourg) ++ ++ ++ ++ 1.0.3 ++ 1.0.3 ++ ++ ++ stable ++ stable ++ ++ 2002-05-19 ++ PHP License ++ * fix bug when parsing responses with boolean types ++ ++ ++ ++ 1.0.2 ++ 1.0.2 ++ ++ ++ stable ++ stable ++ ++ 2002-04-16 ++ PHP License ++ * E_ALL fixes ++* fix HTTP response header parsing ++ ++ ++ ++ 1.0.1 ++ 1.0.1 ++ ++ ++ stable ++ stable ++ ++ 2001-09-25 ++ PHP License ++ This is a PEAR-ified version of Useful Inc's 1.0.1 release. ++Includes an urgent security fix identified by Dan Libby <dan@libby.com>. ++ ++ ++ ++XML_RPC-1.4.0/tests/protoport.php100666 0 0 25543 10277724745 11707 ++ * @copyright 2005 The PHP Group ++ * @license http://www.php.net/license/3_0.txt PHP License ++ * @version CVS: $Id: protoport.php,v 1.4 2005/01/24 17:48:47 danielc Exp $ ++ * @link http://pear.php.net/package/XML_RPC ++ * @since File available since Release 1.2 ++ */ ++ ++/* ++ * If the package version number is found in the left hand ++ * portion of the if() expression below, that means this file has ++ * come from the PEAR installer. Therefore, let's test the ++ * installed version of XML_RPC which should be in the include path. ++ * ++ * If the version has not been substituted in the if() expression, ++ * this file has likely come from a CVS checkout or a .tar file. ++ * Therefore, we'll assume the tests should use the version of ++ * XML_RPC that has come from there as well. ++ */ ++if ('1.4.0' != '@'.'package_version'.'@') { ++ /** ++ * Get the needed class from the PEAR installation ++ */ ++ require_once 'XML/RPC.php'; ++} else { ++ /** ++ * Get the needed class from the parent directory ++ */ ++ require_once '../RPC.php'; ++} ++ ++/** ++ * Compare the test result to the expected result ++ * ++ * If the test fails, echo out the results. ++ * ++ * @param array $expect the array of object properties you expect ++ * from the test ++ * @param object $actual the object results from the test ++ * @param string $test_name the name of the test ++ * ++ * @return void ++ */ ++function compare($expect, $actual, $test_name) { ++ $actual = get_object_vars($actual); ++ if (count(array_diff($actual, $expect))) { ++ echo "$test_name failed.\nExpect: "; ++ print_r($expect); ++ echo "Actual: "; ++ print_r($actual); ++ echo "\n"; ++ } ++} ++ ++if (php_sapi_name() != 'cli') { ++ echo "
\n";
++}
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver');
++compare($x, $c, 'defaults');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver');
++compare($x, $c, 'defaults with http');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver');
++compare($x, $c, 'defaults with https');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver');
++compare($x, $c, 'defaults with ssl');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 65);
++compare($x, $c, 'port 65');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 65);
++compare($x, $c, 'port 65 with http');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 65);
++compare($x, $c, 'port 65 with https');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65);
++compare($x, $c, 'port 65 with ssl');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 0,
++                        'theproxy');
++compare($x, $c, 'defaults proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 0,
++                        'http://theproxy');
++compare($x, $c, 'defaults with http proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 0,
++                        'https://theproxy');
++compare($x, $c, 'defaults with https proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 0,
++                        'ssl://theproxy');
++compare($x, $c, 'defaults with ssl proxy');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 65,
++                        'theproxy', 6565);
++compare($x, $c, 'port 65 proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 65,
++                        'http://theproxy', 6565);
++compare($x, $c, 'port 65 with http proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 65,
++                        'https://theproxy', 6565);
++compare($x, $c, 'port 65 with https proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65,
++                        'ssl://theproxy', 6565);
++compare($x, $c, 'port 65 with ssl proxy 6565');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 443,
++                        'theproxy', 443);
++compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 0,
++                        'ssl://theproxy', 6565);
++compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
++XML_RPC-1.4.0/tests/test_Dump.php100666      0      0        3042 10277724745  11551 new XML_RPC_Value('das ist der Titel', 'string'),
++    'startDate'=>new XML_RPC_Value(mktime(0,0,0,13,11,2004), 'dateTime.iso8601'),
++    'endDate'  =>new XML_RPC_Value(mktime(0,0,0,15,11,2004), 'dateTime.iso8601'),
++    'error'    =>'string',
++    'arkey'    => new XML_RPC_Value( array(
++        new XML_RPC_Value('simple string'),
++        new XML_RPC_Value(12345, 'int')
++        ), 'array')
++    )
++    ,'struct');
++
++XML_RPC_Dump($val);
++
++echo '==============' . "\r\n";
++$val2 = new XML_RPC_Value(44353, 'int');
++XML_RPC_Dump($val2);
++
++echo '==============' . "\r\n";
++$val3 = new XML_RPC_Value('this should be a string', 'string');
++XML_RPC_Dump($val3);
++
++echo '==============' . "\r\n";
++$val4 = new XML_RPC_Value(true, 'boolean');
++XML_RPC_Dump($val4);
++XML_RPC-1.4.0/Dump.php100666      0      0       12074 10277724745   7375 
++ * @version    CVS: $Id: Dump.php,v 1.7 2005/01/24 03:47:55 danielc Exp $
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++
++
++/**
++ * Pull in the XML_RPC class
++ */
++require_once 'XML/RPC.php';
++
++
++/**
++ * Generates the dump of the XML_RPC_Value and echoes it
++ *
++ * @param object $value  the XML_RPC_Value object to dump
++ *
++ * @return void
++ */
++function XML_RPC_Dump($value)
++{
++    $dumper = new XML_RPC_Dump();
++    echo $dumper->generateDump($value);
++}
++
++
++/**
++ * Class which generates a dump of a XML_RPC_Value object
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Christian Weiske 
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Dump
++{
++    /**
++     * The indentation array cache
++     * @var array
++     */
++    var $arIndent      = array();
++
++    /**
++     * The spaces used for indenting the XML
++     * @var string
++     */
++    var $strBaseIndent = '    ';
++
++    /**
++     * Returns the dump in XML format without printing it out
++     *
++     * @param object $value   the XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  the dump
++     */
++    function generateDump($value, $nLevel = 0)
++    {
++        if (!is_object($value) && get_class($value) != 'xml_rpc_value') {
++            require_once 'PEAR.php';
++            PEAR::raiseError('Tried to dump non-XML_RPC_Value variable' . "\r\n",
++                             0, PEAR_ERROR_PRINT);
++            if (is_object($value)) {
++                $strType = get_class($value);
++            } else {
++                $strType = gettype($value);
++            }
++            return $this->getIndent($nLevel) . 'NOT A XML_RPC_Value: '
++                   . $strType . "\r\n";
++        }
++
++        switch ($value->kindOf()) {
++        case 'struct':
++            $ret = $this->genStruct($value, $nLevel);
++            break;
++        case 'array':
++            $ret = $this->genArray($value, $nLevel);
++            break;
++        case 'scalar':
++            $ret = $this->genScalar($value->scalarval(), $nLevel);
++            break;
++        default:
++            require_once 'PEAR.php';
++            PEAR::raiseError('Illegal type "' . $value->kindOf()
++                             . '" in XML_RPC_Value' . "\r\n", 0,
++                             PEAR_ERROR_PRINT);
++        }
++
++        return $ret;
++    }
++
++    /**
++     * Returns the scalar value dump
++     *
++     * @param object $value   the scalar XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genScalar($value, $nLevel)
++    {
++        if (gettype($value) == 'object') {
++            $strClass = ' ' . get_class($value);
++        } else {
++            $strClass = '';
++        }
++        return $this->getIndent($nLevel) . gettype($value) . $strClass
++               . ' ' . $value . "\r\n";
++    }
++
++    /**
++     * Returns the dump of a struct
++     *
++     * @param object $value   the struct XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genStruct($value, $nLevel)
++    {
++        $value->structreset();
++        $strOutput = $this->getIndent($nLevel) . 'struct' . "\r\n";
++        while (list($key, $keyval) = $value->structeach()) {
++            $strOutput .= $this->getIndent($nLevel + 1) . $key . "\r\n";
++            $strOutput .= $this->generateDump($keyval, $nLevel + 2);
++        }
++        return $strOutput;
++    }
++
++    /**
++     * Returns the dump of an array
++     *
++     * @param object $value   the array XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genArray($value, $nLevel)
++    {
++        $nSize     = $value->arraysize();
++        $strOutput = $this->getIndent($nLevel) . 'array' . "\r\n";
++        for($nA = 0; $nA < $nSize; $nA++) {
++            $strOutput .= $this->getIndent($nLevel + 1) . $nA . "\r\n";
++            $strOutput .= $this->generateDump($value->arraymem($nA),
++                                              $nLevel + 2);
++        }
++        return $strOutput;
++    }
++
++    /**
++     * Returns the indent for a specific level and caches it for faster use
++     *
++     * @param int $nLevel  the level
++     *
++     * @return string  the indented string
++     */
++    function getIndent($nLevel)
++    {
++        if (!isset($this->arIndent[$nLevel])) {
++            $this->arIndent[$nLevel] = str_repeat($this->strBaseIndent, $nLevel);
++        }
++        return $this->arIndent[$nLevel];
++    }
++}
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * c-hanging-comment-ender-p: nil
++ * End:
++ */
++
++?>
++XML_RPC-1.4.0/RPC.php100666      0      0      156232 10277724745   7141 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    CVS: $Id: RPC.php,v 1.83 2005/08/14 20:25:35 danielc Exp $
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++
++
++if (!function_exists('xml_parser_create')) {
++    PEAR::loadExtension('xml');
++}
++
++/**#@+
++ * Error constants
++ */
++/**
++ * Parameter values don't match parameter types
++ */
++define('XML_RPC_ERROR_INVALID_TYPE', 101);
++/**
++ * Parameter declared to be numeric but the values are not
++ */
++define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102);
++/**
++ * Communication error
++ */
++define('XML_RPC_ERROR_CONNECTION_FAILED', 103);
++/**
++ * The array or struct has already been started
++ */
++define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
++/**
++ * Incorrect parameters submitted
++ */
++define('XML_RPC_ERROR_INCORRECT_PARAMS', 105);
++/**
++ * Programming error by developer
++ */
++define('XML_RPC_ERROR_PROGRAMMING', 106);
++/**#@-*/
++
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_I4']
++ */
++$GLOBALS['XML_RPC_I4'] = 'i4';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Int']
++ */
++$GLOBALS['XML_RPC_Int'] = 'int';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Boolean']
++ */
++$GLOBALS['XML_RPC_Boolean'] = 'boolean';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Double']
++ */
++$GLOBALS['XML_RPC_Double'] = 'double';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_String']
++ */
++$GLOBALS['XML_RPC_String'] = 'string';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_DateTime']
++ */
++$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Base64']
++ */
++$GLOBALS['XML_RPC_Base64'] = 'base64';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Array']
++ */
++$GLOBALS['XML_RPC_Array'] = 'array';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Struct']
++ */
++$GLOBALS['XML_RPC_Struct'] = 'struct';
++
++
++/**
++ * Data type meta-types
++ * @global array $GLOBALS['XML_RPC_Types']
++ */
++$GLOBALS['XML_RPC_Types'] = array(
++    $GLOBALS['XML_RPC_I4']       => 1,
++    $GLOBALS['XML_RPC_Int']      => 1,
++    $GLOBALS['XML_RPC_Boolean']  => 1,
++    $GLOBALS['XML_RPC_String']   => 1,
++    $GLOBALS['XML_RPC_Double']   => 1,
++    $GLOBALS['XML_RPC_DateTime'] => 1,
++    $GLOBALS['XML_RPC_Base64']   => 1,
++    $GLOBALS['XML_RPC_Array']    => 2,
++    $GLOBALS['XML_RPC_Struct']   => 3,
++);
++
++
++/**
++ * Error message numbers
++ * @global array $GLOBALS['XML_RPC_err']
++ */
++$GLOBALS['XML_RPC_err'] = array(
++    'unknown_method'      => 1,
++    'invalid_return'      => 2,
++    'incorrect_params'    => 3,
++    'introspect_unknown'  => 4,
++    'http_error'          => 5,
++    'not_response_object' => 6,
++    'invalid_request'     => 7,
++);
++
++/**
++ * Error message strings
++ * @global array $GLOBALS['XML_RPC_str']
++ */
++$GLOBALS['XML_RPC_str'] = array(
++    'unknown_method'      => 'Unknown method',
++    'invalid_return'      => 'Invalid return payload: enable debugging to examine incoming payload',
++    'incorrect_params'    => 'Incorrect parameters passed to method',
++    'introspect_unknown'  => 'Can\'t introspect: method unknown',
++    'http_error'          => 'Didn\'t receive 200 OK from remote server.',
++    'not_response_object' => 'The requested method didn\'t return an XML_RPC_Response object.',
++    'invalid_request'     => 'Invalid request payload',
++);
++
++
++/**
++ * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
++ * @global string $GLOBALS['XML_RPC_defencoding']
++ */
++$GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
++
++/**
++ * User error codes start at 800
++ * @global int $GLOBALS['XML_RPC_erruser']
++ */
++$GLOBALS['XML_RPC_erruser'] = 800;
++
++/**
++ * XML parse error codes start at 100
++ * @global int $GLOBALS['XML_RPC_errxml']
++ */
++$GLOBALS['XML_RPC_errxml'] = 100;
++
++
++/**
++ * Compose backslashes for escaping regexp
++ * @global string $GLOBALS['XML_RPC_backslash']
++ */
++$GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
++
++
++/**
++ * Valid parents of XML elements
++ * @global array $GLOBALS['XML_RPC_valid_parents']
++ */
++$GLOBALS['XML_RPC_valid_parents'] = array(
++    'BOOLEAN' => array('VALUE'),
++    'I4' => array('VALUE'),
++    'INT' => array('VALUE'),
++    'STRING' => array('VALUE'),
++    'DOUBLE' => array('VALUE'),
++    'DATETIME.ISO8601' => array('VALUE'),
++    'BASE64' => array('VALUE'),
++    'ARRAY' => array('VALUE'),
++    'STRUCT' => array('VALUE'),
++    'PARAM' => array('PARAMS'),
++    'METHODNAME' => array('METHODCALL'),
++    'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),
++    'MEMBER' => array('STRUCT'),
++    'NAME' => array('MEMBER'),
++    'DATA' => array('ARRAY'),
++    'FAULT' => array('METHODRESPONSE'),
++    'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
++);
++
++
++/**
++ * Stores state during parsing
++ *
++ * quick explanation of components:
++ *   + ac     = accumulates values
++ *   + qt     = decides if quotes are needed for evaluation
++ *   + cm     = denotes struct or array (comma needed)
++ *   + isf    = indicates a fault
++ *   + lv     = indicates "looking for a value": implements the logic
++ *               to allow values with no types to be strings
++ *   + params = stores parameters in method calls
++ *   + method = stores method name
++ *
++ * @global array $GLOBALS['XML_RPC_xh']
++ */
++$GLOBALS['XML_RPC_xh'] = array();
++
++
++/**
++ * Start element handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_se($parser_resource, $name, $attrs)
++{
++    global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String, $XML_RPC_valid_parents;
++    $parser = (int) $parser_resource;
++
++    // if invalid xmlrpc already detected, skip all processing
++    if ($XML_RPC_xh[$parser]['isf'] >= 2) {
++        return;
++    }
++
++    // check for correct element nesting
++    // top level element can only be of 2 types
++    if (count($XML_RPC_xh[$parser]['stack']) == 0) {
++        if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') {
++            $XML_RPC_xh[$parser]['isf'] = 2;
++            $XML_RPC_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element';
++            return;
++        }
++    } else {
++        // not top level element: see if parent is OK
++        if (!in_array($XML_RPC_xh[$parser]['stack'][0], $XML_RPC_valid_parents[$name])) {
++            $name = preg_replace('[^a-zA-Z0-9._-]', '', $name);
++            $XML_RPC_xh[$parser]['isf'] = 2;
++            $XML_RPC_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$XML_RPC_xh[$parser]['stack'][0]}";
++            return;
++        }
++    }
++
++    switch ($name) {
++    case 'STRUCT':
++        $XML_RPC_xh[$parser]['cm']++;
++
++        // turn quoting off
++        $XML_RPC_xh[$parser]['qt'] = 0;
++
++        $cur_val = array();
++        $cur_val['value'] = array();
++        $cur_val['members'] = 1;
++        array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
++        break;
++
++    case 'ARRAY':
++        $XML_RPC_xh[$parser]['cm']++;
++
++        // turn quoting off
++        $XML_RPC_xh[$parser]['qt'] = 0;
++
++        $cur_val = array();
++        $cur_val['value'] = array();
++        $cur_val['members'] = 0;
++        array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
++        break;
++
++    case 'NAME':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        break;
++
++    case 'FAULT':
++        $XML_RPC_xh[$parser]['isf'] = 1;
++        break;
++
++    case 'PARAM':
++        $XML_RPC_xh[$parser]['valuestack'] = array();
++        break;
++
++    case 'VALUE':
++        $XML_RPC_xh[$parser]['lv'] = 1;
++        $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        // look for a value: if this is still 1 by the
++        // time we reach the first data segment then the type is string
++        // by implication and we need to add in a quote
++        break;
++
++    case 'I4':
++    case 'INT':
++    case 'STRING':
++    case 'BOOLEAN':
++    case 'DOUBLE':
++    case 'DATETIME.ISO8601':
++    case 'BASE64':
++        $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
++
++        if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
++            $XML_RPC_xh[$parser]['qt'] = 1;
++
++            if ($name == 'DATETIME.ISO8601') {
++                $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
++            }
++
++        } elseif ($name == 'BASE64') {
++            $XML_RPC_xh[$parser]['qt'] = 2;
++        } else {
++            // No quoting is required here -- but
++            // at the end of the element we must check
++            // for data format errors.
++            $XML_RPC_xh[$parser]['qt'] = 0;
++        }
++        break;
++
++    case 'MEMBER':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        break;
++
++    case 'DATA':
++    case 'METHODCALL':
++    case 'METHODNAME':
++    case 'METHODRESPONSE':
++    case 'PARAMS':
++        // valid elements that add little to processing
++        break;
++    }
++
++
++    // Save current element to stack
++    array_unshift($XML_RPC_xh[$parser]['stack'], $name);
++
++    if ($name != 'VALUE') {
++        $XML_RPC_xh[$parser]['lv'] = 0;
++    }
++}
++
++/**
++ * End element handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_ee($parser_resource, $name)
++{
++    global $XML_RPC_xh, $XML_RPC_Types, $XML_RPC_String;
++    $parser = (int) $parser_resource;
++
++    if ($XML_RPC_xh[$parser]['isf'] >= 2) {
++        return;
++    }
++
++    // push this element from stack
++    // NB: if XML validates, correct opening/closing is guaranteed and
++    // we do not have to check for $name == $curr_elem.
++    // we also checked for proper nesting at start of elements...
++    $curr_elem = array_shift($XML_RPC_xh[$parser]['stack']);
++
++    switch ($name) {
++    case 'STRUCT':
++    case 'ARRAY':
++    $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
++    $XML_RPC_xh[$parser]['value'] = $cur_val['value'];
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++        $XML_RPC_xh[$parser]['cm']--;
++        break;
++
++    case 'NAME':
++    $XML_RPC_xh[$parser]['valuestack'][0]['name'] = $XML_RPC_xh[$parser]['ac'];
++        break;
++
++    case 'BOOLEAN':
++        // special case here: we translate boolean 1 or 0 into PHP
++        // constants true or false
++        if ($XML_RPC_xh[$parser]['ac'] == '1') {
++            $XML_RPC_xh[$parser]['ac'] = 'true';
++        } else {
++            $XML_RPC_xh[$parser]['ac'] = 'false';
++        }
++
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++        // Drop through intentionally.
++
++    case 'I4':
++    case 'INT':
++    case 'STRING':
++    case 'DOUBLE':
++    case 'DATETIME.ISO8601':
++    case 'BASE64':
++        if ($XML_RPC_xh[$parser]['qt'] == 1) {
++            // we use double quotes rather than single so backslashification works OK
++            $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
++        } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
++            $XML_RPC_xh[$parser]['value'] = base64_decode($XML_RPC_xh[$parser]['ac']);
++        } elseif ($name == 'BOOLEAN') {
++            $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
++        } else {
++            // we have an I4, INT or a DOUBLE
++            // we must check that only 0123456789-. are characters here
++            if (!ereg("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
++                XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
++                                         XML_RPC_ERROR_NON_NUMERIC_FOUND);
++                $XML_RPC_xh[$parser]['value'] = XML_RPC_ERROR_NON_NUMERIC_FOUND;
++            } else {
++                // it's ok, add it on
++                $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
++            }
++        }
++
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
++        break;
++
++    case 'VALUE':
++        // deal with a string value
++        if (strlen($XML_RPC_xh[$parser]['ac']) > 0 &&
++            $XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
++            $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
++        }
++
++        $temp = new XML_RPC_Value($XML_RPC_xh[$parser]['value'], $XML_RPC_xh[$parser]['vt']);
++
++        $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
++        if (is_array($cur_val)) {
++            if ($cur_val['members']==0) {
++                $cur_val['value'][] = $temp;
++            } else {
++                $XML_RPC_xh[$parser]['value'] = $temp;
++            }
++            array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
++        } else {
++            $XML_RPC_xh[$parser]['value'] = $temp;
++        }
++        break;
++
++    case 'MEMBER':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++
++        $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
++        if (is_array($cur_val)) {
++            if ($cur_val['members']==1) {
++                $cur_val['value'][$cur_val['name']] = $XML_RPC_xh[$parser]['value'];
++            }
++            array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
++        }
++        break;
++
++    case 'DATA':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        break;
++
++    case 'PARAM':
++        $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['value'];
++        break;
++
++    case 'METHODNAME':
++    case 'RPCMETHODNAME':
++        $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", '',
++                                                      $XML_RPC_xh[$parser]['ac']);
++        break;
++    }
++
++    // if it's a valid type name, set the type
++    if (isset($XML_RPC_Types[strtolower($name)])) {
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++    }
++}
++
++/**
++ * Character data handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_cd($parser_resource, $data)
++{
++    global $XML_RPC_xh, $XML_RPC_backslash;
++    $parser = (int) $parser_resource;
++
++    if ($XML_RPC_xh[$parser]['lv'] != 3) {
++        // "lookforvalue==3" means that we've found an entire value
++        // and should discard any further character data
++
++        if ($XML_RPC_xh[$parser]['lv'] == 1) {
++            // if we've found text and we're just in a  then
++            // turn quoting on, as this will be a string
++            $XML_RPC_xh[$parser]['qt'] = 1;
++            // and say we've found a value
++            $XML_RPC_xh[$parser]['lv'] = 2;
++        }
++
++        // replace characters that eval would
++        // do special things with
++        if (!isset($XML_RPC_xh[$parser]['ac'])) {
++            $XML_RPC_xh[$parser]['ac'] = '';
++        }
++        $XML_RPC_xh[$parser]['ac'] .= $data;
++    }
++}
++
++/**
++ * The common methods and properties for all of the XML_RPC classes
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Base {
++
++    /**
++     * PEAR Error handling
++     *
++     * @return object  PEAR_Error object
++     */
++    function raiseError($msg, $code)
++    {
++        include_once 'PEAR.php';
++        if (is_object(@$this)) {
++            return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
++        } else {
++            return PEAR::raiseError('XML_RPC: ' . $msg, $code);
++        }
++    }
++
++    /**
++     * Tell whether something is a PEAR_Error object
++     *
++     * @param mixed $value  the item to check
++     *
++     * @return bool  whether $value is a PEAR_Error object or not
++     *
++     * @access public
++     */
++    function isError($value)
++    {
++        return is_a($value, 'PEAR_Error');
++    }
++}
++
++/**
++ * The methods and properties for submitting XML RPC requests
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Client extends XML_RPC_Base {
++
++    /**
++     * The path and name of the RPC server script you want the request to go to
++     * @var string
++     */
++    var $path = '';
++
++    /**
++     * The name of the remote server to connect to
++     * @var string
++     */
++    var $server = '';
++
++    /**
++     * The protocol to use in contacting the remote server
++     * @var string
++     */
++    var $protocol = 'http://';
++
++    /**
++     * The port for connecting to the remote server
++     *
++     * The default is 80 for http:// connections
++     * and 443 for https:// and ssl:// connections.
++     *
++     * @var integer
++     */
++    var $port = 80;
++
++    /**
++     * A user name for accessing the RPC server
++     * @var string
++     * @see XML_RPC_Client::setCredentials()
++     */
++    var $username = '';
++
++    /**
++     * A password for accessing the RPC server
++     * @var string
++     * @see XML_RPC_Client::setCredentials()
++     */
++    var $password = '';
++
++    /**
++     * The name of the proxy server to use, if any
++     * @var string
++     */
++    var $proxy = '';
++
++    /**
++     * The protocol to use in contacting the proxy server, if any
++     * @var string
++     */
++    var $proxy_protocol = 'http://';
++
++    /**
++     * The port for connecting to the proxy server
++     *
++     * The default is 8080 for http:// connections
++     * and 443 for https:// and ssl:// connections.
++     *
++     * @var integer
++     */
++    var $proxy_port = 8080;
++
++    /**
++     * A user name for accessing the proxy server
++     * @var string
++     */
++    var $proxy_user = '';
++
++    /**
++     * A password for accessing the proxy server
++     * @var string
++     */
++    var $proxy_pass = '';
++
++    /**
++     * The error number, if any
++     * @var integer
++     */
++    var $errno = 0;
++
++    /**
++     * The error message, if any
++     * @var string
++     */
++    var $errstr = '';
++
++    /**
++     * The current debug mode (1 = on, 0 = off)
++     * @var integer
++     */
++    var $debug = 0;
++
++    /**
++     * The HTTP headers for the current request.
++     * @var string
++     */
++    var $headers = '';
++
++
++    /**
++     * Sets the object's properties
++     *
++     * @param string  $path        the path and name of the RPC server script
++     *                              you want the request to go to
++     * @param string  $server      the URL of the remote server to connect to.
++     *                              If this parameter doesn't specify a
++     *                              protocol and $port is 443, ssl:// is
++     *                              assumed.
++     * @param integer $port        a port for connecting to the remote server.
++     *                              Defaults to 80 for http:// connections and
++     *                              443 for https:// and ssl:// connections.
++     * @param string  $proxy       the URL of the proxy server to use, if any.
++     *                              If this parameter doesn't specify a
++     *                              protocol and $port is 443, ssl:// is
++     *                              assumed.
++     * @param integer $proxy_port  a port for connecting to the remote server.
++     *                              Defaults to 8080 for http:// connections and
++     *                              443 for https:// and ssl:// connections.
++     * @param string  $proxy_user  a user name for accessing the proxy server
++     * @param string  $proxy_pass  a password for accessing the proxy server
++     *
++     * @return void
++     */
++    function XML_RPC_Client($path, $server, $port = 0,
++                            $proxy = '', $proxy_port = 0,
++                            $proxy_user = '', $proxy_pass = '')
++    {
++        $this->path       = $path;
++        $this->proxy_user = $proxy_user;
++        $this->proxy_pass = $proxy_pass;
++
++        preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match);
++        if ($match[1] == '') {
++            if ($port == 443) {
++                $this->server   = $match[2];
++                $this->protocol = 'ssl://';
++                $this->port     = 443;
++            } else {
++                $this->server = $match[2];
++                if ($port) {
++                    $this->port = $port;
++                }
++            }
++        } elseif ($match[1] == 'http://') {
++            $this->server = $match[2];
++            if ($port) {
++                $this->port = $port;
++            }
++        } else {
++            $this->server   = $match[2];
++            $this->protocol = 'ssl://';
++            if ($port) {
++                $this->port = $port;
++            } else {
++                $this->port = 443;
++            }
++        }
++
++        if ($proxy) {
++            preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match);
++            if ($match[1] == '') {
++                if ($proxy_port == 443) {
++                    $this->proxy          = $match[2];
++                    $this->proxy_protocol = 'ssl://';
++                    $this->proxy_port     = 443;
++                } else {
++                    $this->proxy = $match[2];
++                    if ($proxy_port) {
++                        $this->proxy_port = $proxy_port;
++                    }
++                }
++            } elseif ($match[1] == 'http://') {
++                $this->proxy = $match[2];
++                if ($proxy_port) {
++                    $this->proxy_port = $proxy_port;
++                }
++            } else {
++                $this->proxy          = $match[2];
++                $this->proxy_protocol = 'ssl://';
++                if ($proxy_port) {
++                    $this->proxy_port = $proxy_port;
++                } else {
++                    $this->proxy_port = 443;
++                }
++            }
++        }
++    }
++
++    /**
++     * Change the current debug mode
++     *
++     * @param int $in  where 1 = on, 0 = off
++     *
++     * @return void
++     */
++    function setDebug($in)
++    {
++        if ($in) {
++            $this->debug = 1;
++        } else {
++            $this->debug = 0;
++        }
++    }
++
++    /**
++     * Set username and password properties for connecting to the RPC server
++     *
++     * @param string $u  the user name
++     * @param string $p  the password
++     *
++     * @return void
++     *
++     * @see XML_RPC_Client::$username, XML_RPC_Client::$password
++     */
++    function setCredentials($u, $p)
++    {
++        $this->username = $u;
++        $this->password = $p;
++    }
++
++    /**
++     * Transmit the RPC request via HTTP 1.0 protocol
++     *
++     * @param object $msg       the XML_RPC_Message object
++     * @param int    $timeout   how many seconds to wait for the request
++     *
++     * @return object  an XML_RPC_Response object.  0 is returned if any
++     *                  problems happen.
++     *
++     * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
++     *      XML_RPC_Client::setCredentials()
++     */
++    function send($msg, $timeout = 0)
++    {
++        if (strtolower(get_class($msg)) != 'xml_rpc_message') {
++            $this->errstr = 'send()\'s $msg parameter must be an'
++                          . ' XML_RPC_Message object.';
++            $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING);
++            return 0;
++        }
++        $msg->debug = $this->debug;
++        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
++                                        $timeout, $this->username,
++                                        $this->password);
++    }
++
++    /**
++     * Transmit the RPC request via HTTP 1.0 protocol
++     *
++     * Requests should be sent using XML_RPC_Client send() rather than
++     * calling this method directly.
++     *
++     * @param object $msg       the XML_RPC_Message object
++     * @param string $server    the server to send the request to
++     * @param int    $port      the server port send the request to
++     * @param int    $timeout   how many seconds to wait for the request
++     *                           before giving up
++     * @param string $username  a user name for accessing the RPC server
++     * @param string $password  a password for accessing the RPC server
++     *
++     * @return object  an XML_RPC_Response object.  0 is returned if any
++     *                  problems happen.
++     *
++     * @access protected
++     * @see XML_RPC_Client::send()
++     */
++    function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
++                               $username = '', $password = '')
++    {
++        /*
++         * If we're using a proxy open a socket to the proxy server
++         * instead to the xml-rpc server
++         */
++        if ($this->proxy) {
++            if ($this->proxy_protocol == 'http://') {
++                $protocol = '';
++            } else {
++                $protocol = $this->proxy_protocol;
++            }
++            if ($timeout > 0) {
++                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
++                                 $this->errno, $this->errstr, $timeout);
++            } else {
++                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
++                                 $this->errno, $this->errstr);
++            }
++        } else {
++            if ($this->protocol == 'http://') {
++                $protocol = '';
++            } else {
++                $protocol = $this->protocol;
++            }
++            if ($timeout > 0) {
++                $fp = @fsockopen($protocol . $server, $port,
++                                 $this->errno, $this->errstr, $timeout);
++            } else {
++                $fp = @fsockopen($protocol . $server, $port,
++                                 $this->errno, $this->errstr);
++            }
++        }
++
++        /*
++         * Just raising the error without returning it is strange,
++         * but keep it here for backwards compatibility.
++         */
++        if (!$fp && $this->proxy) {
++            $this->raiseError('Connection to proxy server '
++                              . $this->proxy . ':' . $this->proxy_port
++                              . ' failed. ' . $this->errstr,
++                              XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        } elseif (!$fp) {
++            $this->raiseError('Connection to RPC server '
++                              . $server . ':' . $port
++                              . ' failed. ' . $this->errstr,
++                              XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        }
++
++        if ($timeout) {
++            /*
++             * Using socket_set_timeout() because stream_set_timeout()
++             * was introduced in 4.3.0, but we need to support 4.2.0.
++             */
++            socket_set_timeout($fp, $timeout);
++        }
++
++        // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly
++        if ($username != $this->username) {
++            $this->setCredentials($username, $password);
++        }
++
++        // Only create the payload if it was not created previously
++        if (empty($msg->payload)) {
++            $msg->createPayload();
++        }
++        $this->createHeaders($msg);
++
++        $op  = $this->headers . "\r\n\r\n";
++        $op .= $msg->payload;
++
++        if (!fputs($fp, $op, strlen($op))) {
++            $this->errstr = 'Write error';
++            return 0;
++        }
++        $resp = $msg->parseResponseFile($fp);
++
++        $meta = socket_get_status($fp);
++        if ($meta['timed_out']) {
++            fclose($fp);
++            $this->errstr = 'RPC server did not send response before timeout.';
++            $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        }
++
++        fclose($fp);
++        return $resp;
++    }
++
++    /**
++     * Determines the HTTP headers and puts it in the $headers property
++     *
++     * @param object $msg       the XML_RPC_Message object
++     *
++     * @return boolean  TRUE if okay, FALSE if the message payload isn't set.
++     *
++     * @access protected
++     */
++    function createHeaders($msg)
++    {
++        if (empty($msg->payload)) {
++            return false;
++        }
++        if ($this->proxy) {
++            $this->headers = 'POST ' . $this->protocol . $this->server;
++            if ($this->proxy_port) {
++                $this->headers .= ':' . $this->port;
++            }
++        } else {
++           $this->headers = 'POST ';
++        }
++        $this->headers .= $this->path. " HTTP/1.0\r\n";
++
++        $this->headers .= "User-Agent: PEAR XML_RPC\r\n";
++        $this->headers .= 'Host: ' . $this->server . "\r\n";
++
++        if ($this->proxy && $this->proxy_user) {
++            $this->headers .= 'Proxy-Authorization: Basic '
++                     . base64_encode("$this->proxy_user:$this->proxy_pass")
++                     . "\r\n";
++        }
++
++        // thanks to Grant Rauscher  for this
++        if ($this->username) {
++            $this->headers .= 'Authorization: Basic '
++                     . base64_encode("$this->username:$this->password")
++                     . "\r\n";
++        }
++
++        $this->headers .= "Content-Type: text/xml\r\n";
++        $this->headers .= 'Content-Length: ' . strlen($msg->payload);
++        return true;
++    }
++}
++
++/**
++ * The methods and properties for interpreting responses to XML RPC requests
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Response extends XML_RPC_Base
++{
++    var $xv;
++    var $fn;
++    var $fs;
++    var $hdrs;
++
++    /**
++     * @return void
++     */
++    function XML_RPC_Response($val, $fcode = 0, $fstr = '')
++    {
++        if ($fcode != 0) {
++            $this->fn = $fcode;
++            $this->fs = htmlspecialchars($fstr);
++        } else {
++            $this->xv = $val;
++        }
++    }
++
++    /**
++     * @return int  the error code
++     */
++    function faultCode()
++    {
++        if (isset($this->fn)) {
++            return $this->fn;
++        } else {
++            return 0;
++        }
++    }
++
++    /**
++     * @return string  the error string
++     */
++    function faultString()
++    {
++        return $this->fs;
++    }
++
++    /**
++     * @return mixed  the value
++     */
++    function value()
++    {
++        return $this->xv;
++    }
++
++    /**
++     * @return string  the error message in XML format
++     */
++    function serialize()
++    {
++        $rs = "\n";
++        if ($this->fn) {
++            $rs .= "
++  
++    
++      
++        faultCode
++        " . $this->fn . "
++      
++      
++        faultString
++        " . $this->fs . "
++      
++    
++  
++";
++        } else {
++            $rs .= "\n\n" . $this->xv->serialize() .
++        "\n";
++        }
++        $rs .= "\n";
++        return $rs;
++    }
++}
++
++/**
++ * The methods and properties for composing XML RPC messages
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Message extends XML_RPC_Base
++{
++    /**
++     * The current debug mode (1 = on, 0 = off)
++     * @var integer
++     */
++    var $debug = 0;
++
++    /**
++     * The encoding to be used for outgoing messages
++     *
++     * Defaults to the value of $GLOBALS['XML_RPC_defencoding']
++     *
++     * @var string
++     * @see XML_RPC_Message::setSendEncoding(),
++     *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
++     */
++    var $send_encoding = '';
++
++    /**
++     * The method presently being evaluated
++     * @var string
++     */
++    var $methodname = '';
++
++    /**
++     * @var array
++     */
++    var $params = array();
++
++    /**
++     * The XML message being generated
++     * @var string
++     */
++    var $payload = '';
++
++    /**
++     * @return void
++     */
++    function XML_RPC_Message($meth, $pars = 0)
++    {
++        $this->methodname = $meth;
++        if (is_array($pars) && sizeof($pars) > 0) {
++            for ($i = 0; $i < sizeof($pars); $i++) {
++                $this->addParam($pars[$i]);
++            }
++        }
++    }
++
++    /**
++     * Produces the XML declaration including the encoding attribute
++     *
++     * The encoding is determined by this class' $send_encoding
++     * property.  If the $send_encoding property is not set, use
++     * $GLOBALS['XML_RPC_defencoding'].
++     *
++     * @return string  the XML declaration and  element
++     *
++     * @see XML_RPC_Message::setSendEncoding(),
++     *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
++     */
++    function xml_header()
++    {
++        global $XML_RPC_defencoding;
++        if (!$this->send_encoding) {
++            $this->send_encoding = $XML_RPC_defencoding;
++        }
++        return 'send_encoding . '"?>'
++               . "\n\n";
++    }
++
++    /**
++     * @return string  the closing  tag
++     */
++    function xml_footer()
++    {
++        return "\n";
++    }
++
++    /**
++     * @return void
++     *
++     * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
++     */
++    function createPayload()
++    {
++        $this->payload = $this->xml_header();
++        $this->payload .= '' . $this->methodname . "\n";
++        $this->payload .= "\n";
++        for ($i = 0; $i < sizeof($this->params); $i++) {
++            $p = $this->params[$i];
++            $this->payload .= "\n" . $p->serialize() . "\n";
++        }
++        $this->payload .= "\n";
++        $this->payload .= $this->xml_footer();
++        $this->payload = ereg_replace("[\r\n]+", "\r\n", $this->payload);
++    }
++
++    /**
++     * @return string  the name of the method
++     */
++    function method($meth = '')
++    {
++        if ($meth != '') {
++            $this->methodname = $meth;
++        }
++        return $this->methodname;
++    }
++
++    /**
++     * @return string  the payload
++     */
++    function serialize()
++    {
++        $this->createPayload();
++        return $this->payload;
++    }
++
++    /**
++     * @return void
++     */
++    function addParam($par)
++    {
++        $this->params[] = $par;
++    }
++
++    /**
++     * Obtains an XML_RPC_Value object for the given parameter
++     *
++     * @param int $i  the index number of the parameter to obtain
++     *
++     * @return object  the XML_RPC_Value object.
++     *                  If the parameter doesn't exist, an XML_RPC_Response object.
++     *
++     * @since Returns XML_RPC_Response object on error since Release 1.3.0
++     */
++    function getParam($i)
++    {
++        global $XML_RPC_err, $XML_RPC_str;
++
++        if (isset($this->params[$i])) {
++            return $this->params[$i];
++        } else {
++            $this->raiseError('The submitted request did not contain this parameter',
++                              XML_RPC_ERROR_INCORRECT_PARAMS);
++            return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
++                                        $XML_RPC_str['incorrect_params']);
++        }
++    }
++
++    /**
++     * @return int  the number of parameters
++     */
++    function getNumParams()
++    {
++        return sizeof($this->params);
++    }
++
++    /**
++     * Sets the XML declaration's encoding attribute
++     *
++     * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
++     *
++     * @return void
++     *
++     * @see XML_RPC_Message::$send_encoding, XML_RPC_Message::xml_header()
++     * @since Method available since Release 1.2.0
++     */
++    function setSendEncoding($type)
++    {
++        $this->send_encoding = $type;
++    }
++
++    /**
++     * Determine the XML's encoding via the encoding attribute
++     * in the XML declaration
++     *
++     * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
++     * or US-ASCII, $XML_RPC_defencoding will be returned.
++     *
++     * @param string $data  the XML that will be parsed
++     *
++     * @return string  the encoding to be used
++     *
++     * @link   http://php.net/xml_parser_create
++     * @since  Method available since Release 1.2.0
++     */
++    function getEncoding($data)
++    {
++        global $XML_RPC_defencoding;
++
++        if (preg_match('/<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]/i',
++                       $data, $match))
++        {
++            $match[1] = trim(strtoupper($match[1]));
++            switch ($match[1]) {
++                case 'ISO-8859-1':
++                case 'UTF-8':
++                case 'US-ASCII':
++                    return $match[1];
++                    break;
++
++                default:
++                    return $XML_RPC_defencoding;
++            }
++        } else {
++            return $XML_RPC_defencoding;
++        }
++    }
++
++    /**
++     * @return object  a new XML_RPC_Response object
++     */
++    function parseResponseFile($fp)
++    {
++        $ipd = '';
++        while ($data = @fread($fp, 8192)) {
++            $ipd .= $data;
++        }
++        return $this->parseResponse($ipd);
++    }
++
++    /**
++     * @return object  a new XML_RPC_Response object
++     */
++    function parseResponse($data = '')
++    {
++        global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
++
++        $encoding = $this->getEncoding($data);
++        $parser_resource = xml_parser_create($encoding);
++        $parser = (int) $parser_resource;
++
++        $XML_RPC_xh = array();
++        $XML_RPC_xh[$parser] = array();
++
++        $XML_RPC_xh[$parser]['cm'] = 0;
++        $XML_RPC_xh[$parser]['isf'] = 0;
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = '';
++        $XML_RPC_xh[$parser]['stack'] = array();
++        $XML_RPC_xh[$parser]['valuestack'] = array();
++
++        xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
++        xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
++        xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
++
++        $hdrfnd = 0;
++        if ($this->debug) {
++            print "\n
---GOT---\n";
++            print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
++            print "\n---END---
\n"; ++ } ++ ++ // See if response is a 200 or a 100 then a 200, else raise error. ++ // But only do this if we're using the HTTP protocol. ++ if (ereg('^HTTP', $data) && ++ !ereg('^HTTP/[0-9\.]+ 200 ', $data) && ++ !preg_match('@^HTTP/[0-9\.]+ 10[0-9]([A-Za-z ]+)?[\r\n]+HTTP/[0-9\.]+ 200@', $data)) ++ { ++ $errstr = substr($data, 0, strpos($data, "\n") - 1); ++ error_log('HTTP error, got response: ' . $errstr); ++ $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], ++ $XML_RPC_str['http_error'] . ' (' . ++ $errstr . ')'); ++ xml_parser_free($parser_resource); ++ return $r; ++ } ++ ++ // gotta get rid of headers here ++ if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) { ++ $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos); ++ $data = substr($data, $brpos + 4); ++ $hdrfnd = 1; ++ } ++ ++ /* ++ * be tolerant of junk after methodResponse ++ * (e.g. javascript automatically inserted by free hosts) ++ * thanks to Luca Mariano ++ */ ++ $data = substr($data, 0, strpos($data, "") + 17); ++ ++ if (!xml_parse($parser_resource, $data, sizeof($data))) { ++ // thanks to Peter Kocks ++ if (xml_get_current_line_number($parser_resource) == 1) { ++ $errstr = 'XML error at line 1, check URL'; ++ } else { ++ $errstr = sprintf('XML error: %s at line %d', ++ xml_error_string(xml_get_error_code($parser_resource)), ++ xml_get_current_line_number($parser_resource)); ++ } ++ error_log($errstr); ++ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], ++ $XML_RPC_str['invalid_return']); ++ xml_parser_free($parser_resource); ++ return $r; ++ } ++ ++ xml_parser_free($parser_resource); ++ ++ if ($this->debug) { ++ print "\n
---PARSED---\n";
++            var_dump($XML_RPC_xh[$parser]['value']);
++            print "---END---
\n"; ++ } ++ ++ if ($XML_RPC_xh[$parser]['isf'] > 1) { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], ++ $XML_RPC_str['invalid_return'].' '.$XML_RPC_xh[$parser]['isf_reason']); ++ } elseif (!is_object($XML_RPC_xh[$parser]['value'])) { ++ // then something odd has happened ++ // and it's time to generate a client side error ++ // indicating something odd went on ++ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], ++ $XML_RPC_str['invalid_return']); ++ } else { ++ $v = $XML_RPC_xh[$parser]['value']; ++ $allOK=1; ++ if ($XML_RPC_xh[$parser]['isf']) { ++ $f = $v->structmem('faultCode'); ++ $fs = $v->structmem('faultString'); ++ $r = new XML_RPC_Response($v, $f->scalarval(), ++ $fs->scalarval()); ++ } else { ++ $r = new XML_RPC_Response($v); ++ } ++ } ++ $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]); ++ return $r; ++ } ++} ++ ++/** ++ * The methods and properties that represent data in XML RPC format ++ * ++ * @category Web Services ++ * @package XML_RPC ++ * @author Edd Dumbill ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version Release: 1.4.0 ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++class XML_RPC_Value extends XML_RPC_Base ++{ ++ var $me = array(); ++ var $mytype = 0; ++ ++ /** ++ * @return void ++ */ ++ function XML_RPC_Value($val = -1, $type = '') ++ { ++ global $XML_RPC_Types; ++ $this->me = array(); ++ $this->mytype = 0; ++ if ($val != -1 || $type != '') { ++ if ($type == '') { ++ $type = 'string'; ++ } ++ if (!array_key_exists($type, $XML_RPC_Types)) { ++ // XXX ++ // need some way to report this error ++ } elseif ($XML_RPC_Types[$type] == 1) { ++ $this->addScalar($val, $type); ++ } elseif ($XML_RPC_Types[$type] == 2) { ++ $this->addArray($val); ++ } elseif ($XML_RPC_Types[$type] == 3) { ++ $this->addStruct($val); ++ } ++ } ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addScalar($val, $type = 'string') ++ { ++ global $XML_RPC_Types, $XML_RPC_Boolean; ++ ++ if ($this->mytype == 1) { ++ $this->raiseError('Scalar can have only one value', ++ XML_RPC_ERROR_INVALID_TYPE); ++ return 0; ++ } ++ $typeof = $XML_RPC_Types[$type]; ++ if ($typeof != 1) { ++ $this->raiseError("Not a scalar type (${typeof})", ++ XML_RPC_ERROR_INVALID_TYPE); ++ return 0; ++ } ++ ++ if ($type == $XML_RPC_Boolean) { ++ if (strcasecmp($val, 'true') == 0 ++ || $val == 1 ++ || ($val == true && strcasecmp($val, 'false'))) ++ { ++ $val = 1; ++ } else { ++ $val = 0; ++ } ++ } ++ ++ if ($this->mytype == 2) { ++ // we're adding to an array here ++ $ar = $this->me['array']; ++ $ar[] = new XML_RPC_Value($val, $type); ++ $this->me['array'] = $ar; ++ } else { ++ // a scalar, so set the value and remember we're scalar ++ $this->me[$type] = $val; ++ $this->mytype = $typeof; ++ } ++ return 1; ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addArray($vals) ++ { ++ global $XML_RPC_Types; ++ if ($this->mytype != 0) { ++ $this->raiseError( ++ 'Already initialized as a [' . $this->kindOf() . ']', ++ XML_RPC_ERROR_ALREADY_INITIALIZED); ++ return 0; ++ } ++ $this->mytype = $XML_RPC_Types['array']; ++ $this->me['array'] = $vals; ++ return 1; ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addStruct($vals) ++ { ++ global $XML_RPC_Types; ++ if ($this->mytype != 0) { ++ $this->raiseError( ++ 'Already initialized as a [' . $this->kindOf() . ']', ++ XML_RPC_ERROR_ALREADY_INITIALIZED); ++ return 0; ++ } ++ $this->mytype = $XML_RPC_Types['struct']; ++ $this->me['struct'] = $vals; ++ return 1; ++ } ++ ++ /** ++ * @return void ++ */ ++ function dump($ar) ++ { ++ reset($ar); ++ foreach ($ar as $key => $val) { ++ echo "$key => $val
"; ++ if ($key == 'array') { ++ foreach ($val as $key2 => $val2) { ++ echo "-- $key2 => $val2
"; ++ } ++ } ++ } ++ } ++ ++ /** ++ * @return string the data type of the current value ++ */ ++ function kindOf() ++ { ++ switch ($this->mytype) { ++ case 3: ++ return 'struct'; ++ ++ case 2: ++ return 'array'; ++ ++ case 1: ++ return 'scalar'; ++ ++ default: ++ return 'undef'; ++ } ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serializedata($typ, $val) ++ { ++ $rs = ''; ++ global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean; ++ if (!array_key_exists($typ, $XML_RPC_Types)) { ++ // XXX ++ // need some way to report this error ++ return; ++ } ++ switch ($XML_RPC_Types[$typ]) { ++ case 3: ++ // struct ++ $rs .= "\n"; ++ reset($val); ++ foreach ($val as $key2 => $val2) { ++ $rs .= "${key2}\n"; ++ $rs .= $this->serializeval($val2); ++ $rs .= "\n"; ++ } ++ $rs .= ''; ++ break; ++ ++ case 2: ++ // array ++ $rs .= "\n\n"; ++ for ($i = 0; $i < sizeof($val); $i++) { ++ $rs .= $this->serializeval($val[$i]); ++ } ++ $rs .= "\n"; ++ break; ++ ++ case 1: ++ switch ($typ) { ++ case $XML_RPC_Base64: ++ $rs .= "<${typ}>" . base64_encode($val) . ""; ++ break; ++ case $XML_RPC_Boolean: ++ $rs .= "<${typ}>" . ($val ? '1' : '0') . ""; ++ break; ++ case $XML_RPC_String: ++ $rs .= "<${typ}>" . htmlspecialchars($val). ""; ++ break; ++ default: ++ $rs .= "<${typ}>${val}"; ++ } ++ } ++ return $rs; ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serialize() ++ { ++ return $this->serializeval($this); ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serializeval($o) ++ { ++ if (!is_object($o) || empty($o->me) || !is_array($o->me)) { ++ return ''; ++ } ++ $ar = $o->me; ++ reset($ar); ++ list($typ, $val) = each($ar); ++ return '' . $this->serializedata($typ, $val) . "\n"; ++ } ++ ++ /** ++ * @return mixed the contents of the element requested ++ */ ++ function structmem($m) ++ { ++ return $this->me['struct'][$m]; ++ } ++ ++ /** ++ * @return void ++ */ ++ function structreset() ++ { ++ reset($this->me['struct']); ++ } ++ ++ /** ++ * @return the key/value pair of the struct's current element ++ */ ++ function structeach() ++ { ++ return each($this->me['struct']); ++ } ++ ++ /** ++ * @return mixed the current value ++ */ ++ function getval() ++ { ++ // UNSTABLE ++ global $XML_RPC_BOOLEAN, $XML_RPC_Base64; ++ ++ reset($this->me); ++ $b = current($this->me); ++ ++ // contributed by I Sofer, 2001-03-24 ++ // add support for nested arrays to scalarval ++ // i've created a new method here, so as to ++ // preserve back compatibility ++ ++ if (is_array($b)) { ++ foreach ($b as $id => $cont) { ++ $b[$id] = $cont->scalarval(); ++ } ++ } ++ ++ // add support for structures directly encoding php objects ++ if (is_object($b)) { ++ $t = get_object_vars($b); ++ foreach ($t as $id => $cont) { ++ $t[$id] = $cont->scalarval(); ++ } ++ foreach ($t as $id => $cont) { ++ $b->$id = $cont; ++ } ++ } ++ ++ // end contrib ++ return $b; ++ } ++ ++ /** ++ * @return mixed ++ */ ++ function scalarval() ++ { ++ global $XML_RPC_Boolean, $XML_RPC_Base64; ++ reset($this->me); ++ return current($this->me); ++ } ++ ++ /** ++ * @return string ++ */ ++ function scalartyp() ++ { ++ global $XML_RPC_I4, $XML_RPC_Int; ++ reset($this->me); ++ $a = key($this->me); ++ if ($a == $XML_RPC_I4) { ++ $a = $XML_RPC_Int; ++ } ++ return $a; ++ } ++ ++ /** ++ * @return mixed the struct's current element ++ */ ++ function arraymem($m) ++ { ++ return $this->me['array'][$m]; ++ } ++ ++ /** ++ * @return int the number of elements in the array ++ */ ++ function arraysize() ++ { ++ reset($this->me); ++ list($a, $b) = each($this->me); ++ return sizeof($b); ++ } ++ ++ /** ++ * Determines if the item submitted is an XML_RPC_Value object ++ * ++ * @param mixed $val the variable to be evaluated ++ * ++ * @return bool TRUE if the item is an XML_RPC_Value object ++ * ++ * @static ++ * @since Method available since Release 1.3.0 ++ */ ++ function isValue($val) ++ { ++ return (strtolower(get_class($val)) == 'xml_rpc_value'); ++ } ++} ++ ++/** ++ * Return an ISO8601 encoded string ++ * ++ * While timezones ought to be supported, the XML-RPC spec says: ++ * ++ * "Don't assume a timezone. It should be specified by the server in its ++ * documentation what assumptions it makes about timezones." ++ * ++ * This routine always assumes localtime unless $utc is set to 1, in which ++ * case UTC is assumed and an adjustment for locale is made when encoding. ++ * ++ * @return string the formatted date ++ */ ++function XML_RPC_iso8601_encode($timet, $utc = 0) ++{ ++ if (!$utc) { ++ $t = strftime('%Y%m%dT%H:%M:%S', $timet); ++ } else { ++ if (function_exists('gmstrftime')) { ++ // gmstrftime doesn't exist in some versions ++ // of PHP ++ $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); ++ } else { ++ $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); ++ } ++ } ++ return $t; ++} ++ ++/** ++ * Convert a datetime string into a Unix timestamp ++ * ++ * While timezones ought to be supported, the XML-RPC spec says: ++ * ++ * "Don't assume a timezone. It should be specified by the server in its ++ * documentation what assumptions it makes about timezones." ++ * ++ * This routine always assumes localtime unless $utc is set to 1, in which ++ * case UTC is assumed and an adjustment for locale is made when encoding. ++ * ++ * @return int the unix timestamp of the date submitted ++ */ ++function XML_RPC_iso8601_decode($idate, $utc = 0) ++{ ++ $t = 0; ++ if (ereg('([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})', $idate, $regs)) { ++ if ($utc) { ++ $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); ++ } else { ++ $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); ++ } ++ } ++ return $t; ++} ++ ++/** ++ * Converts an XML_RPC_Value object into native PHP types ++ * ++ * @param object $XML_RPC_val the XML_RPC_Value object to decode ++ * ++ * @return mixed the PHP values ++ */ ++function XML_RPC_decode($XML_RPC_val) ++{ ++ $kind = $XML_RPC_val->kindOf(); ++ ++ if ($kind == 'scalar') { ++ return $XML_RPC_val->scalarval(); ++ ++ } elseif ($kind == 'array') { ++ $size = $XML_RPC_val->arraysize(); ++ $arr = array(); ++ for ($i = 0; $i < $size; $i++) { ++ $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i)); ++ } ++ return $arr; ++ ++ } elseif ($kind == 'struct') { ++ $XML_RPC_val->structreset(); ++ $arr = array(); ++ while (list($key, $value) = $XML_RPC_val->structeach()) { ++ $arr[$key] = XML_RPC_decode($value); ++ } ++ return $arr; ++ } ++} ++ ++/** ++ * Converts native PHP types into an XML_RPC_Value object ++ * ++ * @param mixed $php_val the PHP value or variable you want encoded ++ * ++ * @return object the XML_RPC_Value object ++ */ ++function XML_RPC_encode($php_val) ++{ ++ global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double, $XML_RPC_String, ++ $XML_RPC_Array, $XML_RPC_Struct; ++ ++ $type = gettype($php_val); ++ $XML_RPC_val = new XML_RPC_Value; ++ ++ switch ($type) { ++ case 'array': ++ if (empty($php_val)) { ++ $XML_RPC_val->addArray($php_val); ++ break; ++ } ++ $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); ++ if (empty($tmp)) { ++ $arr = array(); ++ foreach ($php_val as $k => $v) { ++ $arr[$k] = XML_RPC_encode($v); ++ } ++ $XML_RPC_val->addArray($arr); ++ break; ++ } ++ // fall though if it's not an enumerated array ++ ++ case 'object': ++ $arr = array(); ++ foreach ($php_val as $k => $v) { ++ $arr[$k] = XML_RPC_encode($v); ++ } ++ $XML_RPC_val->addStruct($arr); ++ break; ++ ++ case 'integer': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Int); ++ break; ++ ++ case 'double': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Double); ++ break; ++ ++ case 'string': ++ case 'NULL': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_String); ++ break; ++ ++ case 'boolean': ++ // Add support for encoding/decoding of booleans, since they ++ // are supported in PHP ++ // by ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean); ++ break; ++ ++ case 'unknown type': ++ default: ++ $XML_RPC_val = false; ++ } ++ return $XML_RPC_val; ++} ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * c-hanging-comment-ender-p: nil ++ * End: ++ */ ++ ++?> ++XML_RPC-1.4.0/Server.php100666 0 0 51010 10277724745 7727 ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version CVS: $Id: Server.php,v 1.29 2005/08/14 20:25:35 danielc Exp $ ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++ ++ ++/** ++ * Pull in the XML_RPC class ++ */ ++require_once 'XML/RPC.php'; ++ ++ ++/** ++ * signature for system.listMethods: return = array, ++ * parameters = a string or nothing ++ * @global array $GLOBALS['XML_RPC_Server_listMethods_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_listMethods_sig'] = array( ++ array($GLOBALS['XML_RPC_Array'], ++ $GLOBALS['XML_RPC_String'] ++ ), ++ array($GLOBALS['XML_RPC_Array']) ++); ++ ++/** ++ * docstring for system.listMethods ++ * @global string $GLOBALS['XML_RPC_Server_listMethods_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_listMethods_doc'] = 'This method lists all the' ++ . ' methods that the XML-RPC server knows how to dispatch'; ++ ++/** ++ * signature for system.methodSignature: return = array, ++ * parameters = string ++ * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_methodSignature_sig'] = array( ++ array($GLOBALS['XML_RPC_Array'], ++ $GLOBALS['XML_RPC_String'] ++ ) ++); ++ ++/** ++ * docstring for system.methodSignature ++ * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_methodSignature_doc'] = 'Returns an array of known' ++ . ' signatures (an array of arrays) for the method name passed. If' ++ . ' no signatures are known, returns a none-array (test for type !=' ++ . ' array to detect missing signature)'; ++ ++/** ++ * signature for system.methodHelp: return = string, ++ * parameters = string ++ * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_methodHelp_sig'] = array( ++ array($GLOBALS['XML_RPC_String'], ++ $GLOBALS['XML_RPC_String'] ++ ) ++); ++ ++/** ++ * docstring for methodHelp ++ * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_methodHelp_doc'] = 'Returns help text if defined' ++ . ' for the method passed, otherwise returns an empty string'; ++ ++/** ++ * dispatch map for the automatically declared XML-RPC methods. ++ * @global array $GLOBALS['XML_RPC_Server_dmap'] ++ */ ++$GLOBALS['XML_RPC_Server_dmap'] = array( ++ 'system.listMethods' => array( ++ 'function' => 'XML_RPC_Server_listMethods', ++ 'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc'] ++ ), ++ 'system.methodHelp' => array( ++ 'function' => 'XML_RPC_Server_methodHelp', ++ 'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc'] ++ ), ++ 'system.methodSignature' => array( ++ 'function' => 'XML_RPC_Server_methodSignature', ++ 'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc'] ++ ) ++); ++ ++/** ++ * @global string $GLOBALS['XML_RPC_Server_debuginfo'] ++ */ ++$GLOBALS['XML_RPC_Server_debuginfo'] = ''; ++ ++ ++/** ++ * Lists all the methods that the XML-RPC server knows how to dispatch ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_listMethods($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $v = new XML_RPC_Value(); ++ $outAr = array(); ++ foreach ($server->dmap as $key => $val) { ++ $outAr[] = new XML_RPC_Value($key, 'string'); ++ } ++ foreach ($XML_RPC_Server_dmap as $key => $val) { ++ $outAr[] = new XML_RPC_Value($key, 'string'); ++ } ++ $v->addArray($outAr); ++ return new XML_RPC_Response($v); ++} ++ ++/** ++ * Returns an array of known signatures (an array of arrays) ++ * for the given method ++ * ++ * If no signatures are known, returns a none-array ++ * (test for type != array to detect missing signature) ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_methodSignature($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $methName = $m->getParam(0); ++ $methName = $methName->scalarval(); ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $server->dmap; ++ $sysCall = 0; ++ } ++ // print "\n"; ++ if (isset($dmap[$methName])) { ++ if ($dmap[$methName]['signature']) { ++ $sigs = array(); ++ $thesigs = $dmap[$methName]['signature']; ++ for ($i = 0; $i < sizeof($thesigs); $i++) { ++ $cursig = array(); ++ $inSig = $thesigs[$i]; ++ for ($j = 0; $j < sizeof($inSig); $j++) { ++ $cursig[] = new XML_RPC_Value($inSig[$j], 'string'); ++ } ++ $sigs[] = new XML_RPC_Value($cursig, 'array'); ++ } ++ $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array')); ++ } else { ++ $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string')); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], ++ $XML_RPC_str['introspect_unknown']); ++ } ++ return $r; ++} ++ ++/** ++ * Returns help text if defined for the method passed, otherwise returns ++ * an empty string ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_methodHelp($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $methName = $m->getParam(0); ++ $methName = $methName->scalarval(); ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $server->dmap; ++ $sysCall = 0; ++ } ++ ++ if (isset($dmap[$methName])) { ++ if ($dmap[$methName]['docstring']) { ++ $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']), ++ 'string'); ++ } else { ++ $r = new XML_RPC_Response(new XML_RPC_Value('', 'string')); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], ++ $XML_RPC_str['introspect_unknown']); ++ } ++ return $r; ++} ++ ++/** ++ * @return void ++ */ ++function XML_RPC_Server_debugmsg($m) ++{ ++ global $XML_RPC_Server_debuginfo; ++ $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n"; ++} ++ ++ ++/** ++ * A server for receiving and replying to XML RPC requests ++ * ++ * ++ * $server = new XML_RPC_Server( ++ * array( ++ * 'isan8' => ++ * array( ++ * 'function' => 'is_8', ++ * 'signature' => ++ * array( ++ * array('boolean', 'int'), ++ * array('boolean', 'int', 'boolean'), ++ * array('boolean', 'string'), ++ * array('boolean', 'string', 'boolean'), ++ * ), ++ * 'docstring' => 'Is the value an 8?' ++ * ), ++ * ), ++ * 1, ++ * 0 ++ * ); ++ * ++ * ++ * @category Web Services ++ * @package XML_RPC ++ * @author Edd Dumbill ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version Release: 1.4.0 ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++class XML_RPC_Server ++{ ++ /** ++ * The dispatch map, listing the methods this server provides. ++ * @var array ++ */ ++ var $dmap = array(); ++ ++ /** ++ * The present response's encoding ++ * @var string ++ * @see XML_RPC_Message::getEncoding() ++ */ ++ var $encoding = ''; ++ ++ /** ++ * Debug mode (0 = off, 1 = on) ++ * @var integer ++ */ ++ var $debug = 0; ++ ++ /** ++ * The response's HTTP headers ++ * @var string ++ */ ++ var $server_headers = ''; ++ ++ /** ++ * The response's XML payload ++ * @var string ++ */ ++ var $server_payload = ''; ++ ++ ++ /** ++ * Constructor for the XML_RPC_Server class ++ * ++ * @param array $dispMap the dispatch map. An associative array ++ * explaining each function. The keys of the main ++ * array are the procedure names used by the ++ * clients. The value is another associative array ++ * that contains up to three elements: ++ * + The 'function' element's value is the name ++ * of the function or method that gets called. ++ * To define a class' method: 'class::method'. ++ * + The 'signature' element (optional) is an ++ * array describing the return values and ++ * parameters ++ * + The 'docstring' element (optional) is a ++ * string describing what the method does ++ * @param int $serviceNow should the HTTP response be sent now? ++ * (1 = yes, 0 = no) ++ * @param int $debug should debug output be displayed? ++ * (1 = yes, 0 = no) ++ * ++ * @return void ++ */ ++ function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) ++ { ++ global $HTTP_RAW_POST_DATA; ++ ++ if ($debug) { ++ $this->debug = 1; ++ } else { ++ $this->debug = 0; ++ } ++ ++ $this->dmap = $dispMap; ++ ++ if ($serviceNow) { ++ $this->service(); ++ } else { ++ $this->createServerPayload(); ++ $this->createServerHeaders(); ++ } ++ } ++ ++ /** ++ * @return string the debug information if debug debug mode is on ++ */ ++ function serializeDebug() ++ { ++ global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA; ++ ++ if ($this->debug) { ++ XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n" ++ . $HTTP_RAW_POST_DATA ++ . "\n" . '^^^ END POST DATA ^^^'); ++ } ++ ++ if ($XML_RPC_Server_debuginfo != '') { ++ return "\n"; ++ } else { ++ return ''; ++ } ++ } ++ ++ /** ++ * Sends the response ++ * ++ * The encoding and content-type are determined by ++ * XML_RPC_Message::getEncoding() ++ * ++ * @return void ++ * ++ * @uses XML_RPC_Server::createServerPayload(), ++ * XML_RPC_Server::createServerHeaders() ++ */ ++ function service() ++ { ++ if (!$this->server_payload) { ++ $this->createServerPayload(); ++ } ++ if (!$this->server_headers) { ++ $this->createServerHeaders(); ++ } ++ header($this->server_headers); ++ print $this->server_payload; ++ } ++ ++ /** ++ * Generates the payload and puts it in the $server_payload property ++ * ++ * @return void ++ * ++ * @uses XML_RPC_Server::parseRequest(), XML_RPC_Server::$encoding, ++ * XML_RPC_Response::serialize(), XML_RPC_Server::serializeDebug() ++ */ ++ function createServerPayload() ++ { ++ $r = $this->parseRequest(); ++ $this->server_payload = 'encoding . '"?>' . "\n" ++ . $this->serializeDebug() ++ . $r->serialize(); ++ } ++ ++ /** ++ * Determines the HTTP headers and puts them in the $server_headers ++ * property ++ * ++ * @return boolean TRUE if okay, FALSE if $server_payload isn't set. ++ * ++ * @uses XML_RPC_Server::createServerPayload(), ++ * XML_RPC_Server::$server_headers ++ */ ++ function createServerHeaders() ++ { ++ if (!$this->server_payload) { ++ return false; ++ } ++ $this->server_headers = 'Content-Length: ' ++ . strlen($this->server_payload) . "\r\n" ++ . 'Content-Type: text/xml;' ++ . ' charset=' . $this->encoding; ++ return true; ++ } ++ ++ /** ++ * @return array ++ */ ++ function verifySignature($in, $sig) ++ { ++ for ($i = 0; $i < sizeof($sig); $i++) { ++ // check each possible signature in turn ++ $cursig = $sig[$i]; ++ if (sizeof($cursig) == $in->getNumParams() + 1) { ++ $itsOK = 1; ++ for ($n = 0; $n < $in->getNumParams(); $n++) { ++ $p = $in->getParam($n); ++ // print "\n"; ++ if ($p->kindOf() == 'scalar') { ++ $pt = $p->scalartyp(); ++ } else { ++ $pt = $p->kindOf(); ++ } ++ // $n+1 as first type of sig is return type ++ if ($pt != $cursig[$n+1]) { ++ $itsOK = 0; ++ $pno = $n+1; ++ $wanted = $cursig[$n+1]; ++ $got = $pt; ++ break; ++ } ++ } ++ if ($itsOK) { ++ return array(1); ++ } ++ } ++ } ++ if (isset($wanted)) { ++ return array(0, "Wanted ${wanted}, got ${got} at param ${pno}"); ++ } else { ++ $allowed = array(); ++ foreach ($sig as $val) { ++ end($val); ++ $allowed[] = key($val); ++ } ++ $allowed = array_unique($allowed); ++ $last = count($allowed) - 1; ++ if ($last > 0) { ++ $allowed[$last] = 'or ' . $allowed[$last]; ++ } ++ return array(0, ++ 'Signature permits ' . implode(', ', $allowed) ++ . ' parameters but the request had ' ++ . $in->getNumParams()); ++ } ++ } ++ ++ /** ++ * @return object a new XML_RPC_Response object ++ * ++ * @uses XML_RPC_Message::getEncoding(), XML_RPC_Server::$encoding ++ */ ++ function parseRequest($data = '') ++ { ++ global $XML_RPC_xh, $HTTP_RAW_POST_DATA, ++ $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml, ++ $XML_RPC_defencoding, $XML_RPC_Server_dmap; ++ ++ if ($data == '') { ++ $data = $HTTP_RAW_POST_DATA; ++ } ++ ++ $this->encoding = XML_RPC_Message::getEncoding($data); ++ $parser_resource = xml_parser_create($this->encoding); ++ $parser = (int) $parser_resource; ++ ++ $XML_RPC_xh[$parser] = array(); ++ $XML_RPC_xh[$parser]['cm'] = 0; ++ $XML_RPC_xh[$parser]['isf'] = 0; ++ $XML_RPC_xh[$parser]['params'] = array(); ++ $XML_RPC_xh[$parser]['method'] = ''; ++ $XML_RPC_xh[$parser]['stack'] = array(); ++ $XML_RPC_xh[$parser]['valuestack'] = array(); ++ ++ $plist = ''; ++ ++ // decompose incoming XML into request structure ++ ++ xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true); ++ xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee'); ++ xml_set_character_data_handler($parser_resource, 'XML_RPC_cd'); ++ if (!xml_parse($parser_resource, $data, 1)) { ++ // return XML error as a faultCode ++ $r = new XML_RPC_Response(0, ++ $XML_RPC_errxml+xml_get_error_code($parser_resource), ++ sprintf('XML error: %s at line %d', ++ xml_error_string(xml_get_error_code($parser_resource)), ++ xml_get_current_line_number($parser_resource))); ++ xml_parser_free($parser_resource); ++ } elseif ($XML_RPC_xh[$parser]['isf']>1) { ++ $r = new XML_RPC_Response(0, ++ $XML_RPC_err['invalid_request'], ++ $XML_RPC_str['invalid_request'] ++ . ': ' ++ . $XML_RPC_xh[$parser]['isf_reason']); ++ xml_parser_free($parser_resource); ++ } else { ++ xml_parser_free($parser_resource); ++ $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']); ++ // now add parameters in ++ for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) { ++ // print '\n"; ++ $plist .= "$i - " . var_export($XML_RPC_xh[$parser]['params'][$i], true) . " \n"; ++ $m->addParam($XML_RPC_xh[$parser]['params'][$i]); ++ } ++ XML_RPC_Server_debugmsg($plist); ++ ++ // now to deal with the method ++ $methName = $XML_RPC_xh[$parser]['method']; ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $this->dmap; ++ $sysCall = 0; ++ } ++ ++ if (isset($dmap[$methName]['function']) ++ && is_string($dmap[$methName]['function']) ++ && strpos($dmap[$methName]['function'], '::') !== false) ++ { ++ $dmap[$methName]['function'] = ++ explode('::', $dmap[$methName]['function']); ++ } ++ ++ if (isset($dmap[$methName]['function']) ++ && is_callable($dmap[$methName]['function'])) ++ { ++ // dispatch if exists ++ if (isset($dmap[$methName]['signature'])) { ++ $sr = $this->verifySignature($m, ++ $dmap[$methName]['signature'] ); ++ } ++ if (!isset($dmap[$methName]['signature']) || $sr[0]) { ++ // if no signature or correct signature ++ if ($sysCall) { ++ $r = call_user_func($dmap[$methName]['function'], $this, $m); ++ } else { ++ $r = call_user_func($dmap[$methName]['function'], $m); ++ } ++ if (!is_a($r, 'XML_RPC_Response')) { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['not_response_object'], ++ $XML_RPC_str['not_response_object']); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], ++ $XML_RPC_str['incorrect_params'] ++ . ': ' . $sr[1]); ++ } ++ } else { ++ // else prepare error response ++ $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'], ++ $XML_RPC_str['unknown_method']); ++ } ++ } ++ return $r; ++ } ++ ++ /** ++ * Echos back the input packet as a string value ++ * ++ * @return void ++ * ++ * Useful for debugging. ++ */ ++ function echoInput() ++ { ++ global $HTTP_RAW_POST_DATA; ++ ++ $r = new XML_RPC_Response(0); ++ $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); ++ print $r->serialize(); ++ } ++} ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * c-hanging-comment-ender-p: nil ++ * End: ++ */ ++ ++?> ++package.xml100666 0 0 25606 10277724746 6300 ++ ++ ++ XML_RPC ++ PHP implementation of the XML-RPC protocol ++ A PEAR-ified version of Useful Inc's XML-RPC for PHP. ++ ++It has support for HTTP/HTTPS transport, proxies and authentication. ++ ++ ++ ++ ssb ++ Stig Bakken ++ stig@php.net ++ lead ++ ++ ++ danielc ++ Daniel Convissor ++ danielc@php.net ++ lead ++ ++ ++ ++ 1.4.0 ++ 2005-08-14 ++ PHP License ++ stable ++ * MAJOR SECURITY FIX: eliminate use of eval(). ++* Using socket_get_status() because stream_get_meta_data() was introduced in 4.3.0, but we need to support 4.2.0. Bug 4805. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 1.3.3 ++ 2005-07-15 ++ stable ++ * Eliminate memory leak by resetting $XML_RPC_xh each time parseResponse() is called. Bug 4780. ++* Using socket_set_timeout() because stream_set_timeout() was introduced in 4.3.0, but we need to support 4.2.0. Bug 4805. ++ ++ ++ ++ 1.3.2 ++ 2005-07-07 ++ stable ++ * Eliminate path disclosure vulnerabilities by suppressing error messages when eval()'ing. ++* Eliminate path disclosure vulnerability by catching bogus parameters submitted to XML_RPC_Value::serializeval(). ++* In XML_RPC_Server::service(), only call createServerPayload() and createServerHeaders() if necessary. Fixes compatibility issue introduced in Release 1.3.0RC1 for users who set the $serviceNow parameter of XML_RPC_Server() to 0. Bug 4757. ++* Change "var $errstring" to "var $errstr". Bug 4582. Was put into CVS version 1.75 of RPC.php but didn't make it into RELEASE_1_3_1. ++ ++ ++ ++ 1.3.1 ++ 2005-06-29 ++ stable ++ * Security fix. Update highly recommended! ++ ++ ++ ++ 1.3.0 ++ 2005-06-13 ++ stable ++ * Stable release. See earlier releases for changes since 1.2.2. ++ ++ ++ ++ 1.3.0RC3 ++ 2005-05-10 ++ beta ++ * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. ++* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. ++* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. ++* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. ++* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). ++* Use <br /> instead of <br> in XML_RPC_Value::dump(). ++ ++ ++ ++ 1.3.0RC2 ++ 2005-05-05 ++ beta ++ * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. ++* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. ++* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. ++* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. ++ ++ ++ ++ 1.3.0RC1 ++ 2005-04-07 ++ beta ++ * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. ++* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. ++* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. ++* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. ++* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. ++* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. ++ ++ ++ ++ 1.2.2 ++ 2005-03-07 ++ stable ++ * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. ++ ++ ++ ++ 1.2.1 ++ 2005-03-01 ++ stable ++ * Add isset() check before examining the dispatch map. Bug 3658. ++ ++ ++ ++ 1.2.0 ++ 2005-02-27 ++ stable ++ * Provide the "stable" release. ++* Add package2.xml for compatibility with PEAR 1.4.0. ++* For changes since 1.1.0, see the changelogs for the various RC releases. ++ ++ ++ ++ 1.2.0RC7 ++ 2005-02-22 ++ beta ++ * Add the setSendEncoding() method and $send_encoding ++ property to XML_RPC_Message. Request 3537. ++* Allow class methods to be mapped using either syntax: ++ 'function' => 'hello::sayHello', ++ or ++ 'function' => array('hello', 'sayhello'), ++ Bug 3363. ++* Use 8192 instead of 32768 for bytes in fread() ++ in parseResponseFile(). Bug 3340. ++ ++ ++ ++ 1.2.0RC6 ++ 2005-01-25 ++ beta ++ * Don't put the protocol in the Host field of the POST data. (danielc) ++ ++ ++ ++ 1.2.0RC5 ++ 2005-01-24 ++ beta ++ * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. ++ ++ ++ ++ 1.2.0RC4 ++ 2005-01-24 ++ beta ++ * When a connection attempt fails, have the method return 0. (danielc) ++* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) ++* Add tests for setting the client properties. (danielc) ++* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) ++* Bundle the tests with the package. (danielc) ++ ++ ++ ++ 1.2.0RC3 ++ 2005-01-19 ++ beta ++ * ssl uses port 443, not 445. ++ ++ ++ ++ 1.2.0RC2 ++ 2005-01-11 ++ beta ++ * Handle ssl:// in the $server string. (danielc) ++* Also default to port 445 for ssl:// requests as well. (danielc) ++* Enhance debugging in the server. (danielc) ++ ++ ++ ++ 1.2.0RC1 ++ 2004-12-30 ++ beta ++ * Make things work with SSL. Bug 2489. (nkukard lbsd net) ++* Allow array function callbacks (Matt Kane) ++* Some minor speed-ups (Matt Kane) ++* Add Dump.php to the package (Christian Weiske) ++* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) ++* Silence fsockopen() errors. Bug 1714. (danielc) ++* Encode empty arrays as an array. Bug 1493. (danielc) ++* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) ++* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) ++* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) ++* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) ++* Allow raiseError() to be called statically. (danielc) ++* Stop double escaping of character entities. Bug 987. (danielc) ++ NOTICE: the following have been removed: ++ * XML_RPC_dh() ++ * $GLOBALS['XML_RPC_entities'] ++ * XML_RPC_entity_decode() ++ * XML_RPC_lookup_entity() ++* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) ++ ++ ++ ++ 1.1.0 ++ 2004-03-15 ++ stable ++ * Added support for sequential arrays to XML_RPC_encode() (mroch) ++* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) ++* Remove "require_once 'PEAR.php'", include only when needed to raise an error ++* Replace echo and error_log() with raiseError() (mroch) ++* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) ++* be tolerant of junk after methodResponse (Luca Mariano, mroch) ++* Silent notice even in the error log (pierre) ++* fix include of shared xml extension on win32 (pierre) ++ ++ ++ ++ 1.0.4 ++ 2002-10-02 ++ stable ++ * added HTTP proxy authorization support (thanks to Arnaud Limbourg) ++ ++ ++ ++ 1.0.3 ++ 2002-05-19 ++ stable ++ * fix bug when parsing responses with boolean types ++ ++ ++ ++ 1.0.2 ++ 2002-04-16 ++ stable ++ * E_ALL fixes ++* fix HTTP response header parsing ++ ++ ++ ++ 1.0.1 ++ 2001-09-25 ++ stable ++ This is a PEAR-ified version of Useful Inc's 1.0.1 release. ++Includes an urgent security fix identified by Dan Libby <dan@libby.com>. ++ ++ ++ ++ ++ +\ Kein Zeilenumbruch am Dateiende. +diff -Nura php-4.3.11/php.ini-dist hardening-patch-4.3.11-0.4.2/php.ini-dist +--- php-4.3.11/php.ini-dist 2005-02-14 09:26:10.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/php.ini-dist 2005-09-07 18:41:01.008095656 +0200 +@@ -1109,6 +1109,185 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's Executor options ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++; White-/blacklist for function calls during normal execution ++;hphp.executor.func.whitelist = ord,chr ++;hphp.executor.func.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for function calls during eval() execution ++;hphp.executor.eval.whitelist = ord,chr ++;hphp.executor.eval.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nura php-4.3.11/php.ini-recommended hardening-patch-4.3.11-0.4.2/php.ini-recommended +--- php-4.3.11/php.ini-recommended 2005-02-14 09:26:10.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/php.ini-recommended 2005-09-07 18:41:01.009095504 +0200 +@@ -1107,6 +1107,185 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's Executor options ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++; White-/blacklist for function calls during normal execution ++;hphp.executor.func.whitelist = ord,chr ++;hphp.executor.func.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for function calls during eval() execution ++;hphp.executor.eval.whitelist = ord,chr ++;hphp.executor.eval.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nura php-4.3.11/README.input_filter hardening-patch-4.3.11-0.4.2/README.input_filter +--- php-4.3.11/README.input_filter 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/README.input_filter 2005-09-07 18:41:01.010095352 +0200 +@@ -0,0 +1,193 @@ ++Input Filter Support ported from PHP 5 ++-------------------------------------- ++ ++XSS (Cross Site Scripting) hacks are becoming more and more prevalent, ++and can be quite difficult to prevent. Whenever you accept user data ++and somehow display this data back to users, you are likely vulnerable ++to XSS hacks. ++ ++The Input Filter support in PHP 5 is aimed at providing the framework ++through which a company-wide or site-wide security policy can be ++enforced. It is implemented as a SAPI hook and is called from the ++treat_data and post handler functions. To implement your own security ++policy you will need to write a standard PHP extension. ++ ++A simple implementation might look like the following. This stores the ++original raw user data and adds a my_get_raw() function while the normal ++$_POST, $_GET and $_COOKIE arrays are only populated with stripped ++data. In this simple example all I am doing is calling strip_tags() on ++the data. If register_globals is turned on, the default globals that ++are created will be stripped ($foo) while a $RAW_foo is created with the ++original user input. ++ ++ZEND_BEGIN_MODULE_GLOBALS(my_input_filter) ++ zval *post_array; ++ zval *get_array; ++ zval *cookie_array; ++ZEND_END_MODULE_GLOBALS(my_input_filter) ++ ++#ifdef ZTS ++#define IF_G(v) TSRMG(my_input_filter_globals_id, zend_my_input_filter_globals *, v) ++#else ++#define IF_G(v) (my_input_filter_globals.v) ++#endif ++ ++ZEND_DECLARE_MODULE_GLOBALS(my_input_filter) ++ ++function_entry my_input_filter_functions[] = { ++ PHP_FE(my_get_raw, NULL) ++ {NULL, NULL, NULL} ++}; ++ ++zend_module_entry my_input_filter_module_entry = { ++ STANDARD_MODULE_HEADER, ++ "my_input_filter", ++ my_input_filter_functions, ++ PHP_MINIT(my_input_filter), ++ PHP_MSHUTDOWN(my_input_filter), ++ NULL, ++ PHP_RSHUTDOWN(my_input_filter), ++ PHP_MINFO(my_input_filter), ++ "0.1", ++ STANDARD_MODULE_PROPERTIES ++}; ++ ++PHP_MINIT_FUNCTION(my_input_filter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(my_input_filter, php_my_input_filter_init_globals, NULL); ++ ++ REGISTER_LONG_CONSTANT("POST", PARSE_POST, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("GET", PARSE_GET, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("COOKIE", PARSE_COOKIE, CONST_CS | CONST_PERSISTENT); ++ ++ sapi_register_input_filter(my_sapi_input_filter); ++ return SUCCESS; ++} ++ ++PHP_RSHUTDOWN_FUNCTION(my_input_filter) ++{ ++ if(IF_G(get_array)) { ++ zval_ptr_dtor(&IF_G(get_array)); ++ IF_G(get_array) = NULL; ++ } ++ if(IF_G(post_array)) { ++ zval_ptr_dtor(&IF_G(post_array)); ++ IF_G(post_array) = NULL; ++ } ++ if(IF_G(cookie_array)) { ++ zval_ptr_dtor(&IF_G(cookie_array)); ++ IF_G(cookie_array) = NULL; ++ } ++ return SUCCESS; ++} ++ ++PHP_MINFO_FUNCTION(my_input_filter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_row( 2, "My Input Filter Support", "enabled" ); ++ php_info_print_table_row( 2, "Revision", "$Revision: 1.1 $"); ++ php_info_print_table_end(); ++} ++ ++/* The filter handler. If you return 1 from it, then PHP also registers the ++ * (modified) variable. Returning 0 prevents PHP from registering the variable; ++ * you can use this if your filter already registers the variable under a ++ * different name, or if you just don't want the variable registered at all. */ ++SAPI_INPUT_FILTER_FUNC(my_sapi_input_filter) ++{ ++ zval new_var; ++ zval *array_ptr = NULL; ++ char *raw_var; ++ int var_len; ++ ++ assert(*val != NULL); ++ ++ switch(arg) { ++ case PARSE_GET: ++ if(!IF_G(get_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(get_array) = array_ptr; ++ break; ++ case PARSE_POST: ++ if(!IF_G(post_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(post_array) = array_ptr; ++ break; ++ case PARSE_COOKIE: ++ if(!IF_G(cookie_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(cookie_array) = array_ptr; ++ break; ++ } ++ Z_STRLEN(new_var) = val_len; ++ Z_STRVAL(new_var) = estrndup(*val, val_len); ++ Z_TYPE(new_var) = IS_STRING; ++ ++ var_len = strlen(var); ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ ++ php_register_variable_ex(raw_var, &new_var, array_ptr TSRMLS_DC); ++ ++ php_strip_tags(*val, val_len, NULL, NULL, 0); ++ ++ *new_val_len = strlen(*val); ++ return 1; ++} ++ ++PHP_FUNCTION(my_get_raw) ++{ ++ long arg; ++ char *var; ++ int var_len; ++ zval **tmp; ++ zval *array_ptr = NULL; ++ HashTable *hash_ptr; ++ char *raw_var; ++ ++ if(zend_parse_parameters(2 TSRMLS_CC, "ls", &arg, &var, &var_len) == FAILURE) { ++ return; ++ } ++ ++ switch(arg) { ++ case PARSE_GET: ++ array_ptr = IF_G(get_array); ++ break; ++ case PARSE_POST: ++ array_ptr = IF_G(post_array); ++ break; ++ case PARSE_COOKIE: ++ array_ptr = IF_G(post_array); ++ break; ++ } ++ ++ if(!array_ptr) RETURN_FALSE; ++ ++ /* ++ * I'm changing the variable name here because when running with register_globals on, ++ * the variable will end up in the global symbol table ++ */ ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ hash_ptr = HASH_OF(array_ptr); ++ ++ if(zend_hash_find(hash_ptr, raw_var, var_len+5, (void **)&tmp) == SUCCESS) { ++ *return_value = **tmp; ++ zval_copy_ctor(return_value); ++ } else { ++ RETVAL_FALSE; ++ } ++ efree(raw_var); ++} ++ +diff -Nura php-4.3.11/sapi/apache/mod_php4.c hardening-patch-4.3.11-0.4.2/sapi/apache/mod_php4.c +--- php-4.3.11/sapi/apache/mod_php4.c 2004-07-21 18:25:28.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/sapi/apache/mod_php4.c 2005-09-07 18:41:01.010095352 +0200 +@@ -446,7 +446,7 @@ + sapi_apache_get_fd, + sapi_apache_force_http_10, + sapi_apache_get_target_uid, +- sapi_apache_get_target_gid ++ sapi_apache_get_target_gid, + }; + /* }}} */ + +@@ -892,7 +892,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component("PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component("PHP/" PHP_VERSION); ++#endif + } + } + #endif +diff -Nura php-4.3.11/sapi/apache2filter/sapi_apache2.c hardening-patch-4.3.11-0.4.2/sapi/apache2filter/sapi_apache2.c +--- php-4.3.11/sapi/apache2filter/sapi_apache2.c 2005-01-07 07:28:36.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/sapi/apache2filter/sapi_apache2.c 2005-09-07 18:41:01.011095200 +0200 +@@ -563,7 +563,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nura php-4.3.11/sapi/apache2handler/sapi_apache2.c hardening-patch-4.3.11-0.4.2/sapi/apache2handler/sapi_apache2.c +--- php-4.3.11/sapi/apache2handler/sapi_apache2.c 2005-03-10 12:39:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/sapi/apache2handler/sapi_apache2.c 2005-09-07 18:41:01.011095200 +0200 +@@ -345,7 +345,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nura php-4.3.11/sapi/cgi/cgi_main.c hardening-patch-4.3.11-0.4.2/sapi/cgi/cgi_main.c +--- php-4.3.11/sapi/cgi/cgi_main.c 2005-02-11 03:12:30.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/sapi/cgi/cgi_main.c 2005-09-07 18:41:01.012095048 +0200 +@@ -1435,11 +1435,19 @@ + SG(headers_sent) = 1; + SG(request_info).no_headers = 1; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit(1); + break; +diff -Nura php-4.3.11/sapi/cli/php_cli.c hardening-patch-4.3.11-0.4.2/sapi/cli/php_cli.c +--- php-4.3.11/sapi/cli/php_cli.c 2005-03-22 16:09:36.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/sapi/cli/php_cli.c 2005-09-07 18:41:01.013094896 +0200 +@@ -652,11 +652,19 @@ + if (php_request_startup(TSRMLS_C)==FAILURE) { + goto err; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit_status=1; + goto out; +diff -Nura php-4.3.11/TSRM/TSRM.h hardening-patch-4.3.11-0.4.2/TSRM/TSRM.h +--- php-4.3.11/TSRM/TSRM.h 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/TSRM/TSRM.h 2005-09-07 18:41:01.014094744 +0200 +@@ -33,6 +33,13 @@ + # define TSRM_API + #endif + ++#if HARDENING_PATCH ++# if HAVE_REALPATH ++# undef realpath ++# define realpath php_realpath ++# endif ++#endif ++ + /* Only compile multi-threading functions if we're in ZTS mode */ + #ifdef ZTS + +@@ -90,6 +97,7 @@ + + #define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts + ++ + #ifdef __cplusplus + extern "C" { + #endif +diff -Nura php-4.3.11/TSRM/tsrm_virtual_cwd.c hardening-patch-4.3.11-0.4.2/TSRM/tsrm_virtual_cwd.c +--- php-4.3.11/TSRM/tsrm_virtual_cwd.c 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/TSRM/tsrm_virtual_cwd.c 2005-09-07 18:41:01.014094744 +0200 +@@ -192,6 +192,165 @@ + return p; + } + ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved) ++{ ++ struct stat sb; ++ char *p, *q, *s; ++ size_t left_len, resolved_len; ++ unsigned symlinks; ++ int serrno, slen; ++ int is_dir = 1; ++ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; ++ ++ serrno = errno; ++ symlinks = 0; ++ if (path[0] == '/') { ++ resolved[0] = '/'; ++ resolved[1] = '\0'; ++ if (path[1] == '\0') ++ return (resolved); ++ resolved_len = 1; ++ left_len = strlcpy(left, path + 1, sizeof(left)); ++ } else { ++ if (getcwd(resolved, PATH_MAX) == NULL) { ++ strlcpy(resolved, ".", PATH_MAX); ++ return (NULL); ++ } ++ resolved_len = strlen(resolved); ++ left_len = strlcpy(left, path, sizeof(left)); ++ } ++ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ ++ /* ++ * Iterate over path components in `left'. ++ */ ++ while (left_len != 0) { ++ /* ++ * Extract the next path component and adjust `left' ++ * and its length. ++ */ ++ p = strchr(left, '/'); ++ s = p ? p : left + left_len; ++ if (s - left >= sizeof(next_token)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ memcpy(next_token, left, s - left); ++ next_token[s - left] = '\0'; ++ left_len -= s - left; ++ if (p != NULL) ++ memmove(left, s + 1, left_len + 1); ++ if (resolved[resolved_len - 1] != '/') { ++ if (resolved_len + 1 >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ resolved[resolved_len++] = '/'; ++ resolved[resolved_len] = '\0'; ++ } ++ if (next_token[0] == '\0') ++ continue; ++ else if (strcmp(next_token, ".") == 0) ++ continue; ++ else if (strcmp(next_token, "..") == 0) { ++ /* ++ * Strip the last path component except when we have ++ * single "/" ++ */ ++ if (!is_dir) { ++ errno = ENOENT; ++ return (NULL); ++ } ++ if (resolved_len > 1) { ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ continue; ++ } ++ ++ /* ++ * Append the next path component and lstat() it. If ++ * lstat() fails we still can return successfully if ++ * there are no more path components left. ++ */ ++ resolved_len = strlcat(resolved, next_token, PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ if (lstat(resolved, &sb) != 0) { ++ if (errno == ENOENT && p == NULL) { ++ errno = serrno; ++ return (resolved); ++ } ++ return (NULL); ++ } ++ if (S_ISLNK(sb.st_mode)) { ++ if (symlinks++ > MAXSYMLINKS) { ++ errno = ELOOP; ++ return (NULL); ++ } ++ slen = readlink(resolved, symlink, sizeof(symlink) - 1); ++ if (slen < 0) ++ return (NULL); ++ symlink[slen] = '\0'; ++ if (symlink[0] == '/') { ++ resolved[1] = 0; ++ resolved_len = 1; ++ } else if (resolved_len > 1) { ++ /* Strip the last path component. */ ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ ++ /* ++ * If there are any path components left, then ++ * append them to symlink. The result is placed ++ * in `left'. ++ */ ++ if (p != NULL) { ++ if (symlink[slen - 1] != '/') { ++ if (slen + 1 >= sizeof(symlink)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ symlink[slen] = '/'; ++ symlink[slen + 1] = 0; ++ } ++ left_len = strlcat(symlink, left, sizeof(left)); ++ if (left_len >= sizeof(left)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ } ++ left_len = strlcpy(left, symlink, sizeof(left)); ++ } else { ++ if (S_ISDIR(sb.st_mode)) { ++ is_dir = 1; ++ } else { ++ is_dir = 0; ++ } ++ } ++ } ++ ++ /* ++ * Remove trailing slash except when the resolved pathname ++ * is a single "/". ++ */ ++ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') ++ resolved[resolved_len - 1] = '\0'; ++ return (resolved); ++} ++#endif ++ + CWD_API void virtual_cwd_startup(void) + { + char cwd[MAXPATHLEN]; +@@ -314,8 +473,7 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now +- return 1; */ ++ return 1; + } + } + } else { /* Concat current directory with relative path and then run realpath() on it */ +@@ -341,9 +499,8 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now + free(tmp); +- return 1; */ ++ return 1; + } + } + free(tmp); +diff -Nura php-4.3.11/TSRM/tsrm_virtual_cwd.h hardening-patch-4.3.11-0.4.2/TSRM/tsrm_virtual_cwd.h +--- php-4.3.11/TSRM/tsrm_virtual_cwd.h 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/TSRM/tsrm_virtual_cwd.h 2005-09-07 18:41:01.015094592 +0200 +@@ -128,6 +128,22 @@ + + typedef int (*verify_path_func)(const cwd_state *); + ++#ifndef HAVE_STRLCPY ++CWD_API size_t php_strlcpy(char *dst, const char *src, size_t siz); ++#undef strlcpy ++#define strlcpy php_strlcpy ++#endif ++ ++#ifndef HAVE_STRLCAT ++CWD_API size_t php_strlcat(char *dst, const char *src, size_t siz); ++#undef strlcat ++#define strlcat php_strlcat ++#endif ++ ++ ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved); ++#endif + CWD_API void virtual_cwd_startup(void); + CWD_API void virtual_cwd_shutdown(void); + CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC); +diff -Nura php-4.3.11/Zend/zend_alloc.c hardening-patch-4.3.11-0.4.2/Zend/zend_alloc.c +--- php-4.3.11/Zend/zend_alloc.c 2004-08-27 18:51:25.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_alloc.c 2005-09-07 18:41:01.016094440 +0200 +@@ -56,6 +56,11 @@ + # define END_MAGIC_SIZE 0 + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++# define CANARY_SIZE sizeof(unsigned int) ++#else ++# define CANARY_SIZE 0 ++#endif + + # if MEMORY_LIMIT + # if ZEND_DEBUG +@@ -95,9 +100,17 @@ + if (p==AG(head)) { \ + AG(head) = p->pNext; \ + } else { \ ++ if (p != p->pLast->pNext) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pLast->pNext = p->pNext; \ + } \ + if (p->pNext) { \ ++ if (p != p->pNext->pLast) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pNext->pLast = p->pLast; \ + } + +@@ -129,6 +142,12 @@ + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (size > LONG_MAX - sizeof(zend_mem_header) - MEM_HEADER_PADDING - END_MAGIC_SIZE - CANARY_SIZE) { ++ zend_security_log(S_MEMORY, "emalloc() - requested size would result in integer overflow"); ++ exit(1); ++ } ++#endif + CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size); + + if (!ZEND_DISABLE_MEMORY_CACHE && (CACHE_INDEX < MAX_CACHED_MEMORY) && (AG(cache_count)[CACHE_INDEX] > 0)) { +@@ -146,6 +165,10 @@ + AG(cache_stats)[CACHE_INDEX][1]++; + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->cached = 0; + p->size = size; + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); +@@ -161,7 +184,7 @@ + AG(allocated_memory_peak) = AG(allocated_memory); + } + #endif +- p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE + CANARY_SIZE); + } + + HANDLE_BLOCK_INTERRUPTIONS(); +@@ -191,7 +214,10 @@ + # endif + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif +- ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); + } +@@ -218,17 +244,36 @@ + return emalloc_rel(lval + offset); + } + } +- ++ ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by safe_emalloc()"); ++#endif + zend_error(E_ERROR, "Possible integer overflow in memory allocation (%ld * %ld + %ld)", nmemb, size, offset); + return 0; + } + + ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p = (zend_mem_header *) ((char *)ptr - sizeof(zend_mem_header) - MEM_HEADER_PADDING); + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (p->canary != HG(canary_1)) goto efree_canary_mismatch; ++ memcpy(&canary_2, (((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), CANARY_SIZE); ++ if (canary_2 != HG(canary_2)) { ++efree_canary_mismatch: ++ zend_security_log(S_MEMORY, "canary mismatch on efree() - heap overflow or double efree detected"); ++ exit(1); ++ } ++ /* to catch double efree()s */ ++ memset((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), 0, CANARY_SIZE); ++ p->canary = 0; ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + tsrm_error(TSRM_ERROR_LEVEL_ERROR, "Memory block allocated at %s:(%d) on thread %x freed at %s:(%d) on thread %x, ignoring", +@@ -273,6 +318,9 @@ + size_t _size = nmemb * size; + + if (nmemb && (_size/nmemb!=size)) { ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by ecalloc()"); ++#endif + fprintf(stderr,"FATAL: ecalloc(): Unable to allocate %ld * %ld bytes\n", (long) nmemb, (long) size); + #if ZEND_DEBUG && HAVE_KILL && HAVE_GETPID + kill(getpid(), SIGSEGV); +@@ -292,6 +340,9 @@ + + ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p; + zend_mem_header *orig; + DECLARE_CACHE_VARS(); +@@ -303,6 +354,16 @@ + + p = orig = (zend_mem_header *) ((char *)ptr-sizeof(zend_mem_header)-MEM_HEADER_PADDING); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (p->canary != HG(canary_1)) goto erealloc_canary_mismatch; ++ memcpy(&canary_2, (((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), CANARY_SIZE); ++ if (canary_2 != HG(canary_2)) { ++erealloc_canary_mismatch: ++ zend_security_log(S_MEMORY, "canary mismatch on erealloc() - heap overflow detected"); ++ exit(1); ++ } ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + void *new_p; +@@ -326,7 +387,7 @@ + } + #endif + REMOVE_POINTER_FROM_LIST(p); +- p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE+CANARY_SIZE); + if (!p) { + if (!allow_failure) { + fprintf(stderr,"FATAL: erealloc(): Unable to allocate %ld bytes\n", (long) size); +@@ -348,6 +409,9 @@ + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->size = size; + + HANDLE_UNBLOCK_INTERRUPTIONS(); +@@ -423,6 +487,10 @@ + { + AG(head) = NULL; + ++#if HARDENING_PATCH_MM_PROTECT ++ HG(canary_1) = zend_canary(); ++ HG(canary_2) = zend_canary(); ++#endif + #if MEMORY_LIMIT + AG(memory_limit) = 1<<30; /* ridiculous limit, effectively no limit */ + AG(allocated_memory) = 0; +diff -Nura php-4.3.11/Zend/zend_alloc.h hardening-patch-4.3.11-0.4.2/Zend/zend_alloc.h +--- php-4.3.11/Zend/zend_alloc.h 2004-08-11 08:10:46.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_alloc.h 2005-09-07 18:41:01.016094440 +0200 +@@ -32,6 +32,9 @@ + #define MEM_BLOCK_CACHED_MAGIC 0xFB8277DCL + + typedef struct _zend_mem_header { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary; ++#endif + #if ZEND_DEBUG + long magic; + char *filename; +diff -Nura php-4.3.11/Zend/zend_builtin_functions.c hardening-patch-4.3.11-0.4.2/Zend/zend_builtin_functions.c +--- php-4.3.11/Zend/zend_builtin_functions.c 2004-12-27 20:28:35.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_builtin_functions.c 2005-09-07 18:41:01.017094288 +0200 +@@ -49,6 +49,9 @@ + static ZEND_FUNCTION(crash); + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++static ZEND_FUNCTION(heap_overflow); ++#endif + static ZEND_FUNCTION(get_included_files); + static ZEND_FUNCTION(is_subclass_of); + static ZEND_FUNCTION(is_a); +@@ -101,6 +104,9 @@ + ZEND_FE(crash, NULL) + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ ZEND_FE(heap_overflow, NULL) ++#endif + ZEND_FE(get_included_files, NULL) + ZEND_FALIAS(get_required_files, get_included_files, NULL) + ZEND_FE(is_subclass_of, NULL) +@@ -805,6 +811,19 @@ + + #endif /* ZEND_DEBUG */ + ++ ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ZEND_FUNCTION(heap_overflow) ++{ ++ char *nowhere = emalloc(10); ++ ++ memcpy(nowhere, "something1234567890", sizeof("something1234567890")); ++ ++ efree(nowhere); ++} ++#endif ++ ++ + /* {{{ proto array get_included_files(void) + Returns an array with the file names that were include_once()'d */ + ZEND_FUNCTION(get_included_files) +diff -Nura php-4.3.11/Zend/zend.c hardening-patch-4.3.11-0.4.2/Zend/zend.c +--- php-4.3.11/Zend/zend.c 2005-01-22 21:36:34.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend.c 2005-09-07 19:04:56.247906040 +0200 +@@ -53,6 +53,12 @@ + ZEND_API void (*zend_unblock_interruptions)(void); + ZEND_API void (*zend_ticks_function)(int ticks); + ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); ++#if HARDENING_PATCH ++ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + + void (*zend_on_timeout)(int seconds TSRMLS_DC); + +@@ -70,9 +76,289 @@ + return SUCCESS; + } + ++#if HARDENING_PATCH ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog) = S_ALL & ~S_SQL | S_MEMORY | S_INTERNAL; ++ } else { ++ EG(hphp_log_syslog) = atoi(new_value) | S_MEMORY | S_INTERNAL; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_facility) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_facility) = LOG_USER; ++ } else { ++ EG(hphp_log_syslog_facility) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_priority) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_priority) = LOG_ALERT; ++ } else { ++ EG(hphp_log_syslog_priority) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_sapi) ++{ ++ if (!new_value) { ++ EG(hphp_log_sapi) = S_ALL & ~S_SQL | S_INTERNAL; ++ } else { ++ EG(hphp_log_sapi) = atoi(new_value) | S_INTERNAL; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_script) ++{ ++ if (!new_value) { ++ EG(hphp_log_script) = S_ALL & (~S_MEMORY) & (~S_INTERNAL); ++ } else { ++ EG(hphp_log_script) = atoi(new_value) & (~S_MEMORY) & (~S_INTERNAL); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_scriptname) ++{ ++ if (!new_value) { ++ EG(hphp_log_scriptname) = NULL; ++ } else { ++ if (EG(hphp_log_scriptname)) { ++ pefree(EG(hphp_log_scriptname),1); ++ } ++ EG(hphp_log_scriptname) = pestrdup(new_value,1); ++ } ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_eval_whitelist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++eval_whitelist_destroy: ++ if (HG(eval_whitelist)) { ++ zend_hash_destroy(HG(eval_whitelist)); ++ efree(HG(eval_whitelist)); ++ } ++ HG(eval_whitelist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto eval_whitelist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(eval_whitelist)); ++ zend_hash_init(HG(eval_whitelist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(eval_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(eval_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_eval_blacklist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++eval_blacklist_destroy: ++ if (HG(eval_blacklist)) { ++ zend_hash_destroy(HG(eval_blacklist)); ++ efree(HG(eval_blacklist)); ++ } ++ HG(eval_blacklist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto eval_blacklist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(eval_blacklist)); ++ zend_hash_init(HG(eval_blacklist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(eval_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(eval_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_func_whitelist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++func_whitelist_destroy: ++ if (HG(func_whitelist)) { ++ zend_hash_destroy(HG(func_whitelist)); ++ efree(HG(func_whitelist)); ++ } ++ HG(func_whitelist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto func_whitelist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(func_whitelist)); ++ zend_hash_init(HG(func_whitelist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(func_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(func_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_func_blacklist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++func_blacklist_destroy: ++ if (HG(func_blacklist)) { ++ zend_hash_destroy(HG(func_blacklist)); ++ efree(HG(func_blacklist)); ++ } ++ HG(func_blacklist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto func_blacklist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(func_blacklist)); ++ zend_hash_init(HG(func_blacklist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(func_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(func_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ ++ return SUCCESS; ++} ++ ++#endif + + ZEND_INI_BEGIN() + ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) ++#if HARDENING_PATCH ++ ZEND_INI_ENTRY("hphp.log.syslog", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog) ++ ZEND_INI_ENTRY("hphp.log.syslog.facility", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_facility) ++ ZEND_INI_ENTRY("hphp.log.syslog.priority", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_priority) ++ ZEND_INI_ENTRY("hphp.log.sapi", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_sapi) ++ ZEND_INI_ENTRY("hphp.log.script", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_script) ++ ZEND_INI_ENTRY("hphp.log.script.name", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_scriptname) ++ STD_ZEND_INI_BOOLEAN("hphp.log.use-x-forwarded-for", "0", ZEND_INI_SYSTEM, OnUpdateBool, hphp_log_use_x_forwarded_for, zend_executor_globals, executor_globals) ++ ++ ZEND_INI_ENTRY("hphp.executor.eval.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_eval_whitelist) ++ ZEND_INI_ENTRY("hphp.executor.eval.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_eval_blacklist) ++ ZEND_INI_ENTRY("hphp.executor.func.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_func_whitelist) ++ ZEND_INI_ENTRY("hphp.executor.func.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_func_blacklist) ++ ++ STD_ZEND_INI_ENTRY("hphp.executor.max_depth", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateLong, hphp_executor_max_depth, zend_executor_globals, executor_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.sql.bailout_on_error", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, hphp_sql_bailout_on_error, hardened_globals_struct, hardened_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.multiheader", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, hphp_multiheader, hardened_globals_struct, hardened_globals) ++#endif + ZEND_INI_END() + + +@@ -354,6 +640,7 @@ + zend_init_rsrc_plist(TSRMLS_C); + EG(lambda_count)=0; + EG(user_error_handler) = NULL; ++ EG(in_code_type) = 0; + EG(in_execution) = 0; + EG(current_execute_data) = NULL; + } +@@ -420,6 +707,14 @@ + extern zend_scanner_globals language_scanner_globals; + #endif + ++ /* Set up Hardening-Patch utility functions first */ ++#if HARDENING_PATCH ++ zend_security_log = utility_functions->security_log_function; ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ zend_is_valid_include = utility_functions->is_valid_include; ++#endif ++ + #ifdef ZTS + ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); + #else +@@ -623,6 +918,7 @@ + } + CG(unclean_shutdown) = 1; + CG(in_compilation) = EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(current_execute_data) = NULL; + longjmp(EG(bailout), FAILURE); + } +diff -Nura php-4.3.11/Zend/zend_canary.c hardening-patch-4.3.11-0.4.2/Zend/zend_canary.c +--- php-4.3.11/Zend/zend_canary.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_canary.c 2005-09-07 18:41:01.019093984 +0200 +@@ -0,0 +1,58 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: zend_canary.c,v 1.1 2004/11/26 12:45:41 ionic Exp $ */ ++ ++#include "zend.h" ++ ++#include ++#include ++ ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++ZEND_API unsigned int zend_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-4.3.11/Zend/zend_compile.c hardening-patch-4.3.11-0.4.2/Zend/zend_compile.c +--- php-4.3.11/Zend/zend_compile.c 2004-12-30 16:22:52.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_compile.c 2005-09-07 18:41:01.020093832 +0200 +@@ -750,6 +750,13 @@ + op_array.function_name = name; + op_array.arg_types = NULL; + op_array.return_reference = return_reference; ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array.created_by_eval = 1; ++ } else { ++ op_array.created_by_eval = 0; ++ } ++#endif + + if (is_method) { + if (zend_hash_add(&CG(active_class_entry)->function_table, name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)) == FAILURE) { +diff -Nura php-4.3.11/Zend/zend_compile.h hardening-patch-4.3.11-0.4.2/Zend/zend_compile.h +--- php-4.3.11/Zend/zend_compile.h 2004-09-24 15:15:14.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_compile.h 2005-09-07 18:41:01.021093680 +0200 +@@ -106,6 +106,9 @@ + char *filename; + + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; ++#if HARDENING_PATCH ++ zend_bool created_by_eval; ++#endif + }; + + +@@ -546,6 +549,7 @@ + #define ZEND_USER_FUNCTION 2 + #define ZEND_OVERLOADED_FUNCTION 3 + #define ZEND_EVAL_CODE 4 ++#define ZEND_SANDBOX_CODE 6 + + #define ZEND_INTERNAL_CLASS 1 + #define ZEND_USER_CLASS 2 +diff -Nura php-4.3.11/Zend/zend_constants.c hardening-patch-4.3.11-0.4.2/Zend/zend_constants.c +--- php-4.3.11/Zend/zend_constants.c 2004-07-13 21:29:45.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_constants.c 2005-09-07 19:04:56.247906040 +0200 +@@ -111,6 +111,73 @@ + REGISTER_MAIN_LONG_CONSTANT("E_USER_NOTICE", E_USER_NOTICE, CONST_PERSISTENT | CONST_CS); + + REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("S_MEMORY", S_MEMORY, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_VARS", S_VARS, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_FILES", S_FILES, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INCLUDE", S_INCLUDE, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_SQL", S_SQL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_EXECUTOR", S_EXECUTOR, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_MISC", S_MISC, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INTERNAL", S_INTERNAL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_ALL", S_ALL, CONST_PERSISTENT | CONST_CS); ++ ++ /* error levels */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRIT", LOG_CRIT, CONST_CS | CONST_PERSISTENT); /* critical conditions */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ERR", LOG_ERR, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_WARNING", LOG_WARNING, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOTICE", LOG_NOTICE, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_INFO", LOG_INFO, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DEBUG", LOG_DEBUG, CONST_CS | CONST_PERSISTENT); ++ /* facility: type of program logging the message */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_KERN", LOG_KERN, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_USER", LOG_USER, CONST_CS | CONST_PERSISTENT); /* generic user level */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_MAIL", LOG_MAIL, CONST_CS | CONST_PERSISTENT); /* log to email */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DAEMON", LOG_DAEMON, CONST_CS | CONST_PERSISTENT); /* other system daemons */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTH", LOG_AUTH, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_SYSLOG", LOG_SYSLOG, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LPR", LOG_LPR, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NEWS ++ /* No LOG_NEWS on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NEWS", LOG_NEWS, CONST_CS | CONST_PERSISTENT); /* usenet new */ ++#endif ++#ifdef LOG_UUCP ++ /* No LOG_UUCP on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_UUCP", LOG_UUCP, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_CRON ++ /* apparently some systems don't have this one */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRON", LOG_CRON, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_AUTHPRIV ++ /* AIX doesn't have LOG_AUTHPRIV */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTHPRIV", LOG_AUTHPRIV, CONST_CS | CONST_PERSISTENT); ++#endif ++#if !defined(PHP_WIN32) && !defined(NETWARE) ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL0", LOG_LOCAL0, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL1", LOG_LOCAL1, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL2", LOG_LOCAL2, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL3", LOG_LOCAL3, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL4", LOG_LOCAL4, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL5", LOG_LOCAL5, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL6", LOG_LOCAL6, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL7", LOG_LOCAL7, CONST_CS | CONST_PERSISTENT); ++#endif ++ /* options */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PID", LOG_PID, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CONS", LOG_CONS, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ODELAY", LOG_ODELAY, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NDELAY", LOG_NDELAY, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NOWAIT ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOWAIT", LOG_NOWAIT, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_PERROR ++ /* AIX doesn't have LOG_PERROR */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ ++#endif ++#endif + + /* true/false constants */ + { +diff -Nura php-4.3.11/Zend/zend_errors.h hardening-patch-4.3.11-0.4.2/Zend/zend_errors.h +--- php-4.3.11/Zend/zend_errors.h 2002-12-31 17:22:59.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_errors.h 2005-09-07 19:04:56.248905888 +0200 +@@ -36,5 +36,17 @@ + #define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE) + #define E_CORE (E_CORE_ERROR | E_CORE_WARNING) + ++#if HARDENING_PATCH ++#define S_MEMORY (1<<0L) ++#define S_VARS (1<<1L) ++#define S_FILES (1<<2L) ++#define S_INCLUDE (1<<3L) ++#define S_SQL (1<<4L) ++#define S_EXECUTOR (1<<5L) ++#define S_MISC (1<<30L) ++#define S_INTERNAL (1<<29L) ++#define S_ALL (S_MEMORY | S_VARS | S_INCLUDE | S_FILES | S_MISC | S_SQL | S_EXECUTOR) ++#endif ++ + #endif /* ZEND_ERRORS_H */ + +diff -Nura php-4.3.11/Zend/zend_execute_API.c hardening-patch-4.3.11-0.4.2/Zend/zend_execute_API.c +--- php-4.3.11/Zend/zend_execute_API.c 2004-11-04 00:15:05.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_execute_API.c 2005-09-07 18:41:01.022093528 +0200 +@@ -142,6 +142,7 @@ + EG(class_table) = CG(class_table); + + EG(in_execution) = 0; ++ EG(in_code_type) = 0; + + zend_ptr_stack_init(&EG(argument_stack)); + +@@ -431,12 +432,14 @@ + zend_execute_data execute_data; + + /* Initialize execute_data */ ++ memset(&execute_data, 0, sizeof(execute_data)); + EX(fbc) = NULL; + EX(object).ptr = NULL; + EX(ce) = NULL; + EX(Ts) = NULL; + EX(op_array) = NULL; + EX(opline) = NULL; ++ EX(execute_depth) = 0; + + *retval_ptr_ptr = NULL; + +@@ -494,6 +497,39 @@ + zval_dtor(&function_name_copy); + return FAILURE; + } ++#if HARDENING_PATCH ++ if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), function_name_copy.value.str.val, function_name_copy.value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", function_name_copy.value.str.val); ++ zval_dtor(&function_name_copy); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), function_name_copy.value.str.val, function_name_copy.value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", function_name_copy.value.str.val); ++ zval_dtor(&function_name_copy); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), function_name_copy.value.str.val, function_name_copy.value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", function_name_copy.value.str.val); ++ zval_dtor(&function_name_copy); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), function_name_copy.value.str.val, function_name_copy.value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", function_name_copy.value.str.val); ++ zval_dtor(&function_name_copy); ++ zend_bailout(); ++ } ++ } ++ } ++#endif + zval_dtor(&function_name_copy); + + for (i=0; itype = type; + EG(return_value_ptr_ptr) = &local_retval_ptr; + EG(active_op_array) = new_op_array; + EG(no_extensions)=1; +@@ -668,6 +704,10 @@ + return retval; + } + ++ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) ++{ ++ return (zend_eval_string_ex(str, retval_ptr, string_name, ZEND_EVAL_CODE TSRMLS_CC)); ++} + + void execute_new_code(TSRMLS_D) + { +diff -Nura php-4.3.11/Zend/zend_execute.c hardening-patch-4.3.11-0.4.2/Zend/zend_execute.c +--- php-4.3.11/Zend/zend_execute.c 2005-02-21 13:38:54.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_execute.c 2005-09-07 18:41:01.024093224 +0200 +@@ -1042,6 +1042,7 @@ + zend_execute_data execute_data; + + /* Initialize execute_data */ ++ memset(&execute_data, 0, sizeof(execute_data)); + EX(fbc) = NULL; + EX(ce) = NULL; + EX(object).ptr = NULL; +@@ -1053,9 +1054,21 @@ + } + EX(prev_execute_data) = EG(current_execute_data); + EX(original_in_execution)=EG(in_execution); ++ EX(original_in_code_type)=EG(in_code_type); + + EG(current_execute_data) = &execute_data; + ++#if HARDENING_PATCH ++ EX(execute_depth) = 0; ++ ++ if ((op_array->type == ZEND_EVAL_CODE || op_array->created_by_eval) && EG(in_code_type) != ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } else if (op_array->type == ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_SANDBOX_CODE; ++ op_array->type = ZEND_EVAL_CODE; ++ } ++#endif ++ + EG(in_execution) = 1; + if (op_array->start_op) { + EX(opline) = op_array->start_op; +@@ -1087,6 +1100,19 @@ + } + } + ++#if HARDENING_PATCH ++ if (EX(prev_execute_data) == NULL) { ++ EX(execute_depth) = 0; ++ } else { ++ EX(execute_depth) = EX(prev_execute_data)->execute_depth + 1; ++ } ++ ++ if (EG(hphp_executor_max_depth) > 0 && EX(execute_depth) > EG(hphp_executor_max_depth)) { ++ zend_security_log(S_EXECUTOR, "Maximum execution depth of %u violated", EG(hphp_executor_max_depth)); ++ zend_bailout(); ++ } ++#endif ++ + while (1) { + #ifdef ZEND_WIN32 + if (EG(timed_out)) { +@@ -1615,6 +1641,36 @@ + if (zend_hash_find(active_function_table, function_name->value.str.val, function_name->value.str.len+1, (void **) &function)==FAILURE) { + zend_error(E_ERROR, "Call to undefined function: %s()", function_name->value.str.val); + } ++#if HARDENING_PATCH ++ if (active_function_table == EG(function_table)) { ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), function_name->value.str.val, function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", function_name->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), function_name->value.str.val, function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", function_name->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), function_name->value.str.val, function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", function_name->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), function_name->value.str.val, function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", function_name->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++#endif ++ + zval_dtor(&tmp); + EX(fbc) = function; + overloaded_function_call_cont: +@@ -1630,6 +1686,35 @@ + if (zend_hash_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { + zend_error(E_ERROR, "Unknown function: %s()", fname->value.str.val); + } ++#if HARDENING_PATCH ++ if (EX(function_state).function->type==ZEND_INTERNAL_FUNCTION) { ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++#endif + FREE_OP(EX(Ts), &EX(opline)->op1, EG(free_op1)); + zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(object).ptr, EX(ce)); + EX(object).ptr = NULL; +@@ -1782,6 +1867,7 @@ + efree(EX(Ts)); + } + EG(in_execution) = EX(original_in_execution); ++ EG(in_code_type) = EX(original_in_code_type); + EG(current_execute_data) = EX(prev_execute_data); + return; + } +@@ -2161,7 +2247,12 @@ + int dummy = 1; + zend_file_handle file_handle = {0}; + ++#if HARDENING_PATCH_INC_PROTECT ++ if (zend_is_valid_include(inc_filename) ++ && zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#else + if (zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#endif + && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) { + + file_handle.filename = inc_filename->value.str.val; +@@ -2190,6 +2281,11 @@ + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: ++#if HARDENING_PATCH_INC_PROTECT ++ if (!zend_is_valid_include(inc_filename)) { ++ break; ++ } ++#endif + new_op_array = compile_filename(EX(opline)->op2.u.constant.value.lval, inc_filename TSRMLS_CC); + break; + case ZEND_EVAL: { +diff -Nura php-4.3.11/Zend/zend_execute_globals.h hardening-patch-4.3.11-0.4.2/Zend/zend_execute_globals.h +--- php-4.3.11/Zend/zend_execute_globals.h 2002-12-31 17:23:00.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_execute_globals.h 2005-09-07 18:41:01.025093072 +0200 +@@ -59,6 +59,8 @@ + object_info object; + temp_variable *Ts; + zend_bool original_in_execution; ++ zend_uint original_in_code_type; ++ zend_uint execute_depth; + zend_op_array *op_array; + struct _zend_execute_data *prev_execute_data; + } zend_execute_data; +diff -Nura php-4.3.11/Zend/zend_extensions.c hardening-patch-4.3.11-0.4.2/Zend/zend_extensions.c +--- php-4.3.11/Zend/zend_extensions.c 2003-03-19 19:00:57.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_extensions.c 2005-09-07 18:41:01.025093072 +0200 +@@ -54,23 +54,44 @@ + return FAILURE; + } + ++ /* check if module is compiled against Hardening-Patch */ ++ if (extension_version_info->zend_extension_api_no < 1000000000) { ++ fprintf(stderr, "%s is not compiled with Hardening-Patch.\n" ++ "The Hardening-Patch version %d is installed.\n\n", ++ new_extension->name, ++ HARDENING_PATCH_ZEND_EXTENSION_API_NO); ++ DL_UNLOAD(handle); ++ return FAILURE; ++ } ++ ++ ++ /* check if module is compiled against correct Hardening-Patch version */ ++ if (extension_version_info->zend_extension_api_no != HARDENING_PATCH_ZEND_EXTENSION_API_NO) { ++ fprintf(stderr, "%s requires Hardening-Patch version %d.\n" ++ "The Hardening-Patch version %d is installed.\n\n", ++ new_extension->name, ++ extension_version_info->zend_extension_api_no, ++ HARDENING_PATCH_ZEND_EXTENSION_API_NO); ++ DL_UNLOAD(handle); ++ return FAILURE; ++ } + + /* allow extension to proclaim compatibility with any Zend version */ +- if (extension_version_info->zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) { +- if (extension_version_info->zend_extension_api_no > ZEND_EXTENSION_API_NO) { ++ if (extension_version_info->real_zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) { ++ if (extension_version_info->real_zend_extension_api_no > ZEND_EXTENSION_API_NO) { + fprintf(stderr, "%s requires Zend Engine API version %d.\n" + "The Zend Engine API version %d which is installed, is outdated.\n\n", + new_extension->name, +- extension_version_info->zend_extension_api_no, ++ extension_version_info->real_zend_extension_api_no, + ZEND_EXTENSION_API_NO); + DL_UNLOAD(handle); + return FAILURE; +- } else if (extension_version_info->zend_extension_api_no < ZEND_EXTENSION_API_NO) { ++ } else if (extension_version_info->real_zend_extension_api_no < ZEND_EXTENSION_API_NO) { + fprintf(stderr, "%s requires Zend Engine API version %d.\n" + "The Zend Engine API version %d which is installed, is newer.\n" + "Contact %s at %s for a later version of %s.\n\n", + new_extension->name, +- extension_version_info->zend_extension_api_no, ++ extension_version_info->real_zend_extension_api_no, + ZEND_EXTENSION_API_NO, + new_extension->author, + new_extension->URL, +diff -Nura php-4.3.11/Zend/zend_extensions.h hardening-patch-4.3.11-0.4.2/Zend/zend_extensions.h +--- php-4.3.11/Zend/zend_extensions.h 2002-12-31 17:23:02.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_extensions.h 2005-09-07 18:41:01.026092920 +0200 +@@ -23,6 +23,9 @@ + + #include "zend_compile.h" + ++/* Create own API version number for Hardening-Patch */ ++ ++#define HARDENING_PATCH_ZEND_EXTENSION_API_NO 1000050805 + #define ZEND_EXTENSION_API_NO 20021010 + + typedef struct _zend_extension_version_info { +@@ -30,6 +33,7 @@ + char *required_zend_version; + unsigned char thread_safe; + unsigned char debug; ++ int real_zend_extension_api_no; + } zend_extension_version_info; + + +@@ -96,7 +100,7 @@ + + + #define ZEND_EXTENSION() \ +- ZEND_EXT_API zend_extension_version_info extension_version_info = { ZEND_EXTENSION_API_NO, ZEND_VERSION, ZTS_V, ZEND_DEBUG } ++ ZEND_EXT_API zend_extension_version_info extension_version_info = { HARDENING_PATCH_ZEND_EXTENSION_API_NO, ZEND_VERSION, ZTS_V, ZEND_DEBUG, ZEND_EXTENSION_API_NO } + + #define STANDARD_ZEND_EXTENSION_PROPERTIES NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1 + #define COMPAT_ZEND_EXTENSION_PROPERTIES NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1 +diff -Nura php-4.3.11/Zend/zend_globals.h hardening-patch-4.3.11-0.4.2/Zend/zend_globals.h +--- php-4.3.11/Zend/zend_globals.h 2004-11-04 00:15:05.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_globals.h 2005-09-07 18:41:01.026092920 +0200 +@@ -163,6 +163,16 @@ + + int error_reporting; + int orig_error_reporting; ++#if HARDENING_PATCH ++ int hphp_log_syslog; ++ int hphp_log_syslog_facility; ++ int hphp_log_syslog_priority; ++ int hphp_log_sapi; ++ int hphp_log_script; ++ char *hphp_log_scriptname; ++ zend_bool hphp_log_use_x_forwarded_for; ++ long hphp_executor_max_depth; ++#endif + int exit_status; + + zend_op_array *active_op_array; +@@ -176,6 +186,7 @@ + int ticks_count; + + zend_bool in_execution; ++ zend_uint in_code_type; + zend_bool bailout_set; + zend_bool full_tables_cleanup; + +diff -Nura php-4.3.11/Zend/zend.h hardening-patch-4.3.11-0.4.2/Zend/zend.h +--- php-4.3.11/Zend/zend.h 2005-01-25 14:08:41.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend.h 2005-09-07 18:41:01.027092768 +0200 +@@ -275,9 +275,10 @@ + struct _zval_struct { + /* Variable information */ + zvalue_value value; /* value */ ++ zend_uint refcount; ++ zend_ushort flags; + zend_uchar type; /* active type */ + zend_uchar is_ref; +- zend_ushort refcount; + }; + + +@@ -338,6 +339,12 @@ + void (*ticks_function)(int ticks); + void (*on_timeout)(int seconds TSRMLS_DC); + zend_bool (*open_function)(const char *filename, struct _zend_file_handle *); ++#if HARDENING_PATCH ++ void (*security_log_function)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ int (*is_valid_include)(zval *z); ++#endif + } zend_utility_functions; + + +@@ -469,7 +476,16 @@ + extern ZEND_API void (*zend_ticks_function)(int ticks); + extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); + extern void (*zend_on_timeout)(int seconds TSRMLS_DC); ++#if HARDENING_PATCH ++extern ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++extern ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ZEND_API unsigned int zend_canary(void); ++#endif + + ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 2, 3); + +@@ -576,6 +592,11 @@ + + #define ZEND_MAX_RESERVED_RESOURCES 4 + ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#include "php_syslog.h" ++#endif ++ + #endif /* ZEND_H */ + + /* +diff -Nura php-4.3.11/Zend/zend_hash.c hardening-patch-4.3.11-0.4.2/Zend/zend_hash.c +--- php-4.3.11/Zend/zend_hash.c 2004-07-12 23:26:46.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_hash.c 2005-09-07 18:41:01.028092616 +0200 +@@ -26,6 +26,17 @@ + # include + #endif + ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int zend_hash_canary = 0x1234567; ++ zend_bool zend_hash_canary_inited = 0; ++#endif ++ ++#define CHECK_HASH_CANARY(hash) \ ++ if (zend_hash_canary != (hash)->canary) { \ ++ zend_security_log(S_MEMORY, "Zend HashTable canary was overwritten"); \ ++ exit(1); \ ++ } ++ + #define HANDLE_NUMERIC(key, length, func) { \ + register char *tmp=key; \ + \ +@@ -175,6 +186,9 @@ + { + uint i = 3; + Bucket **tmp; ++#if HARDENING_PATCH_HASH_PROTECT ++ TSRMLS_FETCH(); ++#endif + + SET_INCONSISTENT(HT_OK); + +@@ -184,6 +198,13 @@ + + ht->nTableSize = 1 << i; + ht->nTableMask = ht->nTableSize - 1; ++#if HARDENING_PATCH_HASH_PROTECT ++ if (zend_hash_canary_inited==0) { ++ zend_hash_canary = zend_canary(); ++ zend_hash_canary_inited = 1; ++ } ++ ht->canary = zend_hash_canary; ++#endif + ht->pDestructor = pDestructor; + ht->pListHead = NULL; + ht->pListTail = NULL; +@@ -259,6 +280,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -327,6 +351,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -402,6 +429,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -450,7 +480,7 @@ + IS_CONSISTENT(ht); + + if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */ +- t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); ++ t = (Bucket **) perealloc(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); + if (t) { + HANDLE_BLOCK_INTERRUPTIONS(); + ht->arBuckets = t; +@@ -460,6 +490,7 @@ + HANDLE_UNBLOCK_INTERRUPTIONS(); + return SUCCESS; + } ++ zend_error(E_ERROR, "zend_hash_do_resize - out of memory"); + return FAILURE; + } + return SUCCESS; +@@ -524,6 +555,9 @@ + ht->pInternalPointer = p->pListNext; + } + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +@@ -553,6 +587,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -579,6 +616,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -608,6 +648,9 @@ + HANDLE_BLOCK_INTERRUPTIONS(); + + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +diff -Nura php-4.3.11/Zend/zend_hash.h hardening-patch-4.3.11-0.4.2/Zend/zend_hash.h +--- php-4.3.11/Zend/zend_hash.h 2002-12-31 17:23:03.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_hash.h 2005-09-07 18:41:01.028092616 +0200 +@@ -54,6 +54,9 @@ + } Bucket; + + typedef struct _hashtable { ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int canary; ++#endif + uint nTableSize; + uint nTableMask; + uint nNumOfElements; +diff -Nura php-4.3.11/Zend/zend_ini.h hardening-patch-4.3.11-0.4.2/Zend/zend_ini.h +--- php-4.3.11/Zend/zend_ini.h 2005-01-09 18:00:16.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_ini.h 2005-09-07 18:41:01.029092464 +0200 +@@ -174,6 +174,7 @@ + /* Standard message handlers */ + BEGIN_EXTERN_C() + ZEND_API ZEND_INI_MH(OnUpdateBool); ++#define OnUpdateLong OnUpdateInt + ZEND_API ZEND_INI_MH(OnUpdateInt); + ZEND_API ZEND_INI_MH(OnUpdateReal); + ZEND_API ZEND_INI_MH(OnUpdateString); +diff -Nura php-4.3.11/Zend/zend_language_scanner.l hardening-patch-4.3.11-0.4.2/Zend/zend_language_scanner.l +--- php-4.3.11/Zend/zend_language_scanner.l 2005-03-09 16:07:19.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_language_scanner.l 2005-09-07 18:41:01.033091856 +0200 +@@ -393,6 +393,13 @@ + compilation_successful=0; + } else { + init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array->created_by_eval = 1; ++ } else { ++ op_array->created_by_eval = 0; ++ } ++#endif + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + compiler_result = zendparse(TSRMLS_C); +diff -Nura php-4.3.11/Zend/zend_language_scanner.c hardening-patch-4.3.11-0.4.2/Zend/zend_language_scanner.c +--- php-4.3.11/Zend/zend_language_scanner.c 2005-03-30 16:35:47.000000000 +0200 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_language_scanner.c 2005-09-07 18:41:01.031092160 +0200 +@@ -3121,6 +3121,13 @@ + compilation_successful=0; + } else { + init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array->created_by_eval = 1; ++ } else { ++ op_array->created_by_eval = 0; ++ } ++#endif + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + compiler_result = zendparse(TSRMLS_C); +diff -Nura php-4.3.11/Zend/zend_llist.c hardening-patch-4.3.11-0.4.2/Zend/zend_llist.c +--- php-4.3.11/Zend/zend_llist.c 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_llist.c 2005-09-07 18:41:01.034091704 +0200 +@@ -21,9 +21,34 @@ + #include "zend.h" + #include "zend_llist.h" + #include "zend_qsort.h" ++#include "zend_globals.h" ++ ++#define CHECK_LIST_CANARY(list) \ ++ if (HG(canary_3) != (list)->canary_h || HG(canary_4) != (list)->canary_t) { \ ++ zend_security_log(S_MEMORY, "linked list canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++#define CHECK_LISTELEMENT_CANARY(elem) \ ++ if (HG(canary_3) != (elem)->canary) { \ ++ zend_security_log(S_MEMORY, "linked list element canary was overwritten"); \ ++ exit(1); \ ++ } ++ + + ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ ++ if (!HG(ll_canary_inited)) { ++ HG(canary_3) = zend_canary(); ++ HG(canary_4) = zend_canary(); ++ HG(ll_canary_inited) = 1; ++ } ++ l->canary_h = HG(canary_3); ++ l->canary_t = HG(canary_4); ++#endif + l->head = NULL; + l->tail = NULL; + l->count = 0; +@@ -37,6 +62,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->prev = l->tail; + tmp->next = NULL; + if (l->tail) { +@@ -55,6 +85,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->next = l->head; + tmp->prev = NULL; + if (l->head) { +@@ -91,10 +126,20 @@ + zend_llist_element *current=l->head; + zend_llist_element *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (compare(current->data, element)) { + DEL_LLIST_ELEMENT(current, l); ++#if HARDENING_PATCH_LL_PROTECT ++ current->canary = 0; ++#endif + break; + } + current = next; +@@ -106,7 +151,14 @@ + { + zend_llist_element *current=l->head, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (l->dtor) { + l->dtor(current->data); +@@ -131,7 +183,14 @@ + zend_llist_element *old_tail; + void *data; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if ((old_tail = l->tail)) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(old_tail) ++#endif + if (l->tail->prev) { + l->tail->prev->next = NULL; + } +@@ -157,9 +216,16 @@ + { + zend_llist_element *ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(src) ++#endif + zend_llist_init(dst, src->size, src->dtor, src->persistent); + ptr = src->head; + while (ptr) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(ptr) ++#endif + zend_llist_add_element(dst, ptr->data); + ptr = ptr->next; + } +@@ -170,11 +236,21 @@ + { + zend_llist_element *element, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + element=l->head; + while (element) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + next = element->next; + if (func(element->data)) { + DEL_LLIST_ELEMENT(element, l); ++#if HARDENING_PATCH_LL_PROTECT ++ element->canary = 0; ++#endif + } + element = next; + } +@@ -185,7 +261,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data TSRMLS_CC); + } + } +@@ -197,6 +279,9 @@ + zend_llist_element **elements; + zend_llist_element *element, **ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + if (l->count <= 0) { + return; + } +@@ -206,6 +291,9 @@ + ptr = &elements[0]; + + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + *ptr++ = element; + } + +@@ -228,7 +316,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, arg TSRMLS_CC); + } + } +@@ -239,8 +333,14 @@ + zend_llist_element *element; + va_list args; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + va_start(args, num_args); + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, num_args, args TSRMLS_CC); + } + va_end(args); +@@ -249,6 +349,10 @@ + + ZEND_API int zend_llist_count(zend_llist *l) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + return l->count; + } + +@@ -256,8 +360,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->head; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -269,8 +380,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->tail; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -282,9 +400,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->next; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +@@ -296,9 +424,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->prev; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +diff -Nura php-4.3.11/Zend/zend_llist.h hardening-patch-4.3.11-0.4.2/Zend/zend_llist.h +--- php-4.3.11/Zend/zend_llist.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_llist.h 2005-09-07 18:41:01.034091704 +0200 +@@ -24,6 +24,9 @@ + #include + + typedef struct _zend_llist_element { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary; ++#endif + struct _zend_llist_element *next; + struct _zend_llist_element *prev; + char data[1]; /* Needs to always be last in the struct */ +@@ -36,6 +39,9 @@ + typedef void (*llist_apply_func_t)(void * TSRMLS_DC); + + typedef struct _zend_llist { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_h; /* head */ ++#endif + zend_llist_element *head; + zend_llist_element *tail; + size_t size; +@@ -43,6 +49,9 @@ + llist_dtor_func_t dtor; + unsigned char persistent; + zend_llist_element *traverse_ptr; ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_t; /* tail */ ++#endif + } zend_llist; + + typedef zend_llist_element* zend_llist_position; +diff -Nura php-4.3.11/Zend/zend_modules.h hardening-patch-4.3.11-0.4.2/Zend/zend_modules.h +--- php-4.3.11/Zend/zend_modules.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_modules.h 2005-09-07 18:41:01.034091704 +0200 +@@ -34,6 +34,7 @@ + ZEND_API extern unsigned char second_arg_force_ref[]; + ZEND_API extern unsigned char third_arg_force_ref[]; + ++#define HARDENING_PATCH_ZEND_MODULE_API_NO 1000050805 + #define ZEND_MODULE_API_NO 20020429 + #ifdef ZTS + #define USING_ZTS 1 +@@ -41,9 +42,9 @@ + #define USING_ZTS 0 + #endif + +-#define STANDARD_MODULE_HEADER sizeof(zend_module_entry), ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS ++#define STANDARD_MODULE_HEADER sizeof(zend_module_entry), HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS + +-#define STANDARD_MODULE_PROPERTIES_EX 0, 0, 0, NULL, 0 ++#define STANDARD_MODULE_PROPERTIES_EX 0, 0, 0, NULL, 0, ZEND_MODULE_API_NO + + #define STANDARD_MODULE_PROPERTIES \ + NULL, NULL, STANDARD_MODULE_PROPERTIES_EX +@@ -75,6 +76,7 @@ + unsigned char type; + void *handle; + int module_number; ++ unsigned int real_zend_api; + }; + + +diff -Nura php-4.3.11/Zend/zend_opcode.c hardening-patch-4.3.11-0.4.2/Zend/zend_opcode.c +--- php-4.3.11/Zend/zend_opcode.c 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_opcode.c 2005-09-07 18:41:01.035091552 +0200 +@@ -88,6 +88,9 @@ + op_array->done_pass_two = 0; + + op_array->start_op = NULL; ++#if HARDENING_PATCH ++ op_array->created_by_eval = 0; ++#endif + + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC); + } +diff -Nura php-4.3.11/Zend/zend_operators.c hardening-patch-4.3.11-0.4.2/Zend/zend_operators.c +--- php-4.3.11/Zend/zend_operators.c 2004-11-29 10:15:28.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_operators.c 2005-09-07 18:41:01.036091400 +0200 +@@ -1575,6 +1575,20 @@ + return (op->value.lval ? 1 : 0); + } + ++ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length) ++{ ++ register unsigned char *str = (unsigned char*)source; ++ register unsigned char *result = (unsigned char*)dest; ++ register unsigned char *end = str + length; ++ ++ while (str < end) { ++ *result++ = tolower((int)*str++); ++ } ++ *result = *end; ++ ++ return dest; ++} ++ + ZEND_API void zend_str_tolower(char *str, unsigned int length) + { + register char *p=str, *end=p+length; +diff -Nura php-4.3.11/Zend/zend_operators.h hardening-patch-4.3.11-0.4.2/Zend/zend_operators.h +--- php-4.3.11/Zend/zend_operators.h 2005-03-15 16:49:29.000000000 +0100 ++++ hardening-patch-4.3.11-0.4.2/Zend/zend_operators.h 2005-09-07 18:41:01.036091400 +0200 +@@ -171,6 +171,14 @@ + ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC); + + ZEND_API void zend_str_tolower(char *str, unsigned int length); ++ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length); ++ ++static inline char * ++zend_str_tolower_dup(const char *source, unsigned int length) ++{ ++ return zend_str_tolower_copy((char *)emalloc(length+1), source, length); ++} ++ + ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2); + ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3); + ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2); diff --git a/0.4.2/hardening-patch-4.4.0-0.4.2.patch b/0.4.2/hardening-patch-4.4.0-0.4.2.patch new file mode 100644 index 0000000..51aef54 --- /dev/null +++ b/0.4.2/hardening-patch-4.4.0-0.4.2.patch @@ -0,0 +1,14668 @@ +diff -Nura php-4.4.0/acinclude.m4 hardening-patch-4.4.0-0.4.2/acinclude.m4 +--- php-4.4.0/acinclude.m4 2005-04-30 11:31:09.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/acinclude.m4 2005-09-07 18:40:29.039955552 +0200 +@@ -1173,6 +1173,36 @@ + fi + ]) + ++dnl ++dnl Check for broken realpath() ++dnl ++dnl realpath("/etc/hosts/../passwd",XXX) should not return ++dnl "/etc/passwd" ++dnl ++AC_DEFUN([PHP_AC_BROKEN_REALPATH],[ ++ AC_CACHE_CHECK(whether realpath is broken, ac_cv_broken_realpath,[ ++ AC_TRY_RUN([ ++main() { ++ char buf[4096+1]; ++ buf[0] = 0; ++ realpath("/etc/hosts/../passwd", buf); ++ exit(strcmp(buf, "/etc/passwd")==0); ++} ++ ],[ ++ ac_cv_broken_realpath=no ++ ],[ ++ ac_cv_broken_realpath=yes ++ ],[ ++ ac_cv_broken_realpath=no ++ ]) ++ ]) ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ AC_DEFINE(PHP_BROKEN_REALPATH, 1, [Whether realpath is broken]) ++ else ++ AC_DEFINE(PHP_BROKEN_REALPATH, 0, [Whether realpath is broken]) ++ fi ++]) ++ + dnl PHP_SHARED_MODULE(module-name, object-var, build-dir, cxx) + dnl + dnl Basically sets up the link-stage for building module-name +diff -Nura php-4.4.0/configure hardening-patch-4.4.0-0.4.2/configure +--- php-4.4.0/configure 2005-07-11 12:07:33.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/configure 2005-09-07 18:45:59.447725936 +0200 +@@ -394,6 +394,16 @@ + ac_default_prefix=/usr/local + # Any additions from configure.in: + ac_help="$ac_help ++ --disable-hardening-patch-mm-protect Disable the Memory Manager protection." ++ac_help="$ac_help ++ --disable-hardening-patch-ll-protect Disable the Linked List protection." ++ac_help="$ac_help ++ --disable-hardening-patch-inc-protect Disable include/require protection." ++ac_help="$ac_help ++ --disable-hardening-patch-fmt-protect Disable format string protection." ++ac_help="$ac_help ++ --disable-hardening-patch-hash-protect Disable Zend HashTable DTOR protection." ++ac_help="$ac_help + + SAPI modules: + " +@@ -846,6 +856,8 @@ + ac_help="$ac_help + --disable-tokenizer Disable tokenizer support" + ac_help="$ac_help ++ --disable-varfilter Disable Hardening-Patch's variable filter" ++ac_help="$ac_help + --enable-wddx Enable WDDX support." + ac_help="$ac_help + --disable-xml Disable XML support using bundled expat lib" +@@ -2682,6 +2694,157 @@ + + + ++# Check whether --enable-hardening-patch-mm-protect or --disable-hardening-patch-mm-protect was given. ++if test "${enable_hardening_patch_mm_protect+set}" = set; then ++ enableval="$enable_hardening_patch_mm_protect" ++ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-ll-protect or --disable-hardening-patch-ll-protect was given. ++if test "${enable_hardening_patch_ll_protect+set}" = set; then ++ enableval="$enable_hardening_patch_ll_protect" ++ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-inc-protect or --disable-hardening-patch-inc-protect was given. ++if test "${enable_hardening_patch_inc_protect+set}" = set; then ++ enableval="$enable_hardening_patch_inc_protect" ++ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-fmt-protect or --disable-hardening-patch-fmt-protect was given. ++if test "${enable_hardening_patch_fmt_protect+set}" = set; then ++ enableval="$enable_hardening_patch_fmt_protect" ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-hash-protect or --disable-hardening-patch-hash-protect was given. ++if test "${enable_hardening_patch_hash_protect+set}" = set; then ++ enableval="$enable_hardening_patch_hash_protect" ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++ ++fi ++ ++ ++echo $ac_n "checking whether to protect the Zend Memory Manager""... $ac_c" 1>&6 ++echo "configure:2725: checking whether to protect the Zend Memory Manager" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_MM_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend Linked Lists""... $ac_c" 1>&6 ++echo "configure:2729: checking whether to protect the Zend Linked Lists" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_LL_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect include/require statements""... $ac_c" 1>&6 ++echo "configure:2733: checking whether to protect include/require statements" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_INC_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect PHP Format String functions""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect PHP Format String functions" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_FMT_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend HashTable Destructors""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect the Zend HashTable Destructors" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_HASH_PROTECT" 1>&6 ++ ++ ++cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH 1 ++EOF ++ ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 0 ++EOF ++ ++fi + + + +@@ -15733,6 +15896,62 @@ + fi + + ++ echo $ac_n "checking whether realpath is broken""... $ac_c" 1>&6 ++echo "configure:14928: checking whether realpath is broken" >&5 ++if eval "test \"`echo '$''{'ac_cv_broken_realpath'+set}'`\" = set"; then ++ echo $ac_n "(cached) $ac_c" 1>&6 ++else ++ ++ if test "$cross_compiling" = yes; then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null ++then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ echo "configure: failed program was:" >&5 ++ cat conftest.$ac_ext >&5 ++ rm -fr conftest* ++ ++ ac_cv_broken_realpath=yes ++ ++fi ++rm -fr conftest* ++fi ++ ++ ++fi ++ ++echo "$ac_t""$ac_cv_broken_realpath" 1>&6 ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 1 ++EOF ++ ++ else ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 0 ++EOF ++ ++ fi ++ ++ + echo $ac_n "checking for declared timezone""... $ac_c" 1>&6 + echo "configure:15738: checking for declared timezone" >&5 + if eval "test \"`echo '$''{'ac_cv_declared_timezone'+set}'`\" = set"; then +@@ -83268,7 +83487,7 @@ + if test "$ac_cv_crypt_blowfish" = "yes"; then + ac_result=1 + else +- ac_result=0 ++ ac_result=1 + fi + cat >> confdefs.h <&6 ++echo "configure:82041: checking whether to enable Hardening-Patch's variable filter" >&5 ++# Check whether --enable-varfilter or --disable-varfilter was given. ++if test "${enable_varfilter+set}" = set; then ++ enableval="$enable_varfilter" ++ PHP_VARFILTER=$enableval ++else ++ ++ PHP_VARFILTER=yes ++ ++ if test "$PHP_ENABLE_ALL" && test "yes" = "yes"; then ++ PHP_VARFILTER=$PHP_ENABLE_ALL ++ fi ++ ++fi ++ ++ ++ ++ext_output="yes, shared" ++ext_shared=yes ++case $PHP_VARFILTER in ++shared,*) ++ PHP_VARFILTER=`echo "$PHP_VARFILTER"|sed 's/^shared,//'` ++ ;; ++shared) ++ PHP_VARFILTER=yes ++ ;; ++no) ++ ext_output=no ++ ext_shared=no ++ ;; ++*) ++ ext_output=yes ++ ext_shared=no ++ ;; ++esac ++ ++ ++ ++echo "$ac_t""$ext_output" 1>&6 ++ ++ ++ ++ ++if test "$PHP_VARFILTER" != "no"; then ++ cat >> confdefs.h <<\EOF ++#define HAVE_VARFILTER 1 ++EOF ++ ++ ++ ext_builddir=ext/varfilter ++ ext_srcdir=$abs_srcdir/ext/varfilter ++ ++ ac_extra= ++ ++ if test "$ext_shared" != "shared" && test "$ext_shared" != "yes" && test "" != "cli"; then ++ ++ ++ ++ case ext/varfilter in ++ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;; ++ /*) ac_srcdir=`echo "ext/varfilter"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;; ++ *) ac_srcdir="$abs_srcdir/ext/varfilter/"; ac_bdir="ext/varfilter/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;; ++ esac ++ ++ ++ ++ b_c_pre=$php_c_pre ++ b_cxx_pre=$php_cxx_pre ++ b_c_meta=$php_c_meta ++ b_cxx_meta=$php_cxx_meta ++ b_c_post=$php_c_post ++ b_cxx_post=$php_cxx_post ++ b_lo=$php_lo ++ ++ ++ old_IFS=$IFS ++ for ac_src in varfilter.c; do ++ ++ IFS=. ++ set $ac_src ++ ac_obj=$1 ++ IFS=$old_IFS ++ ++ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo" ++ ++ case $ac_src in ++ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;; ++ *.cpp) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;; ++ esac ++ ++ cat >>Makefile.objects<>Makefile.objects<>Makefile.objects<> confdefs.h <>Makefile.objects<>Makefile.objects<&6 +@@ -99988,7 +100466,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c; do ++ output.c memory_streams.c user_streams.c hardening_patch.c; do + + IFS=. + set $ac_src +@@ -100161,7 +100639,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c; do ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c; do + + IFS=. + set $ac_src +diff -Nura php-4.4.0/configure.in hardening-patch-4.4.0-0.4.2/configure.in +--- php-4.4.0/configure.in 2005-07-11 09:45:09.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/configure.in 2005-09-07 18:40:29.076949928 +0200 +@@ -238,7 +238,7 @@ + sinclude(Zend/acinclude.m4) + sinclude(Zend/Zend.m4) + sinclude(TSRM/tsrm.m4) +- ++sinclude(main/hardening_patch.m4) + + + divert(2) +@@ -612,6 +612,7 @@ + AC_FUNC_ALLOCA + dnl PHP_AC_BROKEN_SPRINTF + dnl PHP_AC_BROKEN_SNPRINTF ++PHP_AC_BROKEN_REALPATH + PHP_DECLARED_TIMEZONE + PHP_TIME_R_TYPE + PHP_READDIR_R_TYPE +@@ -1241,7 +1242,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c) ++ output.c memory_streams.c user_streams.c hardening_patch.c) + PHP_ADD_SOURCES(/main, internal_functions.c,, sapi) + PHP_ADD_SOURCES(/main, internal_functions_cli.c,, cli) + +@@ -1254,7 +1255,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c) ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c ) + + if test -r "$abs_srcdir/Zend/zend_objects.c"; then + PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_mm.c) +diff -Nura php-4.4.0/ext/fbsql/php_fbsql.c hardening-patch-4.4.0-0.4.2/ext/fbsql/php_fbsql.c +--- php-4.4.0/ext/fbsql/php_fbsql.c 2005-02-09 20:33:32.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/fbsql/php_fbsql.c 2005-09-07 18:40:29.078949624 +0200 +@@ -1797,8 +1797,24 @@ + } + else if (fbcmdErrorsFound(md)) + { ++#if HARDENING_PATCH ++ char* query_copy; ++ int i; ++#endif + FBCErrorMetaData* emd = fbcdcErrorMetaData(c, md); + char* emg = fbcemdAllErrorMessages(emd); ++#if HARDENING_PATCH ++ query_copy=estrdup(query_copy); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "fbsql error: %s - query: %s", emg, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ free(emg); ++ fbcemdRelease(emd); ++ result = 0; ++ zend_bailout(); ++ } ++#endif + if (FB_SQL_G(generateWarnings)) + { + if (emg) +diff -Nura php-4.4.0/ext/mbstring/mbstring.c hardening-patch-4.4.0-0.4.2/ext/mbstring/mbstring.c +--- php-4.4.0/ext/mbstring/mbstring.c 2005-02-21 09:03:47.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/mbstring/mbstring.c 2005-09-07 18:40:29.080949320 +0200 +@@ -1487,6 +1487,7 @@ + char *strtok_buf = NULL, **val_list; + zval *array_ptr = (zval *) arg; + int n, num, val_len, *len_list; ++ unsigned int new_val_len; + enum mbfl_no_encoding from_encoding; + mbfl_string string, resvar, resval; + mbfl_encoding_detector *identd = NULL; +@@ -1609,8 +1610,14 @@ + val_len = len_list[n]; + } + n++; +- /* add variable to symbol table */ +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ /* we need val to be emalloc()ed */ ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(info->data_type, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ /* add variable to symbol table */ ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); ++ + if (convd != NULL){ + mbfl_string_clear(&resvar); + mbfl_string_clear(&resval); +diff -Nura php-4.4.0/ext/mysql/php_mysql.c hardening-patch-4.4.0-0.4.2/ext/mysql/php_mysql.c +--- php-4.4.0/ext/mysql/php_mysql.c 2005-04-08 00:23:01.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/ext/mysql/php_mysql.c 2005-09-07 18:40:29.082949016 +0200 +@@ -1218,6 +1218,8 @@ + { + php_mysql_conn *mysql; + MYSQL_RES *mysql_result; ++ char *copy_query; ++ int i; + + ZEND_FETCH_RESOURCE2(mysql, php_mysql_conn *, mysql_link, link_id, "MySQL-Link", le_link, le_plink); + +@@ -1268,6 +1270,13 @@ + php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #else +@@ -1275,12 +1284,20 @@ + /* check possible error */ + if (MySG(trace_mode)){ + if (mysql_errno(&mysql->conn)){ +- php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, mysql_error(&mysql->conn)); ++ php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #endif ++ + if(use_store == MYSQL_USE_RESULT) { + mysql_result=mysql_use_result(&mysql->conn); + } else { +diff -Nura php-4.4.0/ext/pgsql/pgsql.c hardening-patch-4.4.0-0.4.2/ext/pgsql/pgsql.c +--- php-4.4.0/ext/pgsql/pgsql.c 2005-07-05 14:50:03.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/ext/pgsql/pgsql.c 2005-09-07 18:40:29.084948712 +0200 +@@ -1001,10 +1001,28 @@ + case PGRES_EMPTY_QUERY: + case PGRES_BAD_RESPONSE: + case PGRES_NONFATAL_ERROR: +- case PGRES_FATAL_ERROR: +- PHP_PQ_ERROR("Query failed: %s", pgsql); +- PQclear(pgsql_result); +- RETURN_FALSE; ++ case PGRES_FATAL_ERROR: ++ { ++#if HARDENING_PATCH ++ int i; ++ char *query_copy; ++#endif ++ char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); ++ PQclear(pgsql_result); ++#if HARDENING_PATCH ++ query_copy = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "PgSQL error: %s - query: %s", msgbuf, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ efree(msgbuf); ++ zend_bailout(); ++ } ++#endif ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Query failed: %s", msgbuf); ++ efree(msgbuf); ++ RETURN_FALSE; ++ } + break; + case PGRES_COMMAND_OK: /* successful command that did not return rows */ + default: +diff -Nura php-4.4.0/ext/standard/array.c hardening-patch-4.4.0-0.4.2/ext/standard/array.c +--- php-4.4.0/ext/standard/array.c 2005-06-21 14:11:19.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/ext/standard/array.c 2005-09-07 18:40:29.086948408 +0200 +@@ -1162,6 +1162,32 @@ + } + } + } ++ ++ if (var_name[0] == 'H') { ++ if ((strcmp(var_name, "HTTP_GET_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_FILES")==0)|| ++ (strcmp(var_name, "HTTP_ENV_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(var_name, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(var_name, "HTTP_RAW_POST_DATA")==0)) { ++ return 0; ++ } ++ } else if (var_name[0] == '_') { ++ if ((strcmp(var_name, "_COOKIE")==0)|| ++ (strcmp(var_name, "_ENV")==0)|| ++ (strcmp(var_name, "_FILES")==0)|| ++ (strcmp(var_name, "_GET")==0)|| ++ (strcmp(var_name, "_POST")==0)|| ++ (strcmp(var_name, "_REQUEST")==0)|| ++ (strcmp(var_name, "_SESSION")==0)|| ++ (strcmp(var_name, "_SERVER")==0)) { ++ return 0; ++ } ++ } else if (strcmp(var_name, "GLOBALS")==0) { ++ return 0; ++ } + + return 1; + } +diff -Nura php-4.4.0/ext/standard/basic_functions.c hardening-patch-4.4.0-0.4.2/ext/standard/basic_functions.c +--- php-4.4.0/ext/standard/basic_functions.c 2005-05-16 10:55:31.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/ext/standard/basic_functions.c 2005-09-07 18:58:15.014902728 +0200 +@@ -118,12 +118,14 @@ + typedef struct _php_shutdown_function_entry { + zval **arguments; + int arg_count; ++ zend_bool created_by_eval; + } php_shutdown_function_entry; + + typedef struct _user_tick_function_entry { + zval **arguments; + int arg_count; + int calling; ++ zend_bool created_by_eval; + } user_tick_function_entry; + + /* some prototypes for local functions */ +@@ -306,6 +308,8 @@ + PHP_FE(get_html_translation_table, NULL) + PHP_FE(sha1, NULL) + PHP_FE(sha1_file, NULL) ++ PHP_FE(sha256, NULL) ++ PHP_FE(sha256_file, NULL) + PHP_NAMED_FE(md5,php_if_md5, NULL) + PHP_NAMED_FE(md5_file,php_if_md5_file, NULL) + PHP_NAMED_FE(crc32,php_if_crc32, NULL) +@@ -687,7 +691,7 @@ + PHP_FALIAS(socket_get_status, stream_get_meta_data, NULL) + + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +- PHP_FE(realpath, NULL) ++ PHP_STATIC_FE("realpath", zif_real_path, NULL) + #endif + + #ifdef HAVE_FNMATCH +@@ -2104,6 +2108,13 @@ + { + zval retval; + char *function_name = NULL; ++#if HARDENING_PATCH ++ zend_uint orig_code_type = EG(in_code_type); ++ ++ if (shutdown_function_entry->created_by_eval) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } ++#endif + + if (!zend_is_callable(shutdown_function_entry->arguments[0], 0, &function_name)) { + php_error(E_WARNING, "(Registered shutdown functions) Unable to call %s() - function does not exist", function_name); +@@ -2119,6 +2130,9 @@ + if (function_name) { + efree(function_name); + } ++#if HARDENING_PATCH ++ EG(in_code_type) = orig_code_type; ++#endif + return 0; + } + +@@ -2126,6 +2140,13 @@ + { + zval retval; + zval *function = tick_fe->arguments[0]; ++#if HARDENING_PATCH ++ zend_uint orig_code_type = EG(in_code_type); ++ ++ if (tick_fe->created_by_eval) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } ++#endif + + /* Prevent reentrant calls to the same user ticks function */ + if (! tick_fe->calling) { +@@ -2157,6 +2178,9 @@ + + tick_fe->calling = 0; + } ++#if HARDENING_PATCH ++ EG(in_code_type) = orig_code_type; ++#endif + } + + static void run_user_tick_functions(int tick_count) +@@ -2224,6 +2248,13 @@ + if (zend_get_parameters_array(ht, shutdown_function_entry.arg_count, shutdown_function_entry.arguments) == FAILURE) { + RETURN_FALSE; + } ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ shutdown_function_entry.created_by_eval = 1; ++ } else { ++ shutdown_function_entry.created_by_eval = 0; ++ } ++#endif + + /* Prevent entering of anything but valid callback (syntax check only!) */ + if (!zend_is_callable(shutdown_function_entry.arguments[0], 1, &function_name)) { +@@ -2761,6 +2792,13 @@ + } + + tick_fe.arguments = (zval **) safe_emalloc(sizeof(zval *), tick_fe.arg_count, 0); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ tick_fe.created_by_eval = 1; ++ } else { ++ tick_fe.created_by_eval = 0; ++ } ++#endif + + if (zend_get_parameters_array(ht, tick_fe.arg_count, tick_fe.arguments) == FAILURE) { + RETURN_FALSE; +@@ -3044,6 +3082,35 @@ + memcpy(new_key, prefix, prefix_len); + memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + ++ if (new_key[0] == 'H') { ++ if ((strcmp(new_key, "HTTP_GET_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_FILES")==0)|| ++ (strcmp(new_key, "HTTP_ENV_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(new_key, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(new_key, "HTTP_RAW_POST_DATA")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (new_key[0] == '_') { ++ if ((strcmp(new_key, "_COOKIE")==0)|| ++ (strcmp(new_key, "_ENV")==0)|| ++ (strcmp(new_key, "_FILES")==0)|| ++ (strcmp(new_key, "_GET")==0)|| ++ (strcmp(new_key, "_POST")==0)|| ++ (strcmp(new_key, "_REQUEST")==0)|| ++ (strcmp(new_key, "_SESSION")==0)|| ++ (strcmp(new_key, "_SERVER")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (strcmp(new_key, "GLOBALS")==0) { ++ efree(new_key); ++ return 0; ++ } ++ + zend_hash_del(&EG(symbol_table), new_key, new_key_len); + ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, (*var)->refcount+1, 0); + +diff -Nura php-4.4.0/ext/standard/config.m4 hardening-patch-4.4.0-0.4.2/ext/standard/config.m4 +--- php-4.4.0/ext/standard/config.m4 2004-12-30 08:02:18.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/standard/config.m4 2005-09-07 18:57:05.150523728 +0200 +@@ -203,7 +203,7 @@ + if test "$ac_cv_crypt_blowfish" = "yes"; then + ac_result=1 + else +- ac_result=0 ++ ac_result=1 + fi + AC_DEFINE_UNQUOTED(PHP_BLOWFISH_CRYPT, $ac_result, [Whether the system supports BlowFish salt]) + ]) +@@ -419,6 +419,6 @@ + url_scanner.c var.c versioning.c assert.c strnatcmp.c levenshtein.c \ + incomplete_class.c url_scanner_ex.c ftp_fopen_wrapper.c \ + http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \ +- var_unserializer.c ftok.c aggregation.c sha1.c ) ++ var_unserializer.c ftok.c aggregation.c sha1.c sha256.c crypt_blowfish.c ) + + PHP_ADD_MAKEFILE_FRAGMENT +diff -Nura php-4.4.0/ext/standard/crypt_blowfish.c hardening-patch-4.4.0-0.4.2/ext/standard/crypt_blowfish.c +--- php-4.4.0/ext/standard/crypt_blowfish.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/standard/crypt_blowfish.c 2005-09-07 14:19:05.000000000 +0200 +@@ -0,0 +1,748 @@ ++/* ++ * This code comes from John the Ripper password cracker, with reentrant ++ * and crypt(3) interfaces added, but optimizations specific to password ++ * cracking removed. ++ * ++ * Written by Solar Designer in 1998-2002 and ++ * placed in the public domain. ++ * ++ * There's absolutely no warranty. ++ * ++ * It is my intent that you should be able to use this on your system, ++ * as a part of a software package, or anywhere else to improve security, ++ * ensure compatibility, or for any other purpose. I would appreciate ++ * it if you give credit where it is due and keep your modifications in ++ * the public domain as well, but I don't require that in order to let ++ * you place this code and any modifications you make under a license ++ * of your choice. ++ * ++ * This implementation is compatible with OpenBSD bcrypt.c (version 2a) ++ * by Niels Provos , and uses some of his ++ * ideas. The password hashing algorithm was designed by David Mazieres ++ * . ++ * ++ * There's a paper on the algorithm that explains its design decisions: ++ * ++ * http://www.usenix.org/events/usenix99/provos.html ++ * ++ * Some of the tricks in BF_ROUND might be inspired by Eric Young's ++ * Blowfish library (I can't be sure if I would think of something if I ++ * hadn't seen his code). ++ */ ++ ++#include ++ ++#include ++#ifndef __set_errno ++#define __set_errno(val) errno = (val) ++#endif ++ ++#undef __CONST ++#ifdef __GNUC__ ++#define __CONST __const ++#else ++#define __CONST ++#endif ++ ++#ifdef __i386__ ++#define BF_ASM 0 ++#define BF_SCALE 1 ++#elif defined(__alpha__) || defined(__hppa__) ++#define BF_ASM 0 ++#define BF_SCALE 1 ++#else ++#define BF_ASM 0 ++#define BF_SCALE 0 ++#endif ++ ++typedef unsigned int BF_word; ++ ++/* Number of Blowfish rounds, this is also hardcoded into a few places */ ++#define BF_N 16 ++ ++typedef BF_word BF_key[BF_N + 2]; ++ ++typedef struct { ++ BF_word S[4][0x100]; ++ BF_key P; ++} BF_ctx; ++ ++/* ++ * Magic IV for 64 Blowfish encryptions that we do at the end. ++ * The string is "OrpheanBeholderScryDoubt" on big-endian. ++ */ ++static BF_word BF_magic_w[6] = { ++ 0x4F727068, 0x65616E42, 0x65686F6C, ++ 0x64657253, 0x63727944, 0x6F756274 ++}; ++ ++/* ++ * P-box and S-box tables initialized with digits of Pi. ++ */ ++static BF_ctx BF_init_state = { ++ { ++ { ++ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, ++ 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, ++ 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, ++ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, ++ 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, ++ 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, ++ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, ++ 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, ++ 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, ++ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, ++ 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, ++ 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, ++ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, ++ 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, ++ 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, ++ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, ++ 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, ++ 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, ++ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, ++ 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, ++ 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, ++ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, ++ 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, ++ 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, ++ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, ++ 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, ++ 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, ++ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, ++ 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, ++ 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, ++ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, ++ 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, ++ 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, ++ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, ++ 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, ++ 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, ++ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, ++ 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, ++ 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, ++ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, ++ 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, ++ 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, ++ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, ++ 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, ++ 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, ++ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, ++ 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, ++ 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, ++ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, ++ 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, ++ 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, ++ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, ++ 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, ++ 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, ++ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, ++ 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, ++ 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, ++ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, ++ 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, ++ 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, ++ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, ++ 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, ++ 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, ++ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a ++ }, { ++ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, ++ 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, ++ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, ++ 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, ++ 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, ++ 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, ++ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, ++ 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, ++ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, ++ 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, ++ 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, ++ 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, ++ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, ++ 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, ++ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, ++ 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, ++ 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, ++ 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, ++ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, ++ 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, ++ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, ++ 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, ++ 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, ++ 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, ++ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, ++ 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, ++ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, ++ 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, ++ 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, ++ 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, ++ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, ++ 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, ++ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, ++ 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, ++ 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, ++ 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, ++ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, ++ 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, ++ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, ++ 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, ++ 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, ++ 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, ++ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, ++ 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, ++ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, ++ 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, ++ 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, ++ 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, ++ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, ++ 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, ++ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, ++ 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, ++ 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, ++ 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, ++ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, ++ 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, ++ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, ++ 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, ++ 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, ++ 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, ++ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, ++ 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, ++ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, ++ 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 ++ }, { ++ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, ++ 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, ++ 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, ++ 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, ++ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, ++ 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, ++ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, ++ 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, ++ 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, ++ 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, ++ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, ++ 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, ++ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, ++ 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, ++ 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, ++ 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, ++ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, ++ 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, ++ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, ++ 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, ++ 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, ++ 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, ++ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, ++ 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, ++ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, ++ 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, ++ 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, ++ 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, ++ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, ++ 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, ++ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, ++ 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, ++ 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, ++ 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, ++ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, ++ 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, ++ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, ++ 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, ++ 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, ++ 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, ++ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, ++ 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, ++ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, ++ 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, ++ 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, ++ 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, ++ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, ++ 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, ++ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, ++ 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, ++ 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, ++ 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, ++ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, ++ 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, ++ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, ++ 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, ++ 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, ++ 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, ++ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, ++ 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, ++ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, ++ 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, ++ 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, ++ 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 ++ }, { ++ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, ++ 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, ++ 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, ++ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, ++ 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, ++ 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, ++ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, ++ 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, ++ 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, ++ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, ++ 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, ++ 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, ++ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, ++ 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, ++ 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, ++ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, ++ 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, ++ 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, ++ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, ++ 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, ++ 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, ++ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, ++ 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, ++ 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, ++ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, ++ 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, ++ 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, ++ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, ++ 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, ++ 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, ++ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, ++ 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, ++ 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, ++ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, ++ 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, ++ 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, ++ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, ++ 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, ++ 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, ++ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, ++ 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, ++ 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, ++ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, ++ 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, ++ 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, ++ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, ++ 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, ++ 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, ++ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, ++ 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, ++ 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, ++ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, ++ 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, ++ 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, ++ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, ++ 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, ++ 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, ++ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, ++ 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, ++ 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, ++ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, ++ 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, ++ 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, ++ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 ++ } ++ }, { ++ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, ++ 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, ++ 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, ++ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, ++ 0x9216d5d9, 0x8979fb1b ++ } ++}; ++ ++static unsigned char BF_itoa64[64 + 1] = ++ "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; ++ ++static unsigned char BF_atoi64[0x60] = { ++ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, ++ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64, ++ 64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ++ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64, ++ 64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, ++ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 ++}; ++ ++/* ++ * This may be optimized out if built with function inlining and no BF_ASM. ++ */ ++static void clean(void *data, int size) ++{ ++#if BF_ASM ++ extern void _BF_clean(void *data); ++#endif ++ memset(data, 0, size); ++#if BF_ASM ++ _BF_clean(data); ++#endif ++} ++ ++#define BF_safe_atoi64(dst, src) \ ++{ \ ++ tmp = (unsigned char)(src); \ ++ if (tmp == '$') break; \ ++ if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ ++ tmp = BF_atoi64[tmp]; \ ++ if (tmp > 63) return -1; \ ++ (dst) = tmp; \ ++} ++ ++static int BF_decode(BF_word *dst, __CONST char *src, int size) ++{ ++ unsigned char *dptr = (unsigned char *)dst; ++ unsigned char *end = dptr + size; ++ unsigned char *sptr = (unsigned char *)src; ++ unsigned int tmp, c1, c2, c3, c4; ++ ++ do { ++ BF_safe_atoi64(c1, *sptr++); ++ BF_safe_atoi64(c2, *sptr++); ++ *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4); ++ if (dptr >= end) break; ++ ++ BF_safe_atoi64(c3, *sptr++); ++ *dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2); ++ if (dptr >= end) break; ++ ++ BF_safe_atoi64(c4, *sptr++); ++ *dptr++ = ((c3 & 0x03) << 6) | c4; ++ } while (dptr < end); ++ ++ while (dptr < end) ++ *dptr++ = 0; ++ ++ return 0; ++} ++ ++static void BF_encode(char *dst, __CONST BF_word *src, int size) ++{ ++ unsigned char *sptr = (unsigned char *)src; ++ unsigned char *end = sptr + size; ++ unsigned char *dptr = (unsigned char *)dst; ++ unsigned int c1, c2; ++ ++ do { ++ c1 = *sptr++; ++ *dptr++ = BF_itoa64[c1 >> 2]; ++ c1 = (c1 & 0x03) << 4; ++ if (sptr >= end) { ++ *dptr++ = BF_itoa64[c1]; ++ break; ++ } ++ ++ c2 = *sptr++; ++ c1 |= c2 >> 4; ++ *dptr++ = BF_itoa64[c1]; ++ c1 = (c2 & 0x0f) << 2; ++ if (sptr >= end) { ++ *dptr++ = BF_itoa64[c1]; ++ break; ++ } ++ ++ c2 = *sptr++; ++ c1 |= c2 >> 6; ++ *dptr++ = BF_itoa64[c1]; ++ *dptr++ = BF_itoa64[c2 & 0x3f]; ++ } while (sptr < end); ++} ++ ++static void BF_swap(BF_word *x, int count) ++{ ++ static int endianness_check = 1; ++ char *is_little_endian = (char *)&endianness_check; ++ BF_word tmp; ++ ++ if (*is_little_endian) ++ do { ++ tmp = *x; ++ tmp = (tmp << 16) | (tmp >> 16); ++ *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF); ++ } while (--count); ++} ++ ++#if BF_SCALE ++/* Architectures which can shift addresses left by 2 bits with no extra cost */ ++#define BF_ROUND(L, R, N) \ ++ tmp1 = L & 0xFF; \ ++ tmp2 = L >> 8; \ ++ tmp2 &= 0xFF; \ ++ tmp3 = L >> 16; \ ++ tmp3 &= 0xFF; \ ++ tmp4 = L >> 24; \ ++ tmp1 = data.ctx.S[3][tmp1]; \ ++ tmp2 = data.ctx.S[2][tmp2]; \ ++ tmp3 = data.ctx.S[1][tmp3]; \ ++ tmp3 += data.ctx.S[0][tmp4]; \ ++ tmp3 ^= tmp2; \ ++ R ^= data.ctx.P[N + 1]; \ ++ tmp3 += tmp1; \ ++ R ^= tmp3; ++#else ++/* Architectures with no complicated addressing modes supported */ ++#define BF_INDEX(S, i) \ ++ (*((BF_word *)(((unsigned char *)S) + (i)))) ++#define BF_ROUND(L, R, N) \ ++ tmp1 = L & 0xFF; \ ++ tmp1 <<= 2; \ ++ tmp2 = L >> 6; \ ++ tmp2 &= 0x3FC; \ ++ tmp3 = L >> 14; \ ++ tmp3 &= 0x3FC; \ ++ tmp4 = L >> 22; \ ++ tmp4 &= 0x3FC; \ ++ tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \ ++ tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \ ++ tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \ ++ tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \ ++ tmp3 ^= tmp2; \ ++ R ^= data.ctx.P[N + 1]; \ ++ tmp3 += tmp1; \ ++ R ^= tmp3; ++#endif ++ ++/* ++ * Encrypt one block, BF_N is hardcoded here. ++ */ ++#define BF_ENCRYPT \ ++ L ^= data.ctx.P[0]; \ ++ BF_ROUND(L, R, 0); \ ++ BF_ROUND(R, L, 1); \ ++ BF_ROUND(L, R, 2); \ ++ BF_ROUND(R, L, 3); \ ++ BF_ROUND(L, R, 4); \ ++ BF_ROUND(R, L, 5); \ ++ BF_ROUND(L, R, 6); \ ++ BF_ROUND(R, L, 7); \ ++ BF_ROUND(L, R, 8); \ ++ BF_ROUND(R, L, 9); \ ++ BF_ROUND(L, R, 10); \ ++ BF_ROUND(R, L, 11); \ ++ BF_ROUND(L, R, 12); \ ++ BF_ROUND(R, L, 13); \ ++ BF_ROUND(L, R, 14); \ ++ BF_ROUND(R, L, 15); \ ++ tmp4 = R; \ ++ R = L; \ ++ L = tmp4 ^ data.ctx.P[BF_N + 1]; ++ ++#if BF_ASM ++#define BF_body() \ ++ _BF_body_r(&data.ctx); ++#else ++#define BF_body() \ ++ L = R = 0; \ ++ ptr = data.ctx.P; \ ++ do { \ ++ ptr += 2; \ ++ BF_ENCRYPT; \ ++ *(ptr - 2) = L; \ ++ *(ptr - 1) = R; \ ++ } while (ptr < &data.ctx.P[BF_N + 2]); \ ++\ ++ ptr = data.ctx.S[0]; \ ++ do { \ ++ ptr += 2; \ ++ BF_ENCRYPT; \ ++ *(ptr - 2) = L; \ ++ *(ptr - 1) = R; \ ++ } while (ptr < &data.ctx.S[3][0xFF]); ++#endif ++ ++static void BF_set_key(__CONST char *key, BF_key expanded, BF_key initial) ++{ ++ __CONST char *ptr = key; ++ int i, j; ++ BF_word tmp; ++ ++ for (i = 0; i < BF_N + 2; i++) { ++ tmp = 0; ++ for (j = 0; j < 4; j++) { ++ tmp <<= 8; ++ tmp |= *ptr; ++ ++ if (!*ptr) ptr = key; else ptr++; ++ } ++ ++ expanded[i] = tmp; ++ initial[i] = BF_init_state.P[i] ^ tmp; ++ } ++} ++ ++char *_crypt_blowfish_rn(__CONST char *key, __CONST char *setting, ++ char *output, int size) ++{ ++#if BF_ASM ++ extern void _BF_body_r(BF_ctx *ctx); ++#endif ++ struct { ++ BF_ctx ctx; ++ BF_key expanded_key; ++ union { ++ BF_word salt[4]; ++ BF_word output[6]; ++ } binary; ++ } data; ++ BF_word L, R; ++ BF_word tmp1, tmp2, tmp3, tmp4; ++ BF_word *ptr; ++ BF_word count; ++ int i; ++ ++ if (size < 7 + 22 + 31 + 1) { ++ __set_errno(ERANGE); ++ return NULL; ++ } ++ ++ if (setting[0] != '$' || ++ setting[1] != '2' || ++ setting[2] != 'a' || ++ setting[3] != '$' || ++ setting[4] < '0' || setting[4] > '3' || ++ setting[5] < '0' || setting[5] > '9' || ++ setting[6] != '$') { ++ __set_errno(EINVAL); ++ return NULL; ++ } ++ ++ count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); ++ if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16)) { ++ clean(data.binary.salt, sizeof(data.binary.salt)); ++ __set_errno(EINVAL); ++ return NULL; ++ } ++ ++ BF_swap(data.binary.salt, 4); ++ ++ BF_set_key(key, data.expanded_key, data.ctx.P); ++ ++ memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); ++ ++ L = R = 0; ++ for (i = 0; i < BF_N + 2; i += 2) { ++ L ^= data.binary.salt[i & 2]; ++ R ^= data.binary.salt[(i & 2) + 1]; ++ BF_ENCRYPT; ++ data.ctx.P[i] = L; ++ data.ctx.P[i + 1] = R; ++ } ++ ++ ptr = data.ctx.S[0]; ++ do { ++ ptr += 4; ++ L ^= data.binary.salt[(BF_N + 2) & 3]; ++ R ^= data.binary.salt[(BF_N + 3) & 3]; ++ BF_ENCRYPT; ++ *(ptr - 4) = L; ++ *(ptr - 3) = R; ++ ++ L ^= data.binary.salt[(BF_N + 4) & 3]; ++ R ^= data.binary.salt[(BF_N + 5) & 3]; ++ BF_ENCRYPT; ++ *(ptr - 2) = L; ++ *(ptr - 1) = R; ++ } while (ptr < &data.ctx.S[3][0xFF]); ++ ++ do { ++ data.ctx.P[0] ^= data.expanded_key[0]; ++ data.ctx.P[1] ^= data.expanded_key[1]; ++ data.ctx.P[2] ^= data.expanded_key[2]; ++ data.ctx.P[3] ^= data.expanded_key[3]; ++ data.ctx.P[4] ^= data.expanded_key[4]; ++ data.ctx.P[5] ^= data.expanded_key[5]; ++ data.ctx.P[6] ^= data.expanded_key[6]; ++ data.ctx.P[7] ^= data.expanded_key[7]; ++ data.ctx.P[8] ^= data.expanded_key[8]; ++ data.ctx.P[9] ^= data.expanded_key[9]; ++ data.ctx.P[10] ^= data.expanded_key[10]; ++ data.ctx.P[11] ^= data.expanded_key[11]; ++ data.ctx.P[12] ^= data.expanded_key[12]; ++ data.ctx.P[13] ^= data.expanded_key[13]; ++ data.ctx.P[14] ^= data.expanded_key[14]; ++ data.ctx.P[15] ^= data.expanded_key[15]; ++ data.ctx.P[16] ^= data.expanded_key[16]; ++ data.ctx.P[17] ^= data.expanded_key[17]; ++ ++ BF_body(); ++ ++ tmp1 = data.binary.salt[0]; ++ tmp2 = data.binary.salt[1]; ++ tmp3 = data.binary.salt[2]; ++ tmp4 = data.binary.salt[3]; ++ data.ctx.P[0] ^= tmp1; ++ data.ctx.P[1] ^= tmp2; ++ data.ctx.P[2] ^= tmp3; ++ data.ctx.P[3] ^= tmp4; ++ data.ctx.P[4] ^= tmp1; ++ data.ctx.P[5] ^= tmp2; ++ data.ctx.P[6] ^= tmp3; ++ data.ctx.P[7] ^= tmp4; ++ data.ctx.P[8] ^= tmp1; ++ data.ctx.P[9] ^= tmp2; ++ data.ctx.P[10] ^= tmp3; ++ data.ctx.P[11] ^= tmp4; ++ data.ctx.P[12] ^= tmp1; ++ data.ctx.P[13] ^= tmp2; ++ data.ctx.P[14] ^= tmp3; ++ data.ctx.P[15] ^= tmp4; ++ data.ctx.P[16] ^= tmp1; ++ data.ctx.P[17] ^= tmp2; ++ ++ BF_body(); ++ } while (--count); ++ ++ for (i = 0; i < 6; i += 2) { ++ L = BF_magic_w[i]; ++ R = BF_magic_w[i + 1]; ++ ++ count = 64; ++ do { ++ BF_ENCRYPT; ++ } while (--count); ++ ++ data.binary.output[i] = L; ++ data.binary.output[i + 1] = R; ++ } ++ ++ memcpy(output, setting, 7 + 22 - 1); ++ output[7 + 22 - 1] = BF_itoa64[(int) ++ BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30]; ++ ++/* This has to be bug-compatible with the original implementation, so ++ * only encode 23 of the 24 bytes. :-) */ ++ BF_swap(data.binary.output, 6); ++ BF_encode(&output[7 + 22], data.binary.output, 23); ++ output[7 + 22 + 31] = '\0'; ++ ++/* Overwrite the most obvious sensitive data we have on the stack. Note ++ * that this does not guarantee there's no sensitive data left on the ++ * stack and/or in registers; I'm not aware of portable code that does. */ ++ clean(&data, sizeof(data)); ++ ++ return output; ++} ++ ++char *_crypt_gensalt_blowfish_rn(unsigned long count, ++ __CONST char *input, int size, char *output, int output_size) ++{ ++ if (size < 16 || output_size < 7 + 22 + 1 || ++ (count && (count < 4 || count > 31))) { ++ if (output_size > 0) output[0] = '\0'; ++ __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); ++ return NULL; ++ } ++ ++ if (!count) count = 5; ++ ++ output[0] = '$'; ++ output[1] = '2'; ++ output[2] = 'a'; ++ output[3] = '$'; ++ output[4] = '0' + count / 10; ++ output[5] = '0' + count % 10; ++ output[6] = '$'; ++ ++ BF_encode(&output[7], (BF_word *)input, 16); ++ output[7 + 22] = '\0'; ++ ++ return output; ++} +diff -Nura php-4.4.0/ext/standard/crypt.c hardening-patch-4.4.0-0.4.2/ext/standard/crypt.c +--- php-4.4.0/ext/standard/crypt.c 2004-01-19 04:16:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/standard/crypt.c 2005-09-07 18:57:43.585680696 +0200 +@@ -100,6 +100,8 @@ + return SUCCESS; + } + ++char *_crypt_blowfish_rn(char *key, char *setting, char *output, int size); ++char *_crypt_gensalt_blowfish_rn(unsigned long count, char *input, int size, char *output, int output_size); + + static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +@@ -135,7 +137,14 @@ + + /* The automatic salt generation only covers standard DES and md5-crypt */ + if(!*salt) { +-#if PHP_MD5_CRYPT ++#if PHP_BLOWFISH_CRYPT ++ char randat[16]; ++ int i; ++ ++ for (i=0; i<16; i++) randat[i] = PHP_CRYPT_RAND; ++ ++ _crypt_gensalt_blowfish_rn(5, randat, sizeof(randat), salt, sizeof(salt)); ++#elif PHP_MD5_CRYPT + strcpy(salt, "$1$"); + php_to64(&salt[3], PHP_CRYPT_RAND, 4); + php_to64(&salt[7], PHP_CRYPT_RAND, 4); +@@ -145,8 +154,24 @@ + salt[2] = '\0'; + #endif + } +- +- RETVAL_STRING(crypt(str, salt), 1); ++ ++ if (salt[0] == '$' && ++ salt[1] == '2' && ++ salt[2] == 'a' && ++ salt[3] == '$' && ++ salt[4] >= '0' && salt[4] <= '3' && ++ salt[5] >= '0' && salt[5] <= '9' && ++ salt[6] == '$') { ++ ++ char output[PHP_MAX_SALT_LEN+1]; ++ ++ output[0] = 0; ++ _crypt_blowfish_rn(str, salt, output, sizeof(output)); ++ RETVAL_STRING(output, 1); ++ ++ } else { ++ RETVAL_STRING(crypt(str, salt), 1); ++ } + } + /* }}} */ + #endif +diff -Nura php-4.4.0/ext/standard/dl.c hardening-patch-4.4.0-0.4.2/ext/standard/dl.c +--- php-4.4.0/ext/standard/dl.c 2003-01-29 16:40:24.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/standard/dl.c 2005-09-07 18:40:29.088948104 +0200 +@@ -182,8 +182,35 @@ + RETURN_FALSE; + } + module_entry = get_module(); ++ ++ /* check if Hardening-Patch is installed */ ++ if (module_entry->zend_api < 1000000000) { ++ php_error_docref(NULL TSRMLS_CC, error_type, ++ "%s: Unable to initialize module\n" ++ "Module compiled without Hardening-Patch, module API=%d, debug=%d, thread-safety=%d\n" ++ "PHP compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "These options need to match\n", ++ module_entry->name, module_entry->zend_api, module_entry->zend_debug, module_entry->zts, ++ HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS); ++ DL_UNLOAD(handle); ++ RETURN_FALSE; ++ } ++ ++ /* check if correct Hardening-Patch is installed */ ++ if (module_entry->zend_api != HARDENING_PATCH_ZEND_MODULE_API_NO) { ++ php_error_docref(NULL TSRMLS_CC, error_type, ++ "%s: Unable to initialize module\n" ++ "Module compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "PHP compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "These options need to match\n", ++ module_entry->name, module_entry->zend_api, module_entry->real_zend_api, module_entry->zend_debug, module_entry->zts, ++ HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS); ++ DL_UNLOAD(handle); ++ RETURN_FALSE; ++ } ++ + if ((module_entry->zend_debug != ZEND_DEBUG) || (module_entry->zts != USING_ZTS) +- || (module_entry->zend_api != ZEND_MODULE_API_NO)) { ++ || (module_entry->real_zend_api != ZEND_MODULE_API_NO)) { + /* Check for pre-4.1.0 module which has a slightly different module_entry structure :( */ + struct pre_4_1_0_module_entry { + char *name; +@@ -217,7 +244,7 @@ + zts = ((struct pre_4_1_0_module_entry *)module_entry)->zts; + } else { + name = module_entry->name; +- zend_api = module_entry->zend_api; ++ zend_api = module_entry->real_zend_api; + zend_debug = module_entry->zend_debug; + zts = module_entry->zts; + } +diff -Nura php-4.4.0/ext/standard/file.c hardening-patch-4.4.0-0.4.2/ext/standard/file.c +--- php-4.4.0/ext/standard/file.c 2005-03-27 17:53:59.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/ext/standard/file.c 2005-09-07 18:40:29.089947952 +0200 +@@ -2469,7 +2469,7 @@ + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) + /* {{{ proto string realpath(string path) + Return the resolved path */ +-PHP_FUNCTION(realpath) ++PHP_FUNCTION(real_path) + { + zval **path; + char resolved_path_buff[MAXPATHLEN]; +diff -Nura php-4.4.0/ext/standard/file.h hardening-patch-4.4.0-0.4.2/ext/standard/file.h +--- php-4.4.0/ext/standard/file.h 2004-06-21 21:33:47.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/ext/standard/file.h 2005-09-07 18:40:29.090947800 +0200 +@@ -64,7 +64,7 @@ + PHP_FUNCTION(fd_set); + PHP_FUNCTION(fd_isset); + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +-PHP_FUNCTION(realpath); ++PHP_FUNCTION(real_path); + #endif + #ifdef HAVE_FNMATCH + PHP_FUNCTION(fnmatch); +diff -Nura php-4.4.0/ext/standard/head.c hardening-patch-4.4.0-0.4.2/ext/standard/head.c +--- php-4.4.0/ext/standard/head.c 2005-01-07 22:14:23.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/standard/head.c 2005-09-07 18:40:29.090947800 +0200 +@@ -45,10 +45,31 @@ + { + zend_bool rep = 1; + sapi_header_line ctr = {0}; ++#if HARDENING_PATCH ++ int i; ++#endif + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &ctr.line, + &ctr.line_len, &rep, &ctr.response_code) == FAILURE) + return; ++ ++#if HARDENING_PATCH ++ if (!HG(hphp_multiheader)) { ++ for (i=0; i0 && (iPHP Version %s with Hardening-Patch %s\n", PHP_VERSION, HARDENING_PATCH_VERSION); ++ } else { ++ char temp_ver[40]; ++ ++ snprintf(temp_ver, sizeof(temp_ver), "%s/%s", PHP_VERSION, HARDENING_PATCH_VERSION); ++ php_info_print_table_row(2, "PHP/Hardening-Patch Version", temp_ver); ++ } ++#else + if (!sapi_module.phpinfo_as_text) { + php_printf("

PHP Version %s

\n", PHP_VERSION); + } else { + php_info_print_table_row(2, "PHP Version", PHP_VERSION); + } ++#endif + php_info_print_box_end(); + php_info_print_table_start(); + php_info_print_table_row(2, "System", php_uname ); +diff -Nura php-4.4.0/ext/standard/php_standard.h hardening-patch-4.4.0-0.4.2/ext/standard/php_standard.h +--- php-4.4.0/ext/standard/php_standard.h 2002-12-31 17:35:33.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/standard/php_standard.h 2005-09-07 18:52:04.985155800 +0200 +@@ -28,6 +28,7 @@ + #include "php_mail.h" + #include "md5.h" + #include "sha1.h" ++#include "sha256.h" + #include "html.h" + #include "exec.h" + #include "file.h" +diff -Nura php-4.4.0/ext/standard/sha256.c hardening-patch-4.4.0-0.4.2/ext/standard/sha256.c +--- php-4.4.0/ext/standard/sha256.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/standard/sha256.c 2005-09-07 14:19:05.000000000 +0200 +@@ -0,0 +1,398 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 5 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2004 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 3.0 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available through the world-wide-web at the following url: | ++ | http://www.php.net/license/3_0.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++*/ ++ ++/* $Id: sha256.c,v 1.9 2004/01/08 08:17:34 andi Exp $ */ ++ ++#include ++#include "php.h" ++ ++/* This code is heavily based on the PHP md5/sha1 implementations */ ++ ++#include "sha256.h" ++ ++PHPAPI void make_sha256_digest(char *sha256str, unsigned char *digest) ++{ ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ sprintf(sha256str, "%02x", digest[i]); ++ sha256str += 2; ++ } ++ ++ *sha256str = '\0'; ++} ++ ++/* {{{ proto string sha256(string str [, bool raw_output]) ++ Calculate the sha256 hash of a string */ ++PHP_FUNCTION(sha256) ++{ ++ char *arg; ++ int arg_len; ++ zend_bool raw_output = 0; ++ char sha256str[65]; ++ PHP_SHA256_CTX context; ++ unsigned char digest[32]; ++ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &arg, &arg_len, &raw_output) == FAILURE) { ++ return; ++ } ++ ++ sha256str[0] = '\0'; ++ PHP_SHA256Init(&context); ++ PHP_SHA256Update(&context, arg, arg_len); ++ PHP_SHA256Final(digest, &context); ++ if (raw_output) { ++ RETURN_STRINGL(digest, 32, 1); ++ } else { ++ make_sha256_digest(sha256str, digest); ++ RETVAL_STRING(sha256str, 1); ++ } ++ ++} ++ ++/* }}} */ ++ ++/* {{{ proto string sha256_file(string filename [, bool raw_output]) ++ Calculate the sha256 hash of given filename */ ++PHP_FUNCTION(sha256_file) ++{ ++ char *arg; ++ int arg_len; ++ zend_bool raw_output = 0; ++ char sha256str[65]; ++ unsigned char buf[1024]; ++ unsigned char digest[32]; ++ PHP_SHA256_CTX context; ++ int n; ++ FILE *fp; ++ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &arg, &arg_len, &raw_output) == FAILURE) { ++ return; ++ } ++ ++ if (PG(safe_mode) && (!php_checkuid(arg, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { ++ RETURN_FALSE; ++ } ++ ++ if (php_check_open_basedir(arg TSRMLS_CC)) { ++ RETURN_FALSE; ++ } ++ ++ if ((fp = VCWD_FOPEN(arg, "rb")) == NULL) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open file"); ++ RETURN_FALSE; ++ } ++ ++ PHP_SHA256Init(&context); ++ ++ while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { ++ PHP_SHA256Update(&context, buf, n); ++ } ++ ++ PHP_SHA256Final(digest, &context); ++ ++ if (ferror(fp)) { ++ fclose(fp); ++ RETURN_FALSE; ++ } ++ ++ fclose(fp); ++ ++ if (raw_output) { ++ RETURN_STRINGL(digest, 32, 1); ++ } else { ++ make_sha256_digest(sha256str, digest); ++ RETVAL_STRING(sha256str, 1); ++ } ++} ++/* }}} */ ++ ++ ++static void SHA256Transform(php_uint32[8], const unsigned char[64]); ++static void SHA256Encode(unsigned char *, php_uint32 *, unsigned int); ++static void SHA256Decode(php_uint32 *, const unsigned char *, unsigned int); ++ ++static unsigned char PADDING[64] = ++{ ++ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ++}; ++ ++/* F, G, H and I are basic SHA256 functions. ++ */ ++#define F(x) (ROTATE_RIGHT(x,2) ^ ROTATE_RIGHT(x,13) ^ ROTATE_RIGHT(x,22)) ++#define G(x, y, z) (((x) & (y)) | ((z) & ((y) | (x)))) ++#define H(x) (ROTATE_RIGHT(x,6) ^ ROTATE_RIGHT(x,11) ^ ROTATE_RIGHT(x,25)) ++#define I(x, y, z) (((x) & (y)) | ((~x) & z)) ++ ++/* ROTATE_RIGHT rotates x right n bits. ++ */ ++#define ROTATE_RIGHT(x, n) (((x) >> (n)) | ((x) << (32-(n)))) ++ ++/* W[i] ++ */ ++#define W(i) ( tmp1=ROTATE_RIGHT(x[(i-15)&15],7)^ROTATE_RIGHT(x[(i-15)&15],18)^(x[(i-15)&15] >> 3), \ ++ tmp2=ROTATE_RIGHT(x[(i-2)&15],17)^ROTATE_RIGHT(x[(i-2)&15],19)^(x[(i-2)&15] >> 10), \ ++ (x[i&15]=x[i&15] + tmp1 + x[(i-7)&15] + tmp2) ) ++ ++/* ROUND function of sha256 ++ */ ++ ++#define ROUND(a,b,c,d,e,f,g,h,w,k) { \ ++ t1 = (h) + H((e)) + I((e), (f), (g)) + (k) + (php_uint32)(w); \ ++ (h) = F((a)) + G((a), (b), (c)) + t1; \ ++ (d) += t1; \ ++ } ++ ++ ++/* {{{ PHP_SHA256Init ++ * SHA256 initialization. Begins an SHA256 operation, writing a new context. ++ */ ++PHPAPI void PHP_SHA256Init(PHP_SHA256_CTX * context) ++{ ++ context->count[0] = context->count[1] = 0; ++ /* Load magic initialization constants. ++ */ ++ context->state[0] = 0x6a09e667; ++ context->state[1] = 0xbb67ae85; ++ context->state[2] = 0x3c6ef372; ++ context->state[3] = 0xa54ff53a; ++ context->state[4] = 0x510e527f; ++ context->state[5] = 0x9b05688c; ++ context->state[6] = 0x1f83d9ab; ++ context->state[7] = 0x5be0cd19; ++} ++/* }}} */ ++ ++/* {{{ PHP_SHA256Update ++ SHA256 block update operation. Continues an SHA256 message-digest ++ operation, processing another message block, and updating the ++ context. ++ */ ++PHPAPI void PHP_SHA256Update(PHP_SHA256_CTX * context, const unsigned char *input, ++ unsigned int inputLen) ++{ ++ unsigned int i, index, partLen; ++ ++ /* Compute number of bytes mod 64 */ ++ index = (unsigned int) ((context->count[0] >> 3) & 0x3F); ++ ++ /* Update number of bits */ ++ if ((context->count[0] += ((php_uint32) inputLen << 3)) ++ < ((php_uint32) inputLen << 3)) ++ context->count[1]++; ++ context->count[1] += ((php_uint32) inputLen >> 29); ++ ++ partLen = 64 - index; ++ ++ /* Transform as many times as possible. ++ */ ++ if (inputLen >= partLen) { ++ memcpy ++ ((unsigned char*) & context->buffer[index], (unsigned char*) input, partLen); ++ SHA256Transform(context->state, context->buffer); ++ ++ for (i = partLen; i + 63 < inputLen; i += 64) ++ SHA256Transform(context->state, &input[i]); ++ ++ index = 0; ++ } else ++ i = 0; ++ ++ /* Buffer remaining input */ ++ memcpy ++ ((unsigned char*) & context->buffer[index], (unsigned char*) & input[i], ++ inputLen - i); ++} ++/* }}} */ ++ ++/* {{{ PHP_SHA256Final ++ SHA256 finalization. Ends an SHA256 message-digest operation, writing the ++ the message digest and zeroizing the context. ++ */ ++PHPAPI void PHP_SHA256Final(unsigned char digest[32], PHP_SHA256_CTX * context) ++{ ++ unsigned char bits[8]; ++ unsigned int index, padLen; ++ ++ /* Save number of bits */ ++ bits[7] = context->count[0] & 0xFF; ++ bits[6] = (context->count[0] >> 8) & 0xFF; ++ bits[5] = (context->count[0] >> 16) & 0xFF; ++ bits[4] = (context->count[0] >> 24) & 0xFF; ++ bits[3] = context->count[1] & 0xFF; ++ bits[2] = (context->count[1] >> 8) & 0xFF; ++ bits[1] = (context->count[1] >> 16) & 0xFF; ++ bits[0] = (context->count[1] >> 24) & 0xFF; ++ ++ /* Pad out to 56 mod 64. ++ */ ++ index = (unsigned int) ((context->count[0] >> 3) & 0x3f); ++ padLen = (index < 56) ? (56 - index) : (120 - index); ++ PHP_SHA256Update(context, PADDING, padLen); ++ ++ /* Append length (before padding) */ ++ PHP_SHA256Update(context, bits, 8); ++ ++ /* Store state in digest */ ++ SHA256Encode(digest, context->state, 32); ++ ++ /* Zeroize sensitive information. ++ */ ++ memset((unsigned char*) context, 0, sizeof(*context)); ++} ++/* }}} */ ++ ++/* {{{ SHA256Transform ++ * SHA256 basic transformation. Transforms state based on block. ++ */ ++static void SHA256Transform(state, block) ++php_uint32 state[8]; ++const unsigned char block[64]; ++{ ++ php_uint32 a = state[0], b = state[1], c = state[2]; ++ php_uint32 d = state[3], e = state[4], f = state[5]; ++ php_uint32 g = state[6], h = state[7], x[16], tmp1, tmp2, t1; ++ ++ SHA256Decode(x, block, 64); ++ ++ ROUND(a, b, c, d, e, f, g, h, x[0], 0x428a2f98) ++ ROUND(h, a, b, c, d, e, f, g, x[1], 0x71374491) ++ ROUND(g, h, a, b, c, d, e, f, x[2], 0xb5c0fbcf) ++ ROUND(f, g, h, a, b, c, d, e, x[3], 0xe9b5dba5) ++ ROUND(e, f, g, h, a, b, c, d, x[4], 0x3956c25b) ++ ROUND(d, e, f, g, h, a, b, c, x[5], 0x59f111f1) ++ ROUND(c, d, e, f, g, h, a, b, x[6], 0x923f82a4) ++ ROUND(b, c, d, e, f, g, h, a, x[7], 0xab1c5ed5) ++ ROUND(a, b, c, d, e, f, g, h, x[8], 0xd807aa98) ++ ROUND(h, a, b, c, d, e, f, g, x[9], 0x12835b01) ++ ROUND(g, h, a, b, c, d, e, f, x[10], 0x243185be) ++ ROUND(f, g, h, a, b, c, d, e, x[11], 0x550c7dc3) ++ ROUND(e, f, g, h, a, b, c, d, x[12], 0x72be5d74) ++ ROUND(d, e, f, g, h, a, b, c, x[13], 0x80deb1fe) ++ ROUND(c, d, e, f, g, h, a, b, x[14], 0x9bdc06a7) ++ ROUND(b, c, d, e, f, g, h, a, x[15], 0xc19bf174) ++ ROUND(a, b, c, d, e, f, g, h, W(16), 0xe49b69c1) ++ ROUND(h, a, b, c, d, e, f, g, W(17), 0xefbe4786) ++ ROUND(g, h, a, b, c, d, e, f, W(18), 0x0fc19dc6) ++ ROUND(f, g, h, a, b, c, d, e, W(19), 0x240ca1cc) ++ ROUND(e, f, g, h, a, b, c, d, W(20), 0x2de92c6f) ++ ROUND(d, e, f, g, h, a, b, c, W(21), 0x4a7484aa) ++ ROUND(c, d, e, f, g, h, a, b, W(22), 0x5cb0a9dc) ++ ROUND(b, c, d, e, f, g, h, a, W(23), 0x76f988da) ++ ROUND(a, b, c, d, e, f, g, h, W(24), 0x983e5152) ++ ROUND(h, a, b, c, d, e, f, g, W(25), 0xa831c66d) ++ ROUND(g, h, a, b, c, d, e, f, W(26), 0xb00327c8) ++ ROUND(f, g, h, a, b, c, d, e, W(27), 0xbf597fc7) ++ ROUND(e, f, g, h, a, b, c, d, W(28), 0xc6e00bf3) ++ ROUND(d, e, f, g, h, a, b, c, W(29), 0xd5a79147) ++ ROUND(c, d, e, f, g, h, a, b, W(30), 0x06ca6351) ++ ROUND(b, c, d, e, f, g, h, a, W(31), 0x14292967) ++ ROUND(a, b, c, d, e, f, g, h, W(32), 0x27b70a85) ++ ROUND(h, a, b, c, d, e, f, g, W(33), 0x2e1b2138) ++ ROUND(g, h, a, b, c, d, e, f, W(34), 0x4d2c6dfc) ++ ROUND(f, g, h, a, b, c, d, e, W(35), 0x53380d13) ++ ROUND(e, f, g, h, a, b, c, d, W(36), 0x650a7354) ++ ROUND(d, e, f, g, h, a, b, c, W(37), 0x766a0abb) ++ ROUND(c, d, e, f, g, h, a, b, W(38), 0x81c2c92e) ++ ROUND(b, c, d, e, f, g, h, a, W(39), 0x92722c85) ++ ROUND(a, b, c, d, e, f, g, h, W(40), 0xa2bfe8a1) ++ ROUND(h, a, b, c, d, e, f, g, W(41), 0xa81a664b) ++ ROUND(g, h, a, b, c, d, e, f, W(42), 0xc24b8b70) ++ ROUND(f, g, h, a, b, c, d, e, W(43), 0xc76c51a3) ++ ROUND(e, f, g, h, a, b, c, d, W(44), 0xd192e819) ++ ROUND(d, e, f, g, h, a, b, c, W(45), 0xd6990624) ++ ROUND(c, d, e, f, g, h, a, b, W(46), 0xf40e3585) ++ ROUND(b, c, d, e, f, g, h, a, W(47), 0x106aa070) ++ ROUND(a, b, c, d, e, f, g, h, W(48), 0x19a4c116) ++ ROUND(h, a, b, c, d, e, f, g, W(49), 0x1e376c08) ++ ROUND(g, h, a, b, c, d, e, f, W(50), 0x2748774c) ++ ROUND(f, g, h, a, b, c, d, e, W(51), 0x34b0bcb5) ++ ROUND(e, f, g, h, a, b, c, d, W(52), 0x391c0cb3) ++ ROUND(d, e, f, g, h, a, b, c, W(53), 0x4ed8aa4a) ++ ROUND(c, d, e, f, g, h, a, b, W(54), 0x5b9cca4f) ++ ROUND(b, c, d, e, f, g, h, a, W(55), 0x682e6ff3) ++ ROUND(a, b, c, d, e, f, g, h, W(56), 0x748f82ee) ++ ROUND(h, a, b, c, d, e, f, g, W(57), 0x78a5636f) ++ ROUND(g, h, a, b, c, d, e, f, W(58), 0x84c87814) ++ ROUND(f, g, h, a, b, c, d, e, W(59), 0x8cc70208) ++ ROUND(e, f, g, h, a, b, c, d, W(60), 0x90befffa) ++ ROUND(d, e, f, g, h, a, b, c, W(61), 0xa4506ceb) ++ ROUND(c, d, e, f, g, h, a, b, W(62), 0xbef9a3f7) ++ ROUND(b, c, d, e, f, g, h, a, W(63), 0xc67178f2) ++ ++ state[0] += a; ++ state[1] += b; ++ state[2] += c; ++ state[3] += d; ++ state[4] += e; ++ state[5] += f; ++ state[6] += g; ++ state[7] += h; ++ ++ /* Zeroize sensitive information. */ ++ memset((unsigned char*) x, 0, sizeof(x)); ++} ++/* }}} */ ++ ++/* {{{ SHA256Encode ++ Encodes input (php_uint32) into output (unsigned char). Assumes len is ++ a multiple of 4. ++ */ ++static void SHA256Encode(output, input, len) ++unsigned char *output; ++php_uint32 *input; ++unsigned int len; ++{ ++ unsigned int i, j; ++ ++ for (i = 0, j = 0; j < len; i++, j += 4) { ++ output[j] = (unsigned char) ((input[i] >> 24) & 0xff); ++ output[j + 1] = (unsigned char) ((input[i] >> 16) & 0xff); ++ output[j + 2] = (unsigned char) ((input[i] >> 8) & 0xff); ++ output[j + 3] = (unsigned char) (input[i] & 0xff); ++ } ++} ++/* }}} */ ++ ++/* {{{ SHA256Decode ++ Decodes input (unsigned char) into output (php_uint32). Assumes len is ++ a multiple of 4. ++ */ ++static void SHA256Decode(output, input, len) ++php_uint32 *output; ++const unsigned char *input; ++unsigned int len; ++{ ++ unsigned int i, j; ++ ++ for (i = 0, j = 0; j < len; i++, j += 4) ++ output[i] = ((php_uint32) input[j + 3]) | (((php_uint32) input[j + 2]) << 8) | ++ (((php_uint32) input[j + 1]) << 16) | (((php_uint32) input[j]) << 24); ++} ++/* }}} */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-4.4.0/ext/standard/sha256.h hardening-patch-4.4.0-0.4.2/ext/standard/sha256.h +--- php-4.4.0/ext/standard/sha256.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/standard/sha256.h 2005-09-07 14:19:05.000000000 +0200 +@@ -0,0 +1,40 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 5 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2004 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 3.0 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available through the world-wide-web at the following url: | ++ | http://www.php.net/license/3_0.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++*/ ++ ++/* $Id: sha256.h,v 1.4 2004/01/08 17:32:52 sniper Exp $ */ ++ ++#ifndef SHA256_H ++#define SHA256_H ++ ++#include "ext/standard/basic_functions.h" ++ ++/* SHA1 context. */ ++typedef struct { ++ php_uint32 state[8]; /* state (ABCD) */ ++ php_uint32 count[2]; /* number of bits, modulo 2^64 (lsb first) */ ++ unsigned char buffer[64]; /* input buffer */ ++} PHP_SHA256_CTX; ++ ++PHPAPI void PHP_SHA256Init(PHP_SHA256_CTX *); ++PHPAPI void PHP_SHA256Update(PHP_SHA256_CTX *, const unsigned char *, unsigned int); ++PHPAPI void PHP_SHA256Final(unsigned char[32], PHP_SHA256_CTX *); ++ ++PHP_FUNCTION(sha256); ++PHP_FUNCTION(sha256_file); ++ ++#endif +diff -Nura php-4.4.0/ext/standard/syslog.c hardening-patch-4.4.0-0.4.2/ext/standard/syslog.c +--- php-4.4.0/ext/standard/syslog.c 2004-07-30 16:38:29.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/ext/standard/syslog.c 2005-09-07 18:40:29.091947648 +0200 +@@ -42,6 +42,8 @@ + */ + PHP_MINIT_FUNCTION(syslog) + { ++ ++#if !HARDENING_PATCH + /* error levels */ + REGISTER_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ + REGISTER_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ +@@ -97,7 +99,7 @@ + /* AIX doesn't have LOG_PERROR */ + REGISTER_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ + #endif +- ++#endif + return SUCCESS; + } + /* }}} */ +diff -Nura php-4.4.0/ext/varfilter/config.m4 hardening-patch-4.4.0-0.4.2/ext/varfilter/config.m4 +--- php-4.4.0/ext/varfilter/config.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/varfilter/config.m4 2005-09-07 18:40:29.092947496 +0200 +@@ -0,0 +1,11 @@ ++dnl ++dnl $Id: config.m4,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++dnl ++ ++PHP_ARG_ENABLE(varfilter, whether to enable Hardening-Patch's variable filter, ++[ --disable-varfilter Disable Hardening-Patch's variable filter], yes) ++ ++if test "$PHP_VARFILTER" != "no"; then ++ AC_DEFINE(HAVE_VARFILTER, 1, [ ]) ++ PHP_NEW_EXTENSION(varfilter, varfilter.c, $ext_shared) ++fi +diff -Nura php-4.4.0/ext/varfilter/CREDITS hardening-patch-4.4.0-0.4.2/ext/varfilter/CREDITS +--- php-4.4.0/ext/varfilter/CREDITS 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/varfilter/CREDITS 2005-09-07 18:40:29.092947496 +0200 +@@ -0,0 +1,2 @@ ++varfilter ++Stefan Esser +\ Kein Zeilenumbruch am Dateiende. +diff -Nura php-4.4.0/ext/varfilter/php_varfilter.h hardening-patch-4.4.0-0.4.2/ext/varfilter/php_varfilter.h +--- php-4.4.0/ext/varfilter/php_varfilter.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/varfilter/php_varfilter.h 2005-09-07 18:40:29.092947496 +0200 +@@ -0,0 +1,111 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: php_varfilter.h,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifndef PHP_VARFILTER_H ++#define PHP_VARFILTER_H ++ ++extern zend_module_entry varfilter_module_entry; ++#define phpext_varfilter_ptr &varfilter_module_entry ++ ++#ifdef PHP_WIN32 ++#define PHP_VARFILTER_API __declspec(dllexport) ++#else ++#define PHP_VARFILTER_API ++#endif ++ ++#ifdef ZTS ++#include "TSRM.h" ++#endif ++ ++#include "SAPI.h" ++ ++#include "php_variables.h" ++ ++ ++PHP_MINIT_FUNCTION(varfilter); ++PHP_MSHUTDOWN_FUNCTION(varfilter); ++PHP_RINIT_FUNCTION(varfilter); ++PHP_RSHUTDOWN_FUNCTION(varfilter); ++PHP_MINFO_FUNCTION(varfilter); ++ ++ ++ZEND_BEGIN_MODULE_GLOBALS(varfilter) ++/* request variables */ ++ long max_request_variables; ++ long cur_request_variables; ++ long max_varname_length; ++ long max_totalname_length; ++ long max_value_length; ++ long max_array_depth; ++ long max_array_index_length; ++/* cookie variables */ ++ long max_cookie_vars; ++ long cur_cookie_vars; ++ long max_cookie_name_length; ++ long max_cookie_totalname_length; ++ long max_cookie_value_length; ++ long max_cookie_array_depth; ++ long max_cookie_array_index_length; ++/* get variables */ ++ long max_get_vars; ++ long cur_get_vars; ++ long max_get_name_length; ++ long max_get_totalname_length; ++ long max_get_value_length; ++ long max_get_array_depth; ++ long max_get_array_index_length; ++/* post variables */ ++ long max_post_vars; ++ long cur_post_vars; ++ long max_post_name_length; ++ long max_post_totalname_length; ++ long max_post_value_length; ++ long max_post_array_depth; ++ long max_post_array_index_length; ++/* fileupload */ ++ long max_uploads; ++ long cur_uploads; ++ zend_bool disallow_elf_files; ++ char *verification_script; ++ ++ZEND_END_MODULE_GLOBALS(varfilter) ++ ++ ++#ifdef ZTS ++#define VARFILTER_G(v) TSRMG(varfilter_globals_id, zend_varfilter_globals *, v) ++#else ++#define VARFILTER_G(v) (varfilter_globals.v) ++#endif ++ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter); ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter); ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter); ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter); ++ ++#endif /* PHP_VARFILTER_H */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * indent-tabs-mode: t ++ * End: ++ */ +diff -Nura php-4.4.0/ext/varfilter/varfilter.c hardening-patch-4.4.0-0.4.2/ext/varfilter/varfilter.c +--- php-4.4.0/ext/varfilter/varfilter.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/ext/varfilter/varfilter.c 2005-09-07 18:47:32.454586744 +0200 +@@ -0,0 +1,602 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: varfilter.c,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "php.h" ++#include "php_ini.h" ++#include "ext/standard/info.h" ++#include "php_varfilter.h" ++#include "hardening_patch.h" ++ ++ZEND_DECLARE_MODULE_GLOBALS(varfilter) ++ ++/* True global resources - no need for thread safety here */ ++static int le_varfilter; ++ ++/* {{{ varfilter_module_entry ++ */ ++zend_module_entry varfilter_module_entry = { ++#if ZEND_MODULE_API_NO >= 20010901 ++ STANDARD_MODULE_HEADER, ++#endif ++ "varfilter", ++ NULL, ++ PHP_MINIT(varfilter), ++ PHP_MSHUTDOWN(varfilter), ++ PHP_RINIT(varfilter), /* Replace with NULL if there's nothing to do at request start */ ++ PHP_RSHUTDOWN(varfilter), /* Replace with NULL if there's nothing to do at request end */ ++ PHP_MINFO(varfilter), ++#if ZEND_MODULE_API_NO >= 20010901 ++ "0.3.2", /* Replace with version number for your extension */ ++#endif ++ STANDARD_MODULE_PROPERTIES ++}; ++/* }}} */ ++ ++#ifdef COMPILE_DL_VARFILTER ++ZEND_GET_MODULE(varfilter) ++#endif ++ ++/* {{{ PHP_INI ++ */ ++PHP_INI_BEGIN() ++ /* for backward compatibility */ ++ STD_PHP_INI_ENTRY("varfilter.max_request_variables", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.request.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.cookie.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_cookie_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_value_length", "10000", PHP_INI_PERDIR, OnUpdateLong, max_cookie_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.get.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_get_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_get_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_value_length", "512", PHP_INI_PERDIR, OnUpdateLong, max_get_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_depth", "50", PHP_INI_PERDIR, OnUpdateLong, max_get_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.post.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_post_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_post_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_post_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_post_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.upload.max_uploads", "25", PHP_INI_PERDIR, OnUpdateLong, max_uploads, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.disallow_elf_files", "1", PHP_INI_SYSTEM, OnUpdateBool, disallow_elf_files, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.verification_script", NULL, PHP_INI_SYSTEM, OnUpdateString, verification_script, zend_varfilter_globals, varfilter_globals) ++ ++ ++PHP_INI_END() ++/* }}} */ ++ ++/* {{{ php_varfilter_init_globals ++ */ ++static void php_varfilter_init_globals(zend_varfilter_globals *varfilter_globals) ++{ ++ varfilter_globals->max_request_variables = 200; ++ varfilter_globals->max_varname_length = 64; ++ varfilter_globals->max_value_length = 10000; ++ varfilter_globals->max_array_depth = 100; ++ varfilter_globals->max_totalname_length = 256; ++ varfilter_globals->max_array_index_length = 64; ++ ++ varfilter_globals->max_cookie_vars = 100; ++ varfilter_globals->max_cookie_name_length = 64; ++ varfilter_globals->max_cookie_totalname_length = 256; ++ varfilter_globals->max_cookie_value_length = 10000; ++ varfilter_globals->max_cookie_array_depth = 100; ++ varfilter_globals->max_cookie_array_index_length = 64; ++ ++ varfilter_globals->max_get_vars = 100; ++ varfilter_globals->max_get_name_length = 64; ++ varfilter_globals->max_get_totalname_length = 256; ++ varfilter_globals->max_get_value_length = 512; ++ varfilter_globals->max_get_array_depth = 50; ++ varfilter_globals->max_get_array_index_length = 64; ++ ++ varfilter_globals->max_post_vars = 200; ++ varfilter_globals->max_post_name_length = 64; ++ varfilter_globals->max_post_totalname_length = 256; ++ varfilter_globals->max_post_value_length = 65000; ++ varfilter_globals->max_post_array_depth = 100; ++ varfilter_globals->max_post_array_index_length = 64; ++ ++ varfilter_globals->max_uploads = 25; ++ varfilter_globals->disallow_elf_files = 1; ++ varfilter_globals->verification_script = NULL; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINIT_FUNCTION ++ */ ++PHP_MINIT_FUNCTION(varfilter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(varfilter, php_varfilter_init_globals, NULL); ++ REGISTER_INI_ENTRIES(); ++ ++ sapi_register_input_filter(varfilter_input_filter); ++ sapi_register_pre_upload_filter(varfilter_pre_upload_filter); ++ sapi_register_upload_content_filter(varfilter_upload_content_filter); ++ sapi_register_post_upload_filter(varfilter_post_upload_filter); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MSHUTDOWN_FUNCTION ++ */ ++PHP_MSHUTDOWN_FUNCTION(varfilter) ++{ ++ UNREGISTER_INI_ENTRIES(); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request start */ ++/* {{{ PHP_RINIT_FUNCTION ++ */ ++PHP_RINIT_FUNCTION(varfilter) ++{ ++ VARFILTER_G(cur_request_variables) = 0; ++ VARFILTER_G(cur_get_vars) = 0; ++ VARFILTER_G(cur_post_vars) = 0; ++ VARFILTER_G(cur_cookie_vars) = 0; ++ ++ VARFILTER_G(cur_uploads) = 0; ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request end */ ++/* {{{ PHP_RSHUTDOWN_FUNCTION ++ */ ++PHP_RSHUTDOWN_FUNCTION(varfilter) ++{ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINFO_FUNCTION ++ */ ++PHP_MINFO_FUNCTION(varfilter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_header(2, "Hardening-Patch's variable filter support", "enabled"); ++ php_info_print_table_end(); ++ ++ DISPLAY_INI_ENTRIES(); ++} ++/* }}} */ ++ ++/* {{{ normalize_varname ++ */ ++static void normalize_varname(char *varname) ++{ ++ char *s=varname, *index=NULL, *indexend=NULL, *p; ++ ++ /* overjump leading space */ ++ while (*s == ' ') { ++ s++; ++ } ++ ++ /* and remove it */ ++ if (s != varname) { ++ memmove(varname, s, strlen(s)+1); ++ } ++ ++ for (p=varname; *p && *p != '['; p++) { ++ switch(*p) { ++ case ' ': ++ case '.': ++ *p='_'; ++ break; ++ } ++ } ++ ++ /* find index */ ++ index = strchr(varname, '['); ++ if (index) { ++ index++; ++ s=index; ++ } else { ++ return; ++ } ++ ++ /* done? */ ++ while (index) { ++ ++ while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') { ++ index++; ++ } ++ indexend = strchr(index, ']'); ++ indexend = indexend ? indexend + 1 : index + strlen(index); ++ ++ if (s != index) { ++ memmove(s, index, strlen(index)+1); ++ s += indexend-index; ++ } else { ++ s = indexend; ++ } ++ ++ if (*s == '[') { ++ s++; ++ index = s; ++ } else { ++ index = NULL; ++ } ++ } ++ *s++='\0'; ++} ++/* }}} */ ++ ++/* {{{ SAPI_PRE_UPLOAD_FILTER_FUNC ++ */ ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter) ++{ ++ /* Drop this fileupload if the limit is reached */ ++ if (VARFILTER_G(max_uploads) && VARFILTER_G(max_uploads) <= VARFILTER_G(cur_uploads)) { ++ php_security_log(S_FILES, "configured fileupload limit exceeded - file dropped"); ++ return FAILURE; ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_UPLOAD_CONTENT_FILTER_FUNC ++ */ ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter) ++{ ++ ++ if (VARFILTER_G(disallow_elf_files)) { ++ ++ if (offset == 0 && buffer_len > 10) { ++ ++ if (buffer[0] == 0x7F && buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F') { ++ php_security_log(S_FILES, "uploaded file is an ELF executable - file dropped"); ++ return FAILURE; ++ } ++ } ++ ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_POST_UPLOAD_FILTER_FUNC ++ */ ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter) ++{ ++ int retval = SUCCESS; ++ ++ if (VARFILTER_G(verification_script)) { ++ char cmd[8192]; ++ FILE *in; ++ int first=1; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s", VARFILTER_G(verification_script), tmpfilename); ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_FILES, "unable to execute fileupload verification script %s - file dropped", VARFILTER_G(verification_script)); ++ return FAILURE; ++ } ++ ++ retval = FAILURE; ++ ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ if (first) { ++ retval = atoi(cmd) == 1 ? SUCCESS : FAILURE; ++ first = 0; ++ } ++ } ++ pclose(in); ++ } ++ ++ if (retval != SUCCESS) { ++ php_security_log(S_FILES, "fileupload verification script disallows file - file dropped"); ++ return FAILURE; ++ } ++ ++ VARFILTER_G(cur_uploads)++; ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_INPUT_FILTER_FUNC ++ */ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter) ++{ ++ char *index, *prev_index = NULL, *copy_var; ++ unsigned int var_len, total_len, depth = 0, rv; ++ ++ /* Drop this variable if the limit is reached */ ++ if (VARFILTER_G(max_request_variables) && VARFILTER_G(max_request_variables) <= VARFILTER_G(cur_request_variables)) { ++ php_security_log(S_VARS, "configured request variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_vars) && VARFILTER_G(max_get_vars) <= VARFILTER_G(cur_get_vars)) { ++ php_security_log(S_VARS, "configured GET variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_vars) && VARFILTER_G(max_cookie_vars) <= VARFILTER_G(cur_cookie_vars)) { ++ php_security_log(S_VARS, "configured COOKIE variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_vars) && VARFILTER_G(max_post_vars) <= VARFILTER_G(cur_post_vars)) { ++ php_security_log(S_VARS, "configured POST variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ ++ /* Drop this variable if it exceeds the value length limit */ ++ if (VARFILTER_G(max_value_length) && VARFILTER_G(max_value_length) < val_len) { ++ php_security_log(S_VARS, "configured request variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_value_length) && VARFILTER_G(max_get_value_length) < val_len) { ++ php_security_log(S_VARS, "configured GET variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_value_length) && VARFILTER_G(max_cookie_value_length) < val_len) { ++ php_security_log(S_VARS, "configured COOKIE variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_value_length) && VARFILTER_G(max_post_value_length) < val_len) { ++ php_security_log(S_VARS, "configured POST variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Normalize the variable name */ ++ normalize_varname(var); ++ ++ /* Find length of variable name */ ++ index = strchr(var, '['); ++ total_len = strlen(var); ++ var_len = index ? index-var : total_len; ++ ++ /* Drop this variable if it exceeds the varname/total length limit */ ++ if (VARFILTER_G(max_varname_length) && VARFILTER_G(max_varname_length) < var_len) { ++ php_security_log(S_VARS, "configured request variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_totalname_length) && VARFILTER_G(max_totalname_length) < total_len) { ++ php_security_log(S_VARS, "configured request variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_name_length) && VARFILTER_G(max_get_name_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_get_totalname_length) && VARFILTER_G(max_get_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_name_length) && VARFILTER_G(max_cookie_name_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_cookie_totalname_length) && VARFILTER_G(max_cookie_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_name_length) && VARFILTER_G(max_post_name_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_post_totalname_length) && VARFILTER_G(max_post_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Find out array depth */ ++ while (index) { ++ unsigned int index_length; ++ ++ depth++; ++ index = strchr(index+1, '['); ++ ++ if (prev_index) { ++ index_length = index ? index - 1 - prev_index - 1: strlen(prev_index); ++ ++ if (VARFILTER_G(max_array_index_length) && VARFILTER_G(max_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured request variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_index_length) && VARFILTER_G(max_get_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured GET variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_index_length) && VARFILTER_G(max_cookie_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured COOKIE variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_index_length) && VARFILTER_G(max_post_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured POST variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ prev_index = index; ++ } ++ ++ } ++ ++ /* Drop this variable if it exceeds the array depth limit */ ++ if (VARFILTER_G(max_array_depth) && VARFILTER_G(max_array_depth) < depth) { ++ php_security_log(S_VARS, "configured request variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_depth) && VARFILTER_G(max_get_array_depth) < depth) { ++ php_security_log(S_VARS, "configured GET variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_depth) && VARFILTER_G(max_cookie_array_depth) < depth) { ++ php_security_log(S_VARS, "configured COOKIE variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_depth) && VARFILTER_G(max_post_array_depth) < depth) { ++ php_security_log(S_VARS, "configured POST variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Drop this variable if it is one of GLOBALS, _GET, _POST, ... */ ++ /* This is to protect several silly scripts that do globalizing themself */ ++ ++ switch (var_len) { ++ case 18: ++ if (memcmp(var, "HTTP_RAW_POST_DATA", 18)==0) goto protected_varname; ++ break; ++ case 17: ++ if (memcmp(var, "HTTP_SESSION_VARS", 17)==0) goto protected_varname; ++ break; ++ case 16: ++ if (memcmp(var, "HTTP_SERVER_VARS", 16)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_COOKIE_VARS", 16)==0) goto protected_varname; ++ break; ++ case 15: ++ if (memcmp(var, "HTTP_POST_FILES", 15)==0) goto protected_varname; ++ break; ++ case 14: ++ if (memcmp(var, "HTTP_POST_VARS", 14)==0) goto protected_varname; ++ break; ++ case 13: ++ if (memcmp(var, "HTTP_GET_VARS", 13)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_ENV_VARS", 13)==0) goto protected_varname; ++ break; ++ case 8: ++ if (memcmp(var, "_SESSION", 8)==0) goto protected_varname; ++ if (memcmp(var, "_REQUEST", 8)==0) goto protected_varname; ++ break; ++ case 7: ++ if (memcmp(var, "GLOBALS", 7)==0) goto protected_varname; ++ if (memcmp(var, "_COOKIE", 7)==0) goto protected_varname; ++ if (memcmp(var, "_SERVER", 7)==0) goto protected_varname; ++ break; ++ case 6: ++ if (memcmp(var, "_FILES", 6)==0) goto protected_varname; ++ break; ++ case 5: ++ if (memcmp(var, "_POST", 5)==0) goto protected_varname; ++ break; ++ case 4: ++ if (memcmp(var, "_ENV", 4)==0) goto protected_varname; ++ if (memcmp(var, "_GET", 4)==0) goto protected_varname; ++ break; ++ } ++ ++ /* Okay let PHP register this variable */ ++ VARFILTER_G(cur_request_variables)++; ++ switch (arg) { ++ case PARSE_GET: ++ VARFILTER_G(cur_get_vars)++; ++ break; ++ case PARSE_COOKIE: ++ VARFILTER_G(cur_cookie_vars)++; ++ break; ++ case PARSE_POST: ++ VARFILTER_G(cur_post_vars)++; ++ break; ++ } ++ ++ if (new_val_len) { ++ *new_val_len = val_len; ++ } ++ ++ return 1; ++protected_varname: ++ php_security_log(S_VARS, "tried to register forbidden variable '%s' through %s variables", var, arg == PARSE_GET ? "GET" : arg == PARSE_POST ? "POST" : "COOKIE"); ++ return 0; ++} ++/* }}} */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: noet sw=4 ts=4 fdm=marker ++ * vim<600: noet sw=4 ts=4 ++ */ ++ ++ +diff -Nura php-4.4.0/main/fopen_wrappers.c hardening-patch-4.4.0-0.4.2/main/fopen_wrappers.c +--- php-4.4.0/main/fopen_wrappers.c 2005-02-03 00:44:07.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/main/fopen_wrappers.c 2005-09-07 18:40:29.094947192 +0200 +@@ -166,6 +166,21 @@ + char *pathbuf; + char *ptr; + char *end; ++ char path_copy[MAXPATHLEN]; ++ int path_len; ++ ++ /* Special case path ends with a trailing slash */ ++ path_len = strlen(path); ++ if (path_len >= MAXPATHLEN) { ++ errno = EPERM; /* we deny permission to open it */ ++ return -1; ++ } ++ if (path_len > 0 && path[path_len-1] == PHP_DIR_SEPARATOR) { ++ memcpy(path_copy, path, path_len+1); ++ while (path_len > 0 && path_copy[path_len-1] == PHP_DIR_SEPARATOR) path_len--; ++ path_copy[path_len] = '\0'; ++ path = (const char *)&path_copy; ++ } + + pathbuf = estrdup(PG(open_basedir)); + +diff -Nura php-4.4.0/main/hardened_globals.h hardening-patch-4.4.0-0.4.2/main/hardened_globals.h +--- php-4.4.0/main/hardened_globals.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/main/hardened_globals.h 2005-09-07 18:40:29.094947192 +0200 +@@ -0,0 +1,60 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_GLOBALS_H ++#define HARDENED_GLOBALS_H ++ ++typedef struct _hardened_globals hardened_globals_struct; ++ ++#ifdef ZTS ++# define HG(v) TSRMG(hardened_globals_id, hardened_globals_struct *, v) ++extern int hardened_globals_id; ++#else ++# define HG(v) (hardened_globals.v) ++extern struct _hardened_globals hardened_globals; ++#endif ++ ++ ++struct _hardened_globals { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_1; ++ unsigned int canary_2; ++#endif ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_3; ++ unsigned int canary_4; ++ unsigned int ll_canary_inited; ++#endif ++ zend_bool hphp_sql_bailout_on_error; ++ zend_bool hphp_multiheader; ++ HashTable *eval_whitelist; ++ HashTable *eval_blacklist; ++ HashTable *func_whitelist; ++ HashTable *func_blacklist; ++ unsigned int dummy; ++}; ++ ++ ++#endif /* HARDENED_GLOBALS_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nura php-4.4.0/main/hardening_patch.c hardening-patch-4.4.0-0.4.2/main/hardening_patch.c +--- php-4.4.0/main/hardening_patch.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/main/hardening_patch.c 2005-09-07 18:43:50.698298824 +0200 +@@ -0,0 +1,323 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: hardening_patch.c,v 1.2 2004/11/21 09:38:52 ionic Exp $ */ ++ ++#include "php.h" ++ ++#include ++#include ++ ++#if HAVE_UNISTD_H ++#include ++#endif ++#include "SAPI.h" ++#include "php_globals.h" ++ ++#if HARDENING_PATCH ++ ++#ifdef HAVE_SYS_SOCKET_H ++#include ++#endif ++ ++#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE) ++#undef AF_UNIX ++#endif ++ ++#if defined(AF_UNIX) ++#include ++#endif ++ ++#define SYSLOG_PATH "/dev/log" ++ ++#include "snprintf.h" ++ ++#include "hardening_patch.h" ++ ++#ifdef ZTS ++#include "hardened_globals.h" ++int hardened_globals_id; ++#else ++struct _hardened_globals hardened_globals; ++#endif ++ ++static void hardened_globals_ctor(hardened_globals_struct *hardened_globals TSRMLS_DC) ++{ ++ memset(hardened_globals, 0, sizeof(*hardened_globals)); ++} ++ ++ ++PHPAPI void hardened_startup() ++{ ++#ifdef ZTS ++ ts_allocate_id(&hardened_globals_id, sizeof(hardened_globals_struct), (ts_allocate_ctor) hardened_globals_ctor, NULL); ++#else ++ hardened_globals_ctor(&hardened_globals TSRMLS_CC); ++#endif ++} ++ ++char *loglevel2string(int loglevel) ++{ ++ switch (loglevel) { ++ case S_FILES: ++ return "FILES"; ++ case S_INCLUDE: ++ return "INCLUDE"; ++ case S_MEMORY: ++ return "MEMORY"; ++ case S_MISC: ++ return "MISC"; ++ case S_SQL: ++ return "SQL"; ++ case S_EXECUTOR: ++ return "EXECUTOR"; ++ case S_VARS: ++ return "VARS"; ++ default: ++ return "UNKNOWN"; ++ } ++} ++ ++PHPAPI void php_security_log(int loglevel, char *fmt, ...) ++{ ++#if defined(AF_UNIX) ++ int s, r, i=0; ++ struct sockaddr_un saun; ++ char buf[4096+64]; ++ char error[4096+100]; ++ char *ip_address; ++ char *fname; ++ int lineno; ++ va_list ap; ++ TSRMLS_FETCH(); ++ ++ if (EG(hphp_log_use_x_forwarded_for)) { ++ ip_address = sapi_getenv("HTTP_X_FORWARDED_FOR", 20 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "X-FORWARDED-FOR not set"; ++ } ++ } else { ++ ip_address = sapi_getenv("REMOTE_ADDR", 11 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "REMOTE_ADDR not set"; ++ } ++ } ++ ++ ++ va_start(ap, fmt); ++ ap_php_vsnprintf(error, sizeof(error), fmt, ap); ++ va_end(ap); ++ while (error[i]) { ++ if (error[i] < 32) error[i] = '.'; ++ i++; ++ } ++ ++ if (zend_is_executing(TSRMLS_C)) { ++ lineno = zend_get_executed_lineno(TSRMLS_C); ++ fname = zend_get_executed_filename(TSRMLS_C); ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s', line %u)", error, ip_address, fname, lineno); ++ } else { ++ fname = sapi_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC); ++ if (fname==NULL) { ++ fname = "unknown"; ++ } ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s')", error, ip_address, fname); ++ } ++ ++ /* Syslog-Logging disabled? */ ++ if ((EG(hphp_log_syslog) & loglevel)==0) { ++ goto log_sapi; ++ } ++ ++ ap_php_snprintf(error, sizeof(error), "<%u>hphp[%u]: %s\n", EG(hphp_log_syslog_facility)|EG(hphp_log_syslog_priority),getpid(),buf); ++ ++ s = socket(AF_UNIX, SOCK_DGRAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ s = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ goto log_sapi; ++ } ++ } ++ send(s, error, strlen(error), 0); ++ ++ close(s); ++ ++log_sapi: ++ /* SAPI Logging activated? */ ++ if ((EG(hphp_log_syslog) & loglevel)!=0) { ++ sapi_module.log_message(buf); ++ } ++ ++log_script: ++ /* script logging activaed? */ ++ if (((EG(hphp_log_script) & loglevel)!=0) && EG(hphp_log_scriptname)!=NULL) { ++ char cmd[8192], *cmdpos, *bufpos; ++ FILE *in; ++ int space; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s \'", EG(hphp_log_scriptname), loglevel2string(loglevel)); ++ space = sizeof(cmd) - strlen(cmd); ++ cmdpos = cmd + strlen(cmd); ++ bufpos = buf; ++ if (space <= 1) return; ++ while (space > 2 && *bufpos) { ++ if (*bufpos == '\'') { ++ if (space<=5) break; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\\'; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\''; ++ bufpos++; ++ space-=4; ++ } else { ++ *cmdpos++ = *bufpos++; ++ space--; ++ } ++ } ++ *cmdpos++ = '\''; ++ *cmdpos = 0; ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_INTERNAL, "Unable to execute logging shell script: %s", EG(hphp_log_scriptname)); ++ return; ++ } ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ } ++ pclose(in); ++ } ++ ++#endif ++} ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++PHPAPI unsigned int php_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++ ++PHPAPI int php_is_valid_include(zval *z) ++{ ++ char *filename; ++ int len, i; ++ TSRMLS_FETCH(); ++ ++ /* must be of type string */ ++ if (z->type != IS_STRING || z->value.str.val == NULL) { ++ return (0); ++ } ++ ++ /* short cut */ ++ filename = z->value.str.val; ++ len = z->value.str.len; ++ ++ /* 1. must be shorter than MAXPATHLEN */ ++ if (len > MAXPATHLEN) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') longer than MAXPATHLEN chars", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 2. must not be cutted */ ++ if (len != strlen(filename)) { ++ char *fname = estrndup(filename, len); ++ for (i=0; fname[i]; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename truncated by a \\0 after '%s'", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 3. must not be a URL */ ++ if (strstr(filename, "://")) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') is an URL", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 4. must not be an uploaded file */ ++ if (SG(rfc1867_uploaded_files)) { ++ if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, len+1)) { ++ php_security_log(S_INCLUDE, "Include filename is an uploaded file"); ++ return (0); ++ } ++ } ++ ++ /* passed all tests */ ++ return (1); ++} ++ ++#endif ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-4.4.0/main/hardening_patch.h hardening-patch-4.4.0-0.4.2/main/hardening_patch.h +--- php-4.4.0/main/hardening_patch.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/main/hardening_patch.h 2005-09-07 18:43:16.603482024 +0200 +@@ -0,0 +1,46 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENING_PATCH_H ++#define HARDENING_PATCH_H ++ ++#include "zend.h" ++ ++#if HARDENING_PATCH ++PHPAPI void php_security_log(int loglevel, char *fmt, ...); ++PHPAPI void hardened_startup(); ++#define HARDENING_PATCH_VERSION "0.4.2" ++ ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++PHPAPI unsigned int php_canary(); ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++PHPAPI int php_is_valid_include(zval *z); ++#endif ++ ++#endif /* HARDENING_PATCH_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nura php-4.4.0/main/hardening_patch.m4 hardening-patch-4.4.0-0.4.2/main/hardening_patch.m4 +--- php-4.4.0/main/hardening_patch.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/main/hardening_patch.m4 2005-09-07 18:40:29.097946736 +0200 +@@ -0,0 +1,95 @@ ++dnl ++dnl $Id: hardening_patch.m4,v 1.1 2004/11/14 13:24:24 ionic Exp $ ++dnl ++dnl This file contains Hardening Patch for PHP specific autoconf functions. ++dnl ++ ++AC_ARG_ENABLE(hardening-patch-mm-protect, ++[ --disable-hardening-patch-mm-protect Disable the Memory Manager protection.],[ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-ll-protect, ++[ --disable-hardening-patch-ll-protect Disable the Linked List protection.],[ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-inc-protect, ++[ --disable-hardening-patch-inc-protect Disable include/require protection.],[ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-fmt-protect, ++[ --disable-hardening-patch-fmt-protect Disable format string protection.],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-hash-protect, ++[ --disable-hardening-patch-hash-protect Disable HashTable destructor protection.],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++]) ++ ++AC_MSG_CHECKING(whether to protect the Zend Memory Manager) ++AC_MSG_RESULT($DO_HARDENING_PATCH_MM_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the Zend Linked Lists) ++AC_MSG_RESULT($DO_HARDENING_PATCH_LL_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect include/require statements) ++AC_MSG_RESULT($DO_HARDENING_PATCH_INC_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect PHP Format String functions) ++AC_MSG_RESULT($DO_HARDENING_PATCH_FMT_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the destructor of Zend HashTables) ++AC_MSG_RESULT($DO_HARDENING_PATCH_HASH_PROTECT) ++ ++ ++AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 1, [Memory Manager Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 0, [Memory Manager Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 1, [Linked List Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 0, [Linked List Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 1, [Include/Require Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 0, [Include/Require Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 1, [Fmt String Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 0, [Fmt String Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 1, [HashTable DTOR Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 0, [HashTable DTOR Protection]) ++fi ++ +diff -Nura php-4.4.0/main/main.c hardening-patch-4.4.0-0.4.2/main/main.c +--- php-4.4.0/main/main.c 2005-06-20 21:59:43.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/main/main.c 2005-09-07 18:40:29.098946584 +0200 +@@ -100,6 +100,10 @@ + PHPAPI int core_globals_id; + #endif + ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#endif ++ + #define ERROR_BUF_LEN 1024 + + typedef struct { +@@ -150,10 +154,33 @@ + */ + static PHP_INI_MH(OnChangeMemoryLimit) + { ++#if HARDENING_PATCH ++ long orig_memory_limit; ++ ++ if (entry->modified) { ++ orig_memory_limit = zend_atoi(entry->orig_value, entry->orig_value_length); ++ } else { ++ orig_memory_limit = 1<<30; ++ } ++ if (orig_memory_limit < 0 || orig_memory_limit > (1<<30)) { ++ orig_memory_limit = 1<<30; ++ } ++#endif + if (new_value) { + PG(memory_limit) = zend_atoi(new_value, new_value_length); ++#if HARDENING_PATCH ++ if (PG(memory_limit) > orig_memory_limit) { ++ PG(memory_limit) = orig_memory_limit; ++ php_security_log(S_MISC, "script tried to increase memory_limit above allowed value"); ++ return FAILURE; ++ } ++#endif + } else { ++#if HARDENING_PATCH ++ PG(memory_limit) = orig_memory_limit; ++#else + PG(memory_limit) = 1<<30; /* effectively, no limit */ ++#endif + } + return zend_set_memory_limit(PG(memory_limit)); + } +@@ -1096,6 +1123,10 @@ + tsrm_ls = ts_resource(0); + #endif + ++#if HARDENING_PATCH ++ hardened_startup(); ++#endif ++ + sapi_initialize_empty_request(TSRMLS_C); + sapi_activate(TSRMLS_C); + +@@ -1108,6 +1139,12 @@ + php_output_startup(); + php_output_activate(TSRMLS_C); + ++#if HARDENING_PATCH_INC_PROTECT ++ zuf.is_valid_include = php_is_valid_include; ++#endif ++#if HARDENING_PATCH ++ zuf.security_log_function = php_security_log; ++#endif + zuf.error_function = php_error_cb; + zuf.printf_function = php_printf; + zuf.write_function = php_body_write_wrapper; +@@ -1209,6 +1246,10 @@ + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, sizeof(PHP_CONFIG_FILE_PATH)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("HARDENING_PATCH", 1, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_STRINGL_CONSTANT("HARDENING_PATCH_VERSION", HARDENING_PATCH_VERSION, sizeof(HARDENING_PATCH_VERSION)-1, CONST_PERSISTENT | CONST_CS); ++#endif + REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("PHP_INT_MAX", LONG_MAX, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", sizeof(long), CONST_PERSISTENT | CONST_CS); +@@ -1316,7 +1357,7 @@ + */ + static inline void php_register_server_variables(TSRMLS_D) + { +- zval *array_ptr=NULL; ++ zval *array_ptr=NULL, *vptr; + + ALLOC_ZVAL(array_ptr); + array_init(array_ptr); +@@ -1326,6 +1367,16 @@ + /* Server variables */ + if (sapi_module.register_server_variables) { + sapi_module.register_server_variables(array_ptr TSRMLS_CC); ++ if (zend_hash_find(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA"), (void **)&vptr)==SUCCESS) { ++ char *str; ++ if (vptr->type != IS_STRING) { ++ str = "Array"; ++ } else { ++ str = vptr->value.str.val; ++ } ++ php_security_log(S_VARS, "Attacker tried to overwrite HTTP_RAW_POST_DATA with '%s' through a HTTP header", str); ++ zend_hash_del(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA")); ++ } + } + + /* PHP Authentication support */ +diff -Nura php-4.4.0/main/php_config.h.in hardening-patch-4.4.0-0.4.2/main/php_config.h.in +--- php-4.4.0/main/php_config.h.in 2005-07-11 12:07:41.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/main/php_config.h.in 2005-09-07 18:40:29.099946432 +0200 +@@ -860,6 +860,39 @@ + /* Enabling BIND8 compatibility for Panther */ + #undef BIND_8_COMPAT + ++/* Hardening-Patch */ ++#undef HARDENING_PATCH ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ + /* Whether you have AOLserver */ + #undef HAVE_AOLSERVER + +@@ -1143,6 +1176,12 @@ + /* Define if you have the getaddrinfo function */ + #undef HAVE_GETADDRINFO + ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ + /* Whether system headers declare timezone */ + #undef HAVE_DECLARED_TIMEZONE + +diff -Nura php-4.4.0/main/php_content_types.c hardening-patch-4.4.0-0.4.2/main/php_content_types.c +--- php-4.4.0/main/php_content_types.c 2002-12-31 17:26:14.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/main/php_content_types.c 2005-09-07 18:40:29.099946432 +0200 +@@ -77,6 +77,7 @@ + sapi_register_post_entries(php_post_entries); + sapi_register_default_post_reader(php_default_post_reader); + sapi_register_treat_data(php_default_treat_data); ++ sapi_register_input_filter(php_default_input_filter); + return SUCCESS; + } + /* }}} */ +diff -Nura php-4.4.0/main/php.h hardening-patch-4.4.0-0.4.2/main/php.h +--- php-4.4.0/main/php.h 2005-04-17 15:37:29.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/main/php.h 2005-09-07 18:40:29.100946280 +0200 +@@ -35,11 +35,19 @@ + #include "zend_qsort.h" + #include "php_compat.h" + ++ + #include "zend_API.h" + + #undef sprintf + #define sprintf php_sprintf + ++#if HARDENING_PATCH ++#if HAVE_REALPATH ++#undef realpath ++#define realpath php_realpath ++#endif ++#endif ++ + /* PHP's DEBUG value must match Zend's ZEND_DEBUG value */ + #undef PHP_DEBUG + #define PHP_DEBUG ZEND_DEBUG +@@ -435,6 +443,10 @@ + #endif + #endif /* !XtOffsetOf */ + ++#if HARDENING_PATCH ++#include "hardening_patch.h" ++#endif ++ + #endif + + /* +diff -Nura php-4.4.0/main/php_variables.c hardening-patch-4.4.0-0.4.2/main/php_variables.c +--- php-4.4.0/main/php_variables.c 2005-05-17 20:42:35.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/main/php_variables.c 2005-09-07 18:40:29.100946280 +0200 +@@ -225,17 +225,28 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(PARSE_POST, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, "&", &strtok_buf); + } + } + ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter) ++{ ++ /* TODO: check .ini setting here and apply user-defined input filter */ ++ *new_val_len = val_len; ++ return 1; ++} ++ + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) + { + char *res = NULL, *var, *val, *separator=NULL; +@@ -313,15 +324,26 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } else { ++ unsigned int val_len, new_val_len; ++ + php_url_decode(var, strlen(var)); +- php_register_variable_safe(var, "", 0, array_ptr TSRMLS_CC); ++ val_len = 0; ++ val = estrndup("", 0); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, separator, &strtok_buf); + } +diff -Nura php-4.4.0/main/rfc1867.c hardening-patch-4.4.0-0.4.2/main/rfc1867.c +--- php-4.4.0/main/rfc1867.c 2005-04-04 16:59:58.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/main/rfc1867.c 2005-09-07 18:40:29.101946128 +0200 +@@ -127,6 +127,7 @@ + #define UPLOAD_ERROR_C 3 /* Partially uploaded */ + #define UPLOAD_ERROR_D 4 /* No file uploaded */ + #define UPLOAD_ERROR_E 6 /* Missing /tmp or similar directory */ ++#define UPLOAD_ERROR_F 7 /* Filter forbids upload */ + + void php_rfc1867_register_constants(TSRMLS_D) + { +@@ -136,6 +137,7 @@ + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL", UPLOAD_ERROR_C, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE", UPLOAD_ERROR_D, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FILTER", UPLOAD_ERROR_F, CONST_CS | CONST_PERSISTENT); + } + + static void normalize_protected_variable(char *varname TSRMLS_DC) +@@ -844,6 +846,7 @@ + char buff[FILLUNIT]; + char *cd=NULL,*param=NULL,*filename=NULL, *tmp=NULL; + int blen=0, wlen=0; ++ unsigned long offset; + + zend_llist_clean(&header); + +@@ -891,21 +894,24 @@ + if (!filename && param) { + + char *value = multipart_buffer_read_body(mbuff TSRMLS_CC); ++ unsigned int new_val_len; /* Dummy variable */ + + if (!value) { + value = estrdup(""); + } + ++ if (sapi_module.input_filter(PARSE_POST, param, &value, strlen(value), &new_val_len TSRMLS_CC)) { + #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) +- if (php_mb_encoding_translation(TSRMLS_C)) { +- php_mb_gpc_stack_variable(param, value, &val_list, &len_list, +- &num_vars, &num_vars_max TSRMLS_CC); +- } else { +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); +- } ++ if (php_mb_encoding_translation(TSRMLS_C)) { ++ php_mb_gpc_stack_variable(param, value, &val_list, &len_list, ++ &num_vars, &num_vars_max TSRMLS_CC); ++ } else { ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ } + #else +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); + #endif ++ } + if (!strcasecmp(param, "MAX_FILE_SIZE")) { + max_file_size = atol(value); + } +@@ -981,6 +987,11 @@ + cancel_upload = UPLOAD_ERROR_D; + } + ++ if (sapi_module.pre_upload_filter && sapi_module.pre_upload_filter(param, filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ ++ offset = 0; + while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff) TSRMLS_CC))) + { + if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize)) { +@@ -990,6 +1001,11 @@ + sapi_module.sapi_error(E_WARNING, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename); + cancel_upload = UPLOAD_ERROR_B; + } else if (blen > 0) { ++ ++ if (sapi_module.upload_content_filter && sapi_module.upload_content_filter(offset, buff, blen, &blen TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ + wlen = write(fd, buff, blen); + + if (wlen < blen) { +@@ -997,6 +1013,7 @@ + cancel_upload = UPLOAD_ERROR_C; + } else { + total_bytes += wlen; ++ offset += wlen; + } + } + } +@@ -1011,6 +1028,10 @@ + } + #endif + ++ if (!cancel_upload && sapi_module.post_upload_filter && sapi_module.post_upload_filter(temp_filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ + if (cancel_upload) { + if (temp_filename) { + if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */ +diff -Nura php-4.4.0/main/SAPI.c hardening-patch-4.4.0-0.4.2/main/SAPI.c +--- php-4.4.0/main/SAPI.c 2005-02-22 15:46:24.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/main/SAPI.c 2005-09-07 18:40:29.102945976 +0200 +@@ -831,6 +831,31 @@ + return SUCCESS; + } + ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) ++{ ++ sapi_module.input_filter = input_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)) ++{ ++ sapi_module.pre_upload_filter = pre_upload_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)) ++{ ++ sapi_module.upload_content_filter = upload_content_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)) ++{ ++ sapi_module.post_upload_filter = post_upload_filter; ++ return SUCCESS; ++} ++ ++ + + SAPI_API int sapi_flush(TSRMLS_D) + { +diff -Nura php-4.4.0/main/SAPI.h hardening-patch-4.4.0-0.4.2/main/SAPI.h +--- php-4.4.0/main/SAPI.h 2003-04-09 22:27:55.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/main/SAPI.h 2005-09-07 18:40:29.103945824 +0200 +@@ -101,9 +101,10 @@ + char *current_user; + int current_user_length; + +- /* this is necessary for CLI module */ +- int argc; +- char **argv; ++ /* this is necessary for CLI module */ ++ int argc; ++ char **argv; ++ + } sapi_request_info; + + +@@ -177,6 +178,10 @@ + SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry); + SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D)); + SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC)); ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)); ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)); ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)); ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)); + + SAPI_API int sapi_flush(TSRMLS_D); + SAPI_API struct stat *sapi_get_stat(TSRMLS_D); +@@ -238,8 +243,15 @@ + int (*get_target_uid)(uid_t * TSRMLS_DC); + int (*get_target_gid)(gid_t * TSRMLS_DC); + ++ unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); ++ ++ unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC); ++ unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC); ++ unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC); ++ + void (*ini_defaults)(HashTable *configuration_hash); + int phpinfo_as_text; ++ + }; + + +@@ -262,16 +274,26 @@ + + #define SAPI_DEFAULT_MIMETYPE "text/html" + #define SAPI_DEFAULT_CHARSET "" ++ ++#if HARDENING_PATCH ++#define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION " with Hardening-Patch" ++#else + #define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION ++#endif + + #define SAPI_POST_READER_FUNC(post_reader) void post_reader(TSRMLS_D) + #define SAPI_POST_HANDLER_FUNC(post_handler) void post_handler(char *content_type_dup, void *arg TSRMLS_DC) + + #define SAPI_TREAT_DATA_FUNC(treat_data) void treat_data(int arg, char *str, zval* destArray TSRMLS_DC) ++#define SAPI_INPUT_FILTER_FUNC(input_filter) unsigned int input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) ++#define SAPI_PRE_UPLOAD_FILTER_FUNC(pre_upload_filter) unsigned int pre_upload_filter(char *varname, char *filename TSRMLS_DC) ++#define SAPI_UPLOAD_CONTENT_FILTER_FUNC(upload_content_filter) unsigned int upload_content_filter(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC) ++#define SAPI_POST_UPLOAD_FILTER_FUNC(post_upload_filter) unsigned int post_upload_filter(char *tmpfilename TSRMLS_DC) + + SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data); + SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader); + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data); ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter); + + #define STANDARD_SAPI_MODULE_PROPERTIES + +diff -Nura php-4.4.0/main/snprintf.c hardening-patch-4.4.0-0.4.2/main/snprintf.c +--- php-4.4.0/main/snprintf.c 2005-04-08 07:44:53.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/main/snprintf.c 2005-09-07 18:40:29.103945824 +0200 +@@ -1013,7 +1013,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Nura php-4.4.0/main/spprintf.c hardening-patch-4.4.0-0.4.2/main/spprintf.c +--- php-4.4.0/main/spprintf.c 2005-04-08 07:44:53.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/main/spprintf.c 2005-09-07 18:40:29.104945672 +0200 +@@ -630,7 +630,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = xbuf->len; ++#endif + break; + + /* +diff -Nura php-4.4.0/pear/go-pear-list.php hardening-patch-4.4.0-0.4.2/pear/go-pear-list.php +--- php-4.4.0/pear/go-pear-list.php 2005-07-01 11:41:04.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/pear/go-pear-list.php 2005-09-07 19:03:13.095587576 +0200 +@@ -8,7 +8,7 @@ + $packages = array( + // required packages for the installer + "PEAR" => "1.3.5", +-"XML_RPC" => "1.3.1", ++"XML_RPC" => "1.4.0", + "Console_Getopt" => "1.2", + "Archive_Tar" => "1.3.1", + +diff -Nura php-4.4.0/pear/packages/XML_RPC-1.3.1.tar hardening-patch-4.4.0-0.4.2/pear/packages/XML_RPC-1.3.1.tar +--- php-4.4.0/pear/packages/XML_RPC-1.3.1.tar 2005-07-01 11:42:14.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/pear/packages/XML_RPC-1.3.1.tar 1970-01-01 01:00:00.000000000 +0100 +@@ -1,3733 +0,0 @@ +-package2.xml100644 1750 144 32557 10260516576 6517 +- +- XML_RPC +- pear.php.net +- PHP implementation of the XML-RPC protocol +- A PEAR-ified version of Useful Inc's XML-RPC for PHP. +- +-It has support for HTTP/HTTPS transport, proxies and authentication. +- +- Stig Bakken +- ssb +- stig@php.net +- no +- +- +- Daniel Convissor +- danielc +- danielc@php.net +- yes +- +- 2005-06-29 +- +- +- 1.3.1 +- 1.3.0 +- +- +- stable +- stable +- +- PHP License +- * Security fix. Update highly recommended! +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- PEAR +- pear.php.net +- 1.4.0a1 +- 1.4.0a12 +- +- +- +- +- 4.2.0 +- 6.0.0 +- +- +- 1.4.0a1 +- +- +- +- +- +- +- +- 1.3.0RC3 +- 1.3.0 +- +- +- beta +- stable +- +- 2005-05-10 +- PHP License +- * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. +-* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. +-* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. +-* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. +-* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). +-* Use <br /> instead of <br> in XML_RPC_Value::dump(). +- +- +- +- 1.3.0RC2 +- 1.3.0 +- +- +- beta +- beta +- +- 2005-05-05 +- PHP License +- * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. +-* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. +-* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. +-* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. +- +- +- +- 1.3.0RC1 +- 1.3.0 +- +- +- beta +- beta +- +- 2005-04-07 +- PHP License +- * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. +-* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. +-* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. +-* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. +-* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. +-* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. +- +- +- +- 1.2.2 +- 1.2.0 +- +- +- stable +- stable +- +- 2005-03-07 +- PHP License +- * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. +- +- +- +- 1.2.1 +- 1.2.0 +- +- +- stable +- stable +- +- 2005-03-01 +- PHP License +- * Add isset() check before examining the dispatch map. Bug 3658. +- +- +- +- 1.2.0 +- 1.2.0 +- +- +- stable +- stable +- +- 2005-02-27 +- PHP License +- * Provide the "stable" release. +-* Add package2.xml for compatibility with PEAR 1.4.0. +-* For changes since 1.1.0, see the changelogs for the various RC releases. +- +- +- +- 1.2.0RC7 +- 1.2.0RC7 +- +- +- beta +- beta +- +- 2005-02-22 +- PHP License +- * Add the setSendEncoding() method and $send_encoding +- property to XML_RPC_Message. Request 3537. +-* Allow class methods to be mapped using either syntax: +- 'function' => 'hello::sayHello', +- or +- 'function' => array('hello', 'sayhello'), +- Bug 3363. +-* Use 8192 instead of 32768 for bytes in fread() +- in parseResponseFile(). Bug 3340. +- +- +- +- 1.2.0RC6 +- 1.2.0RC6 +- +- +- beta +- beta +- +- 2005-01-25 +- PHP License +- * Don't put the protocol in the Host field of the POST data. (danielc) +- +- +- +- 1.2.0RC5 +- 1.2.0RC5 +- +- +- beta +- beta +- +- 2005-01-24 +- PHP License +- * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. +- +- +- +- 1.2.0RC4 +- 1.2.0RC4 +- +- +- beta +- beta +- +- 2005-01-24 +- PHP License +- * When a connection attempt fails, have the method return 0. (danielc) +-* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) +-* Add tests for setting the client properties. (danielc) +-* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) +-* Bundle the tests with the package. (danielc) +- +- +- +- 1.2.0RC3 +- 1.2.0RC3 +- +- +- beta +- beta +- +- 2005-01-19 +- PHP License +- * ssl uses port 443, not 445. +- +- +- +- 1.2.0RC2 +- 1.2.0RC2 +- +- +- beta +- beta +- +- 2005-01-11 +- PHP License +- * Handle ssl:// in the $server string. (danielc) +-* Also default to port 445 for ssl:// requests as well. (danielc) +-* Enhance debugging in the server. (danielc) +- +- +- +- 1.2.0RC1 +- 1.2.0RC1 +- +- +- beta +- beta +- +- 2004-12-30 +- PHP License +- * Make things work with SSL. Bug 2489. (nkukard lbsd net) +-* Allow array function callbacks (Matt Kane) +-* Some minor speed-ups (Matt Kane) +-* Add Dump.php to the package (Christian Weiske) +-* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) +-* Silence fsockopen() errors. Bug 1714. (danielc) +-* Encode empty arrays as an array. Bug 1493. (danielc) +-* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) +-* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) +-* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) +-* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) +-* Allow raiseError() to be called statically. (danielc) +-* Stop double escaping of character entities. Bug 987. (danielc) +- NOTICE: the following have been removed: +- * XML_RPC_dh() +- * $GLOBALS['XML_RPC_entities'] +- * XML_RPC_entity_decode() +- * XML_RPC_lookup_entity() +-* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) +- +- +- +- 1.1.0 +- 1.1.0 +- +- +- stable +- stable +- +- 2004-03-15 +- PHP License +- * Added support for sequential arrays to XML_RPC_encode() (mroch) +-* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) +-* Remove "require_once 'PEAR.php'", include only when needed to raise an error +-* Replace echo and error_log() with raiseError() (mroch) +-* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) +-* be tolerant of junk after methodResponse (Luca Mariano, mroch) +-* Silent notice even in the error log (pierre) +-* fix include of shared xml extension on win32 (pierre) +- +- +- +- 1.0.4 +- 1.0.4 +- +- +- stable +- stable +- +- 2002-10-02 +- PHP License +- * added HTTP proxy authorization support (thanks to Arnaud Limbourg) +- +- +- +- 1.0.3 +- 1.0.3 +- +- +- stable +- stable +- +- 2002-05-19 +- PHP License +- * fix bug when parsing responses with boolean types +- +- +- +- 1.0.2 +- 1.0.2 +- +- +- stable +- stable +- +- 2002-04-16 +- PHP License +- * E_ALL fixes +-* fix HTTP response header parsing +- +- +- +- 1.0.1 +- 1.0.1 +- +- +- stable +- stable +- +- 2001-09-25 +- PHP License +- This is a PEAR-ified version of Useful Inc's 1.0.1 release. +-Includes an urgent security fix identified by Dan Libby <dan@libby.com>. +- +- +- +-XML_RPC-1.3.1/tests/protoport.php100644 1750 144 25543 10260516576 12042 +- * @copyright 2005 The PHP Group +- * @license http://www.php.net/license/3_0.txt PHP License +- * @version CVS: $Id: protoport.php,v 1.4 2005/01/24 17:48:47 danielc Exp $ +- * @link http://pear.php.net/package/XML_RPC +- * @since File available since Release 1.2 +- */ +- +-/* +- * If the package version number is found in the left hand +- * portion of the if() expression below, that means this file has +- * come from the PEAR installer. Therefore, let's test the +- * installed version of XML_RPC which should be in the include path. +- * +- * If the version has not been substituted in the if() expression, +- * this file has likely come from a CVS checkout or a .tar file. +- * Therefore, we'll assume the tests should use the version of +- * XML_RPC that has come from there as well. +- */ +-if ('1.3.1' != '@'.'package_version'.'@') { +- /** +- * Get the needed class from the PEAR installation +- */ +- require_once 'XML/RPC.php'; +-} else { +- /** +- * Get the needed class from the parent directory +- */ +- require_once '../RPC.php'; +-} +- +-/** +- * Compare the test result to the expected result +- * +- * If the test fails, echo out the results. +- * +- * @param array $expect the array of object properties you expect +- * from the test +- * @param object $actual the object results from the test +- * @param string $test_name the name of the test +- * +- * @return void +- */ +-function compare($expect, $actual, $test_name) { +- $actual = get_object_vars($actual); +- if (count(array_diff($actual, $expect))) { +- echo "$test_name failed.\nExpect: "; +- print_r($expect); +- echo "Actual: "; +- print_r($actual); +- echo "\n"; +- } +-} +- +-if (php_sapi_name() != 'cli') { +- echo "
\n";
+-}
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver');
+-compare($x, $c, 'defaults');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver');
+-compare($x, $c, 'defaults with http');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver');
+-compare($x, $c, 'defaults with https');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver');
+-compare($x, $c, 'defaults with ssl');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 65);
+-compare($x, $c, 'port 65');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 65);
+-compare($x, $c, 'port 65 with http');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 65);
+-compare($x, $c, 'port 65 with https');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65);
+-compare($x, $c, 'port 65 with ssl');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 0,
+-                        'theproxy');
+-compare($x, $c, 'defaults proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 0,
+-                        'http://theproxy');
+-compare($x, $c, 'defaults with http proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 0,
+-                        'https://theproxy');
+-compare($x, $c, 'defaults with https proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 0,
+-                        'ssl://theproxy');
+-compare($x, $c, 'defaults with ssl proxy');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 65,
+-                        'theproxy', 6565);
+-compare($x, $c, 'port 65 proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 65,
+-                        'http://theproxy', 6565);
+-compare($x, $c, 'port 65 with http proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 65,
+-                        'https://theproxy', 6565);
+-compare($x, $c, 'port 65 with https proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65,
+-                        'ssl://theproxy', 6565);
+-compare($x, $c, 'port 65 with ssl proxy 6565');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 443,
+-                        'theproxy', 443);
+-compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 0,
+-                        'ssl://theproxy', 6565);
+-compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
+-XML_RPC-1.3.1/tests/test_Dump.php100644   1750    144        3042 10260516576  11704 new XML_RPC_Value('das ist der Titel', 'string'),
+-    'startDate'=>new XML_RPC_Value(mktime(0,0,0,13,11,2004), 'dateTime.iso8601'),
+-    'endDate'  =>new XML_RPC_Value(mktime(0,0,0,15,11,2004), 'dateTime.iso8601'),
+-    'error'    =>'string',
+-    'arkey'    => new XML_RPC_Value( array(
+-        new XML_RPC_Value('simple string'),
+-        new XML_RPC_Value(12345, 'int')
+-        ), 'array')
+-    )
+-    ,'struct');
+-
+-XML_RPC_Dump($val);
+-
+-echo '==============' . "\r\n";
+-$val2 = new XML_RPC_Value(44353, 'int');
+-XML_RPC_Dump($val2);
+-
+-echo '==============' . "\r\n";
+-$val3 = new XML_RPC_Value('this should be a string', 'string');
+-XML_RPC_Dump($val3);
+-
+-echo '==============' . "\r\n";
+-$val4 = new XML_RPC_Value(true, 'boolean');
+-XML_RPC_Dump($val4);
+-XML_RPC-1.3.1/Dump.php100644   1750    144       12074 10260516576   7530 
+- * @version    CVS: $Id: Dump.php,v 1.7 2005/01/24 03:47:55 danielc Exp $
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-
+-
+-/**
+- * Pull in the XML_RPC class
+- */
+-require_once 'XML/RPC.php';
+-
+-
+-/**
+- * Generates the dump of the XML_RPC_Value and echoes it
+- *
+- * @param object $value  the XML_RPC_Value object to dump
+- *
+- * @return void
+- */
+-function XML_RPC_Dump($value)
+-{
+-    $dumper = new XML_RPC_Dump();
+-    echo $dumper->generateDump($value);
+-}
+-
+-
+-/**
+- * Class which generates a dump of a XML_RPC_Value object
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Christian Weiske 
+- * @version    Release: 1.3.1
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Dump
+-{
+-    /**
+-     * The indentation array cache
+-     * @var array
+-     */
+-    var $arIndent      = array();
+-
+-    /**
+-     * The spaces used for indenting the XML
+-     * @var string
+-     */
+-    var $strBaseIndent = '    ';
+-
+-    /**
+-     * Returns the dump in XML format without printing it out
+-     *
+-     * @param object $value   the XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  the dump
+-     */
+-    function generateDump($value, $nLevel = 0)
+-    {
+-        if (!is_object($value) && get_class($value) != 'xml_rpc_value') {
+-            require_once 'PEAR.php';
+-            PEAR::raiseError('Tried to dump non-XML_RPC_Value variable' . "\r\n",
+-                             0, PEAR_ERROR_PRINT);
+-            if (is_object($value)) {
+-                $strType = get_class($value);
+-            } else {
+-                $strType = gettype($value);
+-            }
+-            return $this->getIndent($nLevel) . 'NOT A XML_RPC_Value: '
+-                   . $strType . "\r\n";
+-        }
+-
+-        switch ($value->kindOf()) {
+-        case 'struct':
+-            $ret = $this->genStruct($value, $nLevel);
+-            break;
+-        case 'array':
+-            $ret = $this->genArray($value, $nLevel);
+-            break;
+-        case 'scalar':
+-            $ret = $this->genScalar($value->scalarval(), $nLevel);
+-            break;
+-        default:
+-            require_once 'PEAR.php';
+-            PEAR::raiseError('Illegal type "' . $value->kindOf()
+-                             . '" in XML_RPC_Value' . "\r\n", 0,
+-                             PEAR_ERROR_PRINT);
+-        }
+-
+-        return $ret;
+-    }
+-
+-    /**
+-     * Returns the scalar value dump
+-     *
+-     * @param object $value   the scalar XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genScalar($value, $nLevel)
+-    {
+-        if (gettype($value) == 'object') {
+-            $strClass = ' ' . get_class($value);
+-        } else {
+-            $strClass = '';
+-        }
+-        return $this->getIndent($nLevel) . gettype($value) . $strClass
+-               . ' ' . $value . "\r\n";
+-    }
+-
+-    /**
+-     * Returns the dump of a struct
+-     *
+-     * @param object $value   the struct XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genStruct($value, $nLevel)
+-    {
+-        $value->structreset();
+-        $strOutput = $this->getIndent($nLevel) . 'struct' . "\r\n";
+-        while (list($key, $keyval) = $value->structeach()) {
+-            $strOutput .= $this->getIndent($nLevel + 1) . $key . "\r\n";
+-            $strOutput .= $this->generateDump($keyval, $nLevel + 2);
+-        }
+-        return $strOutput;
+-    }
+-
+-    /**
+-     * Returns the dump of an array
+-     *
+-     * @param object $value   the array XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genArray($value, $nLevel)
+-    {
+-        $nSize     = $value->arraysize();
+-        $strOutput = $this->getIndent($nLevel) . 'array' . "\r\n";
+-        for($nA = 0; $nA < $nSize; $nA++) {
+-            $strOutput .= $this->getIndent($nLevel + 1) . $nA . "\r\n";
+-            $strOutput .= $this->generateDump($value->arraymem($nA),
+-                                              $nLevel + 2);
+-        }
+-        return $strOutput;
+-    }
+-
+-    /**
+-     * Returns the indent for a specific level and caches it for faster use
+-     *
+-     * @param int $nLevel  the level
+-     *
+-     * @return string  the indented string
+-     */
+-    function getIndent($nLevel)
+-    {
+-        if (!isset($this->arIndent[$nLevel])) {
+-            $this->arIndent[$nLevel] = str_repeat($this->strBaseIndent, $nLevel);
+-        }
+-        return $this->arIndent[$nLevel];
+-    }
+-}
+-
+-/*
+- * Local variables:
+- * tab-width: 4
+- * c-basic-offset: 4
+- * c-hanging-comment-ender-p: nil
+- * End:
+- */
+-
+-?>
+-XML_RPC-1.3.1/RPC.php100644   1750    144      150065 10260516576   7272 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
+- * @version    CVS: $Id: RPC.php,v 1.74 2005/05/09 20:51:54 danielc Exp $
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-
+-
+-if (!function_exists('xml_parser_create')) {
+-    PEAR::loadExtension('xml');
+-}
+-
+-/**#@+
+- * Error constants
+- */
+-/**
+- * Parameter values don't match parameter types
+- */
+-define('XML_RPC_ERROR_INVALID_TYPE', 101);
+-/**
+- * Parameter declared to be numeric but the values are not
+- */
+-define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102);
+-/**
+- * Communication error
+- */
+-define('XML_RPC_ERROR_CONNECTION_FAILED', 103);
+-/**
+- * The array or struct has already been started
+- */
+-define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
+-/**
+- * Incorrect parameters submitted
+- */
+-define('XML_RPC_ERROR_INCORRECT_PARAMS', 105);
+-/**
+- * Programming error by developer
+- */
+-define('XML_RPC_ERROR_PROGRAMMING', 106);
+-/**#@-*/
+-
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_I4']
+- */
+-$GLOBALS['XML_RPC_I4'] = 'i4';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Int']
+- */
+-$GLOBALS['XML_RPC_Int'] = 'int';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Boolean']
+- */
+-$GLOBALS['XML_RPC_Boolean'] = 'boolean';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Double']
+- */
+-$GLOBALS['XML_RPC_Double'] = 'double';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_String']
+- */
+-$GLOBALS['XML_RPC_String'] = 'string';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_DateTime']
+- */
+-$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Base64']
+- */
+-$GLOBALS['XML_RPC_Base64'] = 'base64';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Array']
+- */
+-$GLOBALS['XML_RPC_Array'] = 'array';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Struct']
+- */
+-$GLOBALS['XML_RPC_Struct'] = 'struct';
+-
+-
+-/**
+- * Data type meta-types
+- * @global array $GLOBALS['XML_RPC_Types']
+- */
+-$GLOBALS['XML_RPC_Types'] = array(
+-    $GLOBALS['XML_RPC_I4']       => 1,
+-    $GLOBALS['XML_RPC_Int']      => 1,
+-    $GLOBALS['XML_RPC_Boolean']  => 1,
+-    $GLOBALS['XML_RPC_String']   => 1,
+-    $GLOBALS['XML_RPC_Double']   => 1,
+-    $GLOBALS['XML_RPC_DateTime'] => 1,
+-    $GLOBALS['XML_RPC_Base64']   => 1,
+-    $GLOBALS['XML_RPC_Array']    => 2,
+-    $GLOBALS['XML_RPC_Struct']   => 3,
+-);
+-
+-
+-/**
+- * Error message numbers
+- * @global array $GLOBALS['XML_RPC_err']
+- */
+-$GLOBALS['XML_RPC_err'] = array(
+-    'unknown_method'      => 1,
+-    'invalid_return'      => 2,
+-    'incorrect_params'    => 3,
+-    'introspect_unknown'  => 4,
+-    'http_error'          => 5,
+-    'not_response_object' => 6,
+-);
+-
+-/**
+- * Error message strings
+- * @global array $GLOBALS['XML_RPC_str']
+- */
+-$GLOBALS['XML_RPC_str'] = array(
+-    'unknown_method'      => 'Unknown method',
+-    'invalid_return'      => 'Invalid return payload: enable debugging to examine incoming payload',
+-    'incorrect_params'    => 'Incorrect parameters passed to method',
+-    'introspect_unknown'  => 'Can\'t introspect: method unknown',
+-    'http_error'          => 'Didn\'t receive 200 OK from remote server.',
+-    'not_response_object' => 'The requested method didn\'t return an XML_RPC_Response object.',
+-);
+-
+-
+-/**
+- * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
+- * @global string $GLOBALS['XML_RPC_defencoding']
+- */
+-$GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
+-
+-/**
+- * User error codes start at 800
+- * @global int $GLOBALS['XML_RPC_erruser']
+- */
+-$GLOBALS['XML_RPC_erruser'] = 800;
+-
+-/**
+- * XML parse error codes start at 100
+- * @global int $GLOBALS['XML_RPC_errxml']
+- */
+-$GLOBALS['XML_RPC_errxml'] = 100;
+-
+-
+-/**
+- * Compose backslashes for escaping regexp
+- * @global string $GLOBALS['XML_RPC_backslash']
+- */
+-$GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
+-
+-
+-/**
+- * Stores state during parsing
+- *
+- * quick explanation of components:
+- *   + st     = builds up a string for evaluation
+- *   + ac     = accumulates values
+- *   + qt     = decides if quotes are needed for evaluation
+- *   + cm     = denotes struct or array (comma needed)
+- *   + isf    = indicates a fault
+- *   + lv     = indicates "looking for a value": implements the logic
+- *               to allow values with no types to be strings
+- *   + params = stores parameters in method calls
+- *   + method = stores method name
+- *
+- * @global array $GLOBALS['XML_RPC_xh']
+- */
+-$GLOBALS['XML_RPC_xh'] = array();
+-
+-
+-/**
+- * Start element handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_se($parser_resource, $name, $attrs)
+-{
+-    global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String;
+-    $parser = (int) $parser_resource;
+-
+-    switch ($name) {
+-    case 'STRUCT':
+-    case 'ARRAY':
+-        $XML_RPC_xh[$parser]['st'] .= 'array(';
+-        $XML_RPC_xh[$parser]['cm']++;
+-        // this last line turns quoting off
+-        // this means if we get an empty array we'll
+-        // simply get a bit of whitespace in the eval
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'NAME':
+-        $XML_RPC_xh[$parser]['st'] .= '"';
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        break;
+-
+-    case 'FAULT':
+-        $XML_RPC_xh[$parser]['isf'] = 1;
+-        break;
+-
+-    case 'PARAM':
+-        $XML_RPC_xh[$parser]['st'] = '';
+-        break;
+-
+-    case 'VALUE':
+-        $XML_RPC_xh[$parser]['st'] .= 'new XML_RPC_Value(';
+-        $XML_RPC_xh[$parser]['lv'] = 1;
+-        $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        // look for a value: if this is still 1 by the
+-        // time we reach the first data segment then the type is string
+-        // by implication and we need to add in a quote
+-        break;
+-
+-    case 'I4':
+-    case 'INT':
+-    case 'STRING':
+-    case 'BOOLEAN':
+-    case 'DOUBLE':
+-    case 'DATETIME.ISO8601':
+-    case 'BASE64':
+-        $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
+-
+-        if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
+-            $XML_RPC_xh[$parser]['qt'] = 1;
+-
+-            if ($name == 'DATETIME.ISO8601') {
+-                $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
+-            }
+-
+-        } elseif ($name == 'BASE64') {
+-            $XML_RPC_xh[$parser]['qt'] = 2;
+-        } else {
+-            // No quoting is required here -- but
+-            // at the end of the element we must check
+-            // for data format errors.
+-            $XML_RPC_xh[$parser]['qt'] = 0;
+-        }
+-        break;
+-
+-    case 'MEMBER':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-    }
+-
+-    if ($name != 'VALUE') {
+-        $XML_RPC_xh[$parser]['lv'] = 0;
+-    }
+-}
+-
+-/**
+- * End element handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_ee($parser_resource, $name)
+-{
+-    global $XML_RPC_xh, $XML_RPC_Types, $XML_RPC_String;
+-    $parser = (int) $parser_resource;
+-
+-    switch ($name) {
+-    case 'STRUCT':
+-    case 'ARRAY':
+-        if ($XML_RPC_xh[$parser]['cm']
+-            && substr($XML_RPC_xh[$parser]['st'], -1) == ',')
+-        {
+-            $XML_RPC_xh[$parser]['st'] = substr($XML_RPC_xh[$parser]['st'], 0, -1);
+-        }
+-
+-        $XML_RPC_xh[$parser]['st'] .= ')';
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-        $XML_RPC_xh[$parser]['cm']--;
+-        break;
+-
+-    case 'NAME':
+-        $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'] . '" => ';
+-        break;
+-
+-    case 'BOOLEAN':
+-        // special case here: we translate boolean 1 or 0 into PHP
+-        // constants true or false
+-        if ($XML_RPC_xh[$parser]['ac'] == '1') {
+-            $XML_RPC_xh[$parser]['ac'] = 'true';
+-        } else {
+-            $XML_RPC_xh[$parser]['ac'] = 'false';
+-        }
+-
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-        // Drop through intentionally.
+-
+-    case 'I4':
+-    case 'INT':
+-    case 'STRING':
+-    case 'DOUBLE':
+-    case 'DATETIME.ISO8601':
+-    case 'BASE64':
+-        if ($XML_RPC_xh[$parser]['qt'] == 1) {
+-            // we use double quotes rather than single so backslashification works OK
+-            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
+-        } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
+-            $XML_RPC_xh[$parser]['st'] .= 'base64_decode("'
+-                                        . $XML_RPC_xh[$parser]['ac'] . '")';
+-        } elseif ($name == 'BOOLEAN') {
+-            $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
+-        } else {
+-            // we have an I4, INT or a DOUBLE
+-            // we must check that only 0123456789-. are characters here
+-            if (!ereg("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
+-                XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
+-                                         XML_RPC_ERROR_NON_NUMERIC_FOUND);
+-                $XML_RPC_xh[$parser]['st'] .= 'XML_RPC_ERROR_NON_NUMERIC_FOUND';
+-            } else {
+-                // it's ok, add it on
+-                $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
+-            }
+-        }
+-
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
+-        break;
+-
+-    case 'VALUE':
+-        // deal with a string value
+-        if (strlen($XML_RPC_xh[$parser]['ac']) > 0 &&
+-            $XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
+-
+-            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
+-        }
+-
+-        // This if () detects if no scalar was inside 
+-        // and pads an empty "".
+-        if ($XML_RPC_xh[$parser]['st'][strlen($XML_RPC_xh[$parser]['st'])-1] == '(') {
+-            $XML_RPC_xh[$parser]['st'] .= '""';
+-        }
+-        $XML_RPC_xh[$parser]['st'] .= ", '" . $XML_RPC_xh[$parser]['vt'] . "')";
+-        if ($XML_RPC_xh[$parser]['cm']) {
+-            $XML_RPC_xh[$parser]['st'] .= ',';
+-        }
+-        break;
+-
+-    case 'MEMBER':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'DATA':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'PARAM':
+-        $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['st'];
+-        break;
+-
+-    case 'METHODNAME':
+-    case 'RPCMETHODNAME':
+-        $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", '',
+-                                                      $XML_RPC_xh[$parser]['ac']);
+-        break;
+-    }
+-
+-    // if it's a valid type name, set the type
+-    if (isset($XML_RPC_Types[strtolower($name)])) {
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-    }
+-}
+-
+-/**
+- * Character data handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_cd($parser_resource, $data)
+-{
+-    global $XML_RPC_xh, $XML_RPC_backslash;
+-    $parser = (int) $parser_resource;
+-
+-    if ($XML_RPC_xh[$parser]['lv'] != 3) {
+-        // "lookforvalue==3" means that we've found an entire value
+-        // and should discard any further character data
+-
+-        if ($XML_RPC_xh[$parser]['lv'] == 1) {
+-            // if we've found text and we're just in a  then
+-            // turn quoting on, as this will be a string
+-            $XML_RPC_xh[$parser]['qt'] = 1;
+-            // and say we've found a value
+-            $XML_RPC_xh[$parser]['lv'] = 2;
+-        }
+-
+-        // replace characters that eval would
+-        // do special things with
+-        if (!isset($XML_RPC_xh[$parser]['ac'])) {
+-            $XML_RPC_xh[$parser]['ac'] = '';
+-        }
+-        $XML_RPC_xh[$parser]['ac'] .= str_replace('$', '\$',
+-            str_replace('"', '\"', str_replace(chr(92),
+-            $XML_RPC_backslash, $data)));
+-    }
+-}
+-
+-/**
+- * The common methods and properties for all of the XML_RPC classes
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
+- * @version    Release: 1.3.1
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Base {
+-
+-    /**
+-     * PEAR Error handling
+-     *
+-     * @return object  PEAR_Error object
+-     */
+-    function raiseError($msg, $code)
+-    {
+-        include_once 'PEAR.php';
+-        if (is_object(@$this)) {
+-            return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
+-        } else {
+-            return PEAR::raiseError('XML_RPC: ' . $msg, $code);
+-        }
+-    }
+-
+-    /**
+-     * Tell whether something is a PEAR_Error object
+-     *
+-     * @param mixed $value  the item to check
+-     *
+-     * @return bool  whether $value is a PEAR_Error object or not
+-     *
+-     * @access public
+-     */
+-    function isError($value)
+-    {
+-        return is_a($value, 'PEAR_Error');
+-    }
+-}
+-
+-/**
+- * The methods and properties for submitting XML RPC requests
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
+- * @version    Release: 1.3.1
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Client extends XML_RPC_Base {
+-
+-    /**
+-     * The path and name of the RPC server script you want the request to go to
+-     * @var string
+-     */
+-    var $path = '';
+-
+-    /**
+-     * The name of the remote server to connect to
+-     * @var string
+-     */
+-    var $server = '';
+-
+-    /**
+-     * The protocol to use in contacting the remote server
+-     * @var string
+-     */
+-    var $protocol = 'http://';
+-
+-    /**
+-     * The port for connecting to the remote server
+-     *
+-     * The default is 80 for http:// connections
+-     * and 443 for https:// and ssl:// connections.
+-     *
+-     * @var integer
+-     */
+-    var $port = 80;
+-
+-    /**
+-     * A user name for accessing the RPC server
+-     * @var string
+-     * @see XML_RPC_Client::setCredentials()
+-     */
+-    var $username = '';
+-
+-    /**
+-     * A password for accessing the RPC server
+-     * @var string
+-     * @see XML_RPC_Client::setCredentials()
+-     */
+-    var $password = '';
+-
+-    /**
+-     * The name of the proxy server to use, if any
+-     * @var string
+-     */
+-    var $proxy = '';
+-
+-    /**
+-     * The protocol to use in contacting the proxy server, if any
+-     * @var string
+-     */
+-    var $proxy_protocol = 'http://';
+-
+-    /**
+-     * The port for connecting to the proxy server
+-     *
+-     * The default is 8080 for http:// connections
+-     * and 443 for https:// and ssl:// connections.
+-     *
+-     * @var integer
+-     */
+-    var $proxy_port = 8080;
+-
+-    /**
+-     * A user name for accessing the proxy server
+-     * @var string
+-     */
+-    var $proxy_user = '';
+-
+-    /**
+-     * A password for accessing the proxy server
+-     * @var string
+-     */
+-    var $proxy_pass = '';
+-
+-    /**
+-     * The error number, if any
+-     * @var integer
+-     */
+-    var $errno = 0;
+-
+-    /**
+-     * The error message, if any
+-     * @var string
+-     */
+-    var $errstring = '';
+-
+-    /**
+-     * The current debug mode (1 = on, 0 = off)
+-     * @var integer
+-     */
+-    var $debug = 0;
+-
+-    /**
+-     * The HTTP headers for the current request.
+-     * @var string
+-     */
+-    var $headers = '';
+-
+-
+-    /**
+-     * Sets the object's properties
+-     *
+-     * @param string  $path        the path and name of the RPC server script
+-     *                              you want the request to go to
+-     * @param string  $server      the URL of the remote server to connect to.
+-     *                              If this parameter doesn't specify a
+-     *                              protocol and $port is 443, ssl:// is
+-     *                              assumed.
+-     * @param integer $port        a port for connecting to the remote server.
+-     *                              Defaults to 80 for http:// connections and
+-     *                              443 for https:// and ssl:// connections.
+-     * @param string  $proxy       the URL of the proxy server to use, if any.
+-     *                              If this parameter doesn't specify a
+-     *                              protocol and $port is 443, ssl:// is
+-     *                              assumed.
+-     * @param integer $proxy_port  a port for connecting to the remote server.
+-     *                              Defaults to 8080 for http:// connections and
+-     *                              443 for https:// and ssl:// connections.
+-     * @param string  $proxy_user  a user name for accessing the proxy server
+-     * @param string  $proxy_pass  a password for accessing the proxy server
+-     *
+-     * @return void
+-     */
+-    function XML_RPC_Client($path, $server, $port = 0,
+-                            $proxy = '', $proxy_port = 0,
+-                            $proxy_user = '', $proxy_pass = '')
+-    {
+-        $this->path       = $path;
+-        $this->proxy_user = $proxy_user;
+-        $this->proxy_pass = $proxy_pass;
+-
+-        preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match);
+-        if ($match[1] == '') {
+-            if ($port == 443) {
+-                $this->server   = $match[2];
+-                $this->protocol = 'ssl://';
+-                $this->port     = 443;
+-            } else {
+-                $this->server = $match[2];
+-                if ($port) {
+-                    $this->port = $port;
+-                }
+-            }
+-        } elseif ($match[1] == 'http://') {
+-            $this->server = $match[2];
+-            if ($port) {
+-                $this->port = $port;
+-            }
+-        } else {
+-            $this->server   = $match[2];
+-            $this->protocol = 'ssl://';
+-            if ($port) {
+-                $this->port = $port;
+-            } else {
+-                $this->port = 443;
+-            }
+-        }
+-
+-        if ($proxy) {
+-            preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match);
+-            if ($match[1] == '') {
+-                if ($proxy_port == 443) {
+-                    $this->proxy          = $match[2];
+-                    $this->proxy_protocol = 'ssl://';
+-                    $this->proxy_port     = 443;
+-                } else {
+-                    $this->proxy = $match[2];
+-                    if ($proxy_port) {
+-                        $this->proxy_port = $proxy_port;
+-                    }
+-                }
+-            } elseif ($match[1] == 'http://') {
+-                $this->proxy = $match[2];
+-                if ($proxy_port) {
+-                    $this->proxy_port = $proxy_port;
+-                }
+-            } else {
+-                $this->proxy          = $match[2];
+-                $this->proxy_protocol = 'ssl://';
+-                if ($proxy_port) {
+-                    $this->proxy_port = $proxy_port;
+-                } else {
+-                    $this->proxy_port = 443;
+-                }
+-            }
+-        }
+-    }
+-
+-    /**
+-     * Change the current debug mode
+-     *
+-     * @param int $in  where 1 = on, 0 = off
+-     *
+-     * @return void
+-     */
+-    function setDebug($in)
+-    {
+-        if ($in) {
+-            $this->debug = 1;
+-        } else {
+-            $this->debug = 0;
+-        }
+-    }
+-
+-    /**
+-     * Set username and password properties for connecting to the RPC server
+-     *
+-     * @param string $u  the user name
+-     * @param string $p  the password
+-     *
+-     * @return void
+-     *
+-     * @see XML_RPC_Client::$username, XML_RPC_Client::$password
+-     */
+-    function setCredentials($u, $p)
+-    {
+-        $this->username = $u;
+-        $this->password = $p;
+-    }
+-
+-    /**
+-     * Transmit the RPC request via HTTP 1.0 protocol
+-     *
+-     * @param object $msg       the XML_RPC_Message object
+-     * @param int    $timeout   how many seconds to wait for the request
+-     *
+-     * @return object  an XML_RPC_Response object.  0 is returned if any
+-     *                  problems happen.
+-     *
+-     * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
+-     *      XML_RPC_Client::setCredentials()
+-     */
+-    function send($msg, $timeout = 0)
+-    {
+-        if (strtolower(get_class($msg)) != 'xml_rpc_message') {
+-            $this->errstr = 'send()\'s $msg parameter must be an'
+-                          . ' XML_RPC_Message object.';
+-            $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING);
+-            return 0;
+-        }
+-        $msg->debug = $this->debug;
+-        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
+-                                        $timeout, $this->username,
+-                                        $this->password);
+-    }
+-
+-    /**
+-     * Transmit the RPC request via HTTP 1.0 protocol
+-     *
+-     * Requests should be sent using XML_RPC_Client send() rather than
+-     * calling this method directly.
+-     *
+-     * @param object $msg       the XML_RPC_Message object
+-     * @param string $server    the server to send the request to
+-     * @param int    $port      the server port send the request to
+-     * @param int    $timeout   how many seconds to wait for the request
+-     *                           before giving up
+-     * @param string $username  a user name for accessing the RPC server
+-     * @param string $password  a password for accessing the RPC server
+-     *
+-     * @return object  an XML_RPC_Response object.  0 is returned if any
+-     *                  problems happen.
+-     *
+-     * @access protected
+-     * @see XML_RPC_Client::send()
+-     */
+-    function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
+-                               $username = '', $password = '')
+-    {
+-        /*
+-         * If we're using a proxy open a socket to the proxy server
+-         * instead to the xml-rpc server
+-         */
+-        if ($this->proxy) {
+-            if ($this->proxy_protocol == 'http://') {
+-                $protocol = '';
+-            } else {
+-                $protocol = $this->proxy_protocol;
+-            }
+-            if ($timeout > 0) {
+-                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
+-                                 $this->errno, $this->errstr, $timeout);
+-            } else {
+-                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
+-                                 $this->errno, $this->errstr);
+-            }
+-        } else {
+-            if ($this->protocol == 'http://') {
+-                $protocol = '';
+-            } else {
+-                $protocol = $this->protocol;
+-            }
+-            if ($timeout > 0) {
+-                $fp = @fsockopen($protocol . $server, $port,
+-                                 $this->errno, $this->errstr, $timeout);
+-            } else {
+-                $fp = @fsockopen($protocol . $server, $port,
+-                                 $this->errno, $this->errstr);
+-            }
+-        }
+-
+-        /*
+-         * Just raising the error without returning it is strange,
+-         * but keep it here for backwards compatibility.
+-         */
+-        if (!$fp && $this->proxy) {
+-            $this->raiseError('Connection to proxy server '
+-                              . $this->proxy . ':' . $this->proxy_port
+-                              . ' failed. ' . $this->errstr,
+-                              XML_RPC_ERROR_CONNECTION_FAILED);
+-            return 0;
+-        } elseif (!$fp) {
+-            $this->raiseError('Connection to RPC server '
+-                              . $server . ':' . $port
+-                              . ' failed. ' . $this->errstr,
+-                              XML_RPC_ERROR_CONNECTION_FAILED);
+-            return 0;
+-        }
+-
+-        if ($timeout) {
+-            stream_set_timeout($fp, $timeout);
+-        }
+-
+-        // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly
+-        if ($username != $this->username) {
+-            $this->setCredentials($username, $password);
+-        }
+-
+-        // Only create the payload if it was not created previously
+-        if (empty($msg->payload)) {
+-            $msg->createPayload();
+-        }
+-        $this->createHeaders($msg);
+-
+-        $op  = $this->headers . "\r\n\r\n";
+-        $op .= $msg->payload;
+-
+-        if (!fputs($fp, $op, strlen($op))) {
+-            $this->errstr = 'Write error';
+-            return 0;
+-        }
+-        $resp = $msg->parseResponseFile($fp);
+-
+-        $meta = stream_get_meta_data($fp);
+-        if ($meta['timed_out']) {
+-            fclose($fp);
+-            $this->errstr = 'RPC server did not send response before timeout.';
+-            $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED);
+-            return 0;
+-        }
+-
+-        fclose($fp);
+-        return $resp;
+-    }
+-
+-    /**
+-     * Determines the HTTP headers and puts it in the $headers property
+-     *
+-     * @param object $msg       the XML_RPC_Message object
+-     *
+-     * @return boolean  TRUE if okay, FALSE if the message payload isn't set.
+-     *
+-     * @access protected
+-     */
+-    function createHeaders($msg)
+-    {
+-        if (empty($msg->payload)) {
+-            return false;
+-        }
+-        if ($this->proxy) {
+-            $this->headers = 'POST ' . $this->protocol . $this->server;
+-            if ($this->proxy_port) {
+-                $this->headers .= ':' . $this->port;
+-            }
+-        } else {
+-           $this->headers = 'POST ';
+-        }
+-        $this->headers .= $this->path. " HTTP/1.0\r\n";
+-        
+-        $this->headers .= "User-Agent: PEAR XML_RPC\r\n";
+-        $this->headers .= 'Host: ' . $this->server . "\r\n";
+-
+-        if ($this->proxy && $this->proxy_user) {
+-            $this->headers .= 'Proxy-Authorization: Basic '
+-                     . base64_encode("$this->proxy_user:$this->proxy_pass")
+-                     . "\r\n";
+-        }
+-
+-        // thanks to Grant Rauscher  for this
+-        if ($this->username) {
+-            $this->headers .= 'Authorization: Basic '
+-                     . base64_encode("$this->username:$this->password")
+-                     . "\r\n";
+-        }
+-
+-        $this->headers .= "Content-Type: text/xml\r\n";
+-        $this->headers .= 'Content-Length: ' . strlen($msg->payload);
+-        return true;
+-    }
+-}
+-
+-/**
+- * The methods and properties for interpreting responses to XML RPC requests
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
+- * @version    Release: 1.3.1
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Response extends XML_RPC_Base
+-{
+-    var $xv;
+-    var $fn;
+-    var $fs;
+-    var $hdrs;
+-
+-    /**
+-     * @return void
+-     */
+-    function XML_RPC_Response($val, $fcode = 0, $fstr = '')
+-    {
+-        if ($fcode != 0) {
+-            $this->fn = $fcode;
+-            $this->fs = htmlspecialchars($fstr);
+-        } else {
+-            $this->xv = $val;
+-        }
+-    }
+-
+-    /**
+-     * @return int  the error code
+-     */
+-    function faultCode()
+-    {
+-        if (isset($this->fn)) {
+-            return $this->fn;
+-        } else {
+-            return 0;
+-        }
+-    }
+-
+-    /**
+-     * @return string  the error string
+-     */
+-    function faultString()
+-    {
+-        return $this->fs;
+-    }
+-
+-    /**
+-     * @return mixed  the value
+-     */
+-    function value()
+-    {
+-        return $this->xv;
+-    }
+-
+-    /**
+-     * @return string  the error message in XML format
+-     */
+-    function serialize()
+-    {
+-        $rs = "\n";
+-        if ($this->fn) {
+-            $rs .= "
+-  
+-    
+-      
+-        faultCode
+-        " . $this->fn . "
+-      
+-      
+-        faultString
+-        " . $this->fs . "
+-      
+-    
+-  
+-";
+-        } else {
+-            $rs .= "\n\n" . $this->xv->serialize() .
+-        "\n";
+-        }
+-        $rs .= "\n";
+-        return $rs;
+-    }
+-}
+-
+-/**
+- * The methods and properties for composing XML RPC messages
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
+- * @version    Release: 1.3.1
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Message extends XML_RPC_Base
+-{
+-    /**
+-     * The current debug mode (1 = on, 0 = off)
+-     * @var integer
+-     */
+-    var $debug = 0;
+-
+-    /**
+-     * The encoding to be used for outgoing messages
+-     *
+-     * Defaults to the value of $GLOBALS['XML_RPC_defencoding']
+-     *
+-     * @var string
+-     * @see XML_RPC_Message::setSendEncoding(),
+-     *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
+-     */
+-    var $send_encoding = '';
+-
+-    /**
+-     * The method presently being evaluated
+-     * @var string
+-     */
+-    var $methodname = '';
+-
+-    /**
+-     * @var array
+-     */
+-    var $params = array();
+-
+-    /**
+-     * The XML message being generated
+-     * @var string
+-     */
+-    var $payload = '';
+-
+-    /**
+-     * @return void
+-     */
+-    function XML_RPC_Message($meth, $pars = 0)
+-    {
+-        $this->methodname = $meth;
+-        if (is_array($pars) && sizeof($pars) > 0) {
+-            for ($i = 0; $i < sizeof($pars); $i++) {
+-                $this->addParam($pars[$i]);
+-            }
+-        }
+-    }
+-
+-    /**
+-     * Produces the XML declaration including the encoding attribute
+-     *
+-     * The encoding is determined by this class' $send_encoding
+-     * property.  If the $send_encoding property is not set, use
+-     * $GLOBALS['XML_RPC_defencoding'].
+-     *
+-     * @return string  the XML declaration and  element
+-     *
+-     * @see XML_RPC_Message::setSendEncoding(),
+-     *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
+-     */
+-    function xml_header()
+-    {
+-        global $XML_RPC_defencoding;
+-        if (!$this->send_encoding) {
+-            $this->send_encoding = $XML_RPC_defencoding;
+-        }
+-        return 'send_encoding . '"?>'
+-               . "\n\n";
+-    }
+-
+-    /**
+-     * @return string  the closing  tag
+-     */
+-    function xml_footer()
+-    {
+-        return "\n";
+-    }
+-
+-    /**
+-     * @return void
+-     *
+-     * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
+-     */
+-    function createPayload()
+-    {
+-        $this->payload = $this->xml_header();
+-        $this->payload .= '' . $this->methodname . "\n";
+-        $this->payload .= "\n";
+-        for ($i = 0; $i < sizeof($this->params); $i++) {
+-            $p = $this->params[$i];
+-            $this->payload .= "\n" . $p->serialize() . "\n";
+-        }
+-        $this->payload .= "\n";
+-        $this->payload .= $this->xml_footer();
+-        $this->payload = ereg_replace("[\r\n]+", "\r\n", $this->payload);
+-    }
+-
+-    /**
+-     * @return string  the name of the method
+-     */
+-    function method($meth = '')
+-    {
+-        if ($meth != '') {
+-            $this->methodname = $meth;
+-        }
+-        return $this->methodname;
+-    }
+-
+-    /**
+-     * @return string  the payload
+-     */
+-    function serialize()
+-    {
+-        $this->createPayload();
+-        return $this->payload;
+-    }
+-
+-    /**
+-     * @return void
+-     */
+-    function addParam($par)
+-    {
+-        $this->params[] = $par;
+-    }
+-
+-    /**
+-     * Obtains an XML_RPC_Value object for the given parameter
+-     *
+-     * @param int $i  the index number of the parameter to obtain
+-     *
+-     * @return object  the XML_RPC_Value object.
+-     *                  If the parameter doesn't exist, an XML_RPC_Response object.
+-     *
+-     * @since Returns XML_RPC_Response object on error since Release 1.3.0
+-     */
+-    function getParam($i)
+-    {
+-        global $XML_RPC_err, $XML_RPC_str;
+-
+-        if (isset($this->params[$i])) {
+-            return $this->params[$i];
+-        } else {
+-            $this->raiseError('The submitted request did not contain this parameter',
+-                              XML_RPC_ERROR_INCORRECT_PARAMS);
+-            return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
+-                                        $XML_RPC_str['incorrect_params']);
+-        }
+-    }
+-
+-    /**
+-     * @return int  the number of parameters
+-     */
+-    function getNumParams()
+-    {
+-        return sizeof($this->params);
+-    }
+-
+-    /**
+-     * Sets the XML declaration's encoding attribute
+-     *
+-     * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
+-     *
+-     * @return void
+-     *
+-     * @see XML_RPC_Message::$send_encoding, XML_RPC_Message::xml_header()
+-     * @since Method available since Release 1.2.0
+-     */
+-    function setSendEncoding($type)
+-    {
+-        $this->send_encoding = $type;
+-    }
+-
+-    /**
+-     * Determine the XML's encoding via the encoding attribute
+-     * in the XML declaration
+-     *
+-     * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
+-     * or US-ASCII, $XML_RPC_defencoding will be returned.
+-     *
+-     * @param string $data  the XML that will be parsed
+-     *
+-     * @return string  the encoding to be used
+-     *
+-     * @link   http://php.net/xml_parser_create
+-     * @since  Method available since Release 1.2.0
+-     */
+-    function getEncoding($data)
+-    {
+-        global $XML_RPC_defencoding;
+-
+-        if (preg_match('/<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]/i',
+-                       $data, $match))
+-        {
+-            $match[1] = trim(strtoupper($match[1]));
+-            switch ($match[1]) {
+-                case 'ISO-8859-1':
+-                case 'UTF-8':
+-                case 'US-ASCII':
+-                    return $match[1];
+-                    break;
+-
+-                default:
+-                    return $XML_RPC_defencoding;
+-            }
+-        } else {
+-            return $XML_RPC_defencoding;
+-        }
+-    }
+-
+-    /**
+-     * @return object  a new XML_RPC_Response object
+-     */
+-    function parseResponseFile($fp)
+-    {
+-        $ipd = '';
+-        while ($data = @fread($fp, 8192)) {
+-            $ipd .= $data;
+-        }
+-        return $this->parseResponse($ipd);
+-    }
+-
+-    /**
+-     * @return object  a new XML_RPC_Response object
+-     */
+-    function parseResponse($data = '')
+-    {
+-        global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
+-
+-        $encoding = $this->getEncoding($data);
+-        $parser_resource = xml_parser_create($encoding);
+-        $parser = (int) $parser_resource;
+-
+-        $XML_RPC_xh[$parser] = array();
+-
+-        $XML_RPC_xh[$parser]['st'] = '';
+-        $XML_RPC_xh[$parser]['cm'] = 0;
+-        $XML_RPC_xh[$parser]['isf'] = 0;
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = '';
+-
+-        xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
+-        xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
+-        xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
+-
+-        $hdrfnd = 0;
+-        if ($this->debug) {
+-            print "
---GOT---\n";
+-            print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
+-            print "\n---END---\n
"; +- } +- +- // See if response is a 200 or a 100 then a 200, else raise error. +- // But only do this if we're using the HTTP protocol. +- if (ereg('^HTTP', $data) && +- !ereg('^HTTP/[0-9\.]+ 200 ', $data) && +- !preg_match('@^HTTP/[0-9\.]+ 10[0-9]([A-Za-z ]+)?[\r\n]+HTTP/[0-9\.]+ 200@', $data)) +- { +- $errstr = substr($data, 0, strpos($data, "\n") - 1); +- error_log('HTTP error, got response: ' . $errstr); +- $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], +- $XML_RPC_str['http_error'] . ' (' . +- $errstr . ')'); +- xml_parser_free($parser_resource); +- return $r; +- } +- // gotta get rid of headers here +- +- +- if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) { +- $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos); +- $data = substr($data, $brpos + 4); +- $hdrfnd = 1; +- } +- +- /* +- * be tolerant of junk after methodResponse +- * (e.g. javascript automatically inserted by free hosts) +- * thanks to Luca Mariano +- */ +- $data = substr($data, 0, strpos($data, "") + 17); +- +- if (!xml_parse($parser_resource, $data, sizeof($data))) { +- // thanks to Peter Kocks +- if (xml_get_current_line_number($parser_resource) == 1) { +- $errstr = 'XML error at line 1, check URL'; +- } else { +- $errstr = sprintf('XML error: %s at line %d', +- xml_error_string(xml_get_error_code($parser_resource)), +- xml_get_current_line_number($parser_resource)); +- } +- error_log($errstr); +- $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], +- $XML_RPC_str['invalid_return']); +- xml_parser_free($parser_resource); +- return $r; +- } +- xml_parser_free($parser_resource); +- if ($this->debug) { +- print '
---EVALING---[' .
+-            strlen($XML_RPC_xh[$parser]['st']) . " chars]---\n" .
+-            htmlspecialchars($XML_RPC_xh[$parser]['st']) . ";\n---END---
"; +- } +- if (strlen($XML_RPC_xh[$parser]['st']) == 0) { +- // then something odd has happened +- // and it's time to generate a client side error +- // indicating something odd went on +- $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], +- $XML_RPC_str['invalid_return']); +- } else { +- eval('$v=' . $XML_RPC_xh[$parser]['st'] . '; $allOK=1;'); +- if ($XML_RPC_xh[$parser]['isf']) { +- $f = $v->structmem('faultCode'); +- $fs = $v->structmem('faultString'); +- $r = new XML_RPC_Response($v, $f->scalarval(), +- $fs->scalarval()); +- } else { +- $r = new XML_RPC_Response($v); +- } +- } +- $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]); +- return $r; +- } +-} +- +-/** +- * The methods and properties that represent data in XML RPC format +- * +- * @category Web Services +- * @package XML_RPC +- * @author Edd Dumbill +- * @author Stig Bakken +- * @author Martin Jansen +- * @author Daniel Convissor +- * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group +- * @version Release: 1.3.1 +- * @link http://pear.php.net/package/XML_RPC +- */ +-class XML_RPC_Value extends XML_RPC_Base +-{ +- var $me = array(); +- var $mytype = 0; +- +- /** +- * @return void +- */ +- function XML_RPC_Value($val = -1, $type = '') +- { +- global $XML_RPC_Types; +- $this->me = array(); +- $this->mytype = 0; +- if ($val != -1 || $type != '') { +- if ($type == '') { +- $type = 'string'; +- } +- if (!array_key_exists($type, $XML_RPC_Types)) { +- // XXX +- // need some way to report this error +- } elseif ($XML_RPC_Types[$type] == 1) { +- $this->addScalar($val, $type); +- } elseif ($XML_RPC_Types[$type] == 2) { +- $this->addArray($val); +- } elseif ($XML_RPC_Types[$type] == 3) { +- $this->addStruct($val); +- } +- } +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addScalar($val, $type = 'string') +- { +- global $XML_RPC_Types, $XML_RPC_Boolean; +- +- if ($this->mytype == 1) { +- $this->raiseError('Scalar can have only one value', +- XML_RPC_ERROR_INVALID_TYPE); +- return 0; +- } +- $typeof = $XML_RPC_Types[$type]; +- if ($typeof != 1) { +- $this->raiseError("Not a scalar type (${typeof})", +- XML_RPC_ERROR_INVALID_TYPE); +- return 0; +- } +- +- if ($type == $XML_RPC_Boolean) { +- if (strcasecmp($val, 'true') == 0 +- || $val == 1 +- || ($val == true && strcasecmp($val, 'false'))) +- { +- $val = 1; +- } else { +- $val = 0; +- } +- } +- +- if ($this->mytype == 2) { +- // we're adding to an array here +- $ar = $this->me['array']; +- $ar[] = new XML_RPC_Value($val, $type); +- $this->me['array'] = $ar; +- } else { +- // a scalar, so set the value and remember we're scalar +- $this->me[$type] = $val; +- $this->mytype = $typeof; +- } +- return 1; +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addArray($vals) +- { +- global $XML_RPC_Types; +- if ($this->mytype != 0) { +- $this->raiseError( +- 'Already initialized as a [' . $this->kindOf() . ']', +- XML_RPC_ERROR_ALREADY_INITIALIZED); +- return 0; +- } +- $this->mytype = $XML_RPC_Types['array']; +- $this->me['array'] = $vals; +- return 1; +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addStruct($vals) +- { +- global $XML_RPC_Types; +- if ($this->mytype != 0) { +- $this->raiseError( +- 'Already initialized as a [' . $this->kindOf() . ']', +- XML_RPC_ERROR_ALREADY_INITIALIZED); +- return 0; +- } +- $this->mytype = $XML_RPC_Types['struct']; +- $this->me['struct'] = $vals; +- return 1; +- } +- +- /** +- * @return void +- */ +- function dump($ar) +- { +- reset($ar); +- foreach ($ar as $key => $val) { +- echo "$key => $val
"; +- if ($key == 'array') { +- foreach ($val as $key2 => $val2) { +- echo "-- $key2 => $val2
"; +- } +- } +- } +- } +- +- /** +- * @return string the data type of the current value +- */ +- function kindOf() +- { +- switch ($this->mytype) { +- case 3: +- return 'struct'; +- +- case 2: +- return 'array'; +- +- case 1: +- return 'scalar'; +- +- default: +- return 'undef'; +- } +- } +- +- /** +- * @return string the data in XML format +- */ +- function serializedata($typ, $val) +- { +- $rs = ''; +- global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean; +- if (!array_key_exists($typ, $XML_RPC_Types)) { +- // XXX +- // need some way to report this error +- return; +- } +- switch ($XML_RPC_Types[$typ]) { +- case 3: +- // struct +- $rs .= "\n"; +- reset($val); +- foreach ($val as $key2 => $val2) { +- $rs .= "${key2}\n"; +- $rs .= $this->serializeval($val2); +- $rs .= "\n"; +- } +- $rs .= ''; +- break; +- +- case 2: +- // array +- $rs .= "\n\n"; +- for ($i = 0; $i < sizeof($val); $i++) { +- $rs .= $this->serializeval($val[$i]); +- } +- $rs .= "\n"; +- break; +- +- case 1: +- switch ($typ) { +- case $XML_RPC_Base64: +- $rs .= "<${typ}>" . base64_encode($val) . ""; +- break; +- case $XML_RPC_Boolean: +- $rs .= "<${typ}>" . ($val ? '1' : '0') . ""; +- break; +- case $XML_RPC_String: +- $rs .= "<${typ}>" . htmlspecialchars($val). ""; +- break; +- default: +- $rs .= "<${typ}>${val}"; +- } +- } +- return $rs; +- } +- +- /** +- * @return string the data in XML format +- */ +- function serialize() +- { +- return $this->serializeval($this); +- } +- +- /** +- * @return string the data in XML format +- */ +- function serializeval($o) +- { +- $rs = ''; +- $ar = $o->me; +- reset($ar); +- list($typ, $val) = each($ar); +- $rs .= ''; +- $rs .= $this->serializedata($typ, $val); +- $rs .= "\n"; +- return $rs; +- } +- +- /** +- * @return mixed the contents of the element requested +- */ +- function structmem($m) +- { +- return $this->me['struct'][$m]; +- } +- +- /** +- * @return void +- */ +- function structreset() +- { +- reset($this->me['struct']); +- } +- +- /** +- * @return the key/value pair of the struct's current element +- */ +- function structeach() +- { +- return each($this->me['struct']); +- } +- +- /** +- * @return mixed the current value +- */ +- function getval() +- { +- // UNSTABLE +- global $XML_RPC_BOOLEAN, $XML_RPC_Base64; +- +- reset($this->me); +- $b = current($this->me); +- +- // contributed by I Sofer, 2001-03-24 +- // add support for nested arrays to scalarval +- // i've created a new method here, so as to +- // preserve back compatibility +- +- if (is_array($b)) { +- foreach ($b as $id => $cont) { +- $b[$id] = $cont->scalarval(); +- } +- } +- +- // add support for structures directly encoding php objects +- if (is_object($b)) { +- $t = get_object_vars($b); +- foreach ($t as $id => $cont) { +- $t[$id] = $cont->scalarval(); +- } +- foreach ($t as $id => $cont) { +- eval('$b->'.$id.' = $cont;'); +- } +- } +- +- // end contrib +- return $b; +- } +- +- /** +- * @return mixed +- */ +- function scalarval() +- { +- global $XML_RPC_Boolean, $XML_RPC_Base64; +- reset($this->me); +- return current($this->me); +- } +- +- /** +- * @return string +- */ +- function scalartyp() +- { +- global $XML_RPC_I4, $XML_RPC_Int; +- reset($this->me); +- $a = key($this->me); +- if ($a == $XML_RPC_I4) { +- $a = $XML_RPC_Int; +- } +- return $a; +- } +- +- /** +- * @return mixed the struct's current element +- */ +- function arraymem($m) +- { +- return $this->me['array'][$m]; +- } +- +- /** +- * @return int the number of elements in the array +- */ +- function arraysize() +- { +- reset($this->me); +- list($a, $b) = each($this->me); +- return sizeof($b); +- } +- +- /** +- * Determines if the item submitted is an XML_RPC_Value object +- * +- * @param mixed $val the variable to be evaluated +- * +- * @return bool TRUE if the item is an XML_RPC_Value object +- * +- * @static +- * @since Method available since Release 1.3.0 +- */ +- function isValue($val) +- { +- return (strtolower(get_class($val)) == 'xml_rpc_value'); +- } +-} +- +-/** +- * Return an ISO8601 encoded string +- * +- * While timezones ought to be supported, the XML-RPC spec says: +- * +- * "Don't assume a timezone. It should be specified by the server in its +- * documentation what assumptions it makes about timezones." +- * +- * This routine always assumes localtime unless $utc is set to 1, in which +- * case UTC is assumed and an adjustment for locale is made when encoding. +- * +- * @return string the formatted date +- */ +-function XML_RPC_iso8601_encode($timet, $utc = 0) +-{ +- if (!$utc) { +- $t = strftime('%Y%m%dT%H:%M:%S', $timet); +- } else { +- if (function_exists('gmstrftime')) { +- // gmstrftime doesn't exist in some versions +- // of PHP +- $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); +- } else { +- $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); +- } +- } +- return $t; +-} +- +-/** +- * Convert a datetime string into a Unix timestamp +- * +- * While timezones ought to be supported, the XML-RPC spec says: +- * +- * "Don't assume a timezone. It should be specified by the server in its +- * documentation what assumptions it makes about timezones." +- * +- * This routine always assumes localtime unless $utc is set to 1, in which +- * case UTC is assumed and an adjustment for locale is made when encoding. +- * +- * @return int the unix timestamp of the date submitted +- */ +-function XML_RPC_iso8601_decode($idate, $utc = 0) +-{ +- $t = 0; +- if (ereg('([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})', $idate, $regs)) { +- if ($utc) { +- $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +- } else { +- $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +- } +- } +- return $t; +-} +- +-/** +- * Converts an XML_RPC_Value object into native PHP types +- * +- * @param object $XML_RPC_val the XML_RPC_Value object to decode +- * +- * @return mixed the PHP values +- */ +-function XML_RPC_decode($XML_RPC_val) +-{ +- $kind = $XML_RPC_val->kindOf(); +- +- if ($kind == 'scalar') { +- return $XML_RPC_val->scalarval(); +- +- } elseif ($kind == 'array') { +- $size = $XML_RPC_val->arraysize(); +- $arr = array(); +- for ($i = 0; $i < $size; $i++) { +- $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i)); +- } +- return $arr; +- +- } elseif ($kind == 'struct') { +- $XML_RPC_val->structreset(); +- $arr = array(); +- while (list($key, $value) = $XML_RPC_val->structeach()) { +- $arr[$key] = XML_RPC_decode($value); +- } +- return $arr; +- } +-} +- +-/** +- * Converts native PHP types into an XML_RPC_Value object +- * +- * @param mixed $php_val the PHP value or variable you want encoded +- * +- * @return object the XML_RPC_Value object +- */ +-function XML_RPC_encode($php_val) +-{ +- global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double, $XML_RPC_String, +- $XML_RPC_Array, $XML_RPC_Struct; +- +- $type = gettype($php_val); +- $XML_RPC_val = new XML_RPC_Value; +- +- switch ($type) { +- case 'array': +- if (empty($php_val)) { +- $XML_RPC_val->addArray($php_val); +- break; +- } +- $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); +- if (empty($tmp)) { +- $arr = array(); +- foreach ($php_val as $k => $v) { +- $arr[$k] = XML_RPC_encode($v); +- } +- $XML_RPC_val->addArray($arr); +- break; +- } +- // fall though if it's not an enumerated array +- +- case 'object': +- $arr = array(); +- foreach ($php_val as $k => $v) { +- $arr[$k] = XML_RPC_encode($v); +- } +- $XML_RPC_val->addStruct($arr); +- break; +- +- case 'integer': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Int); +- break; +- +- case 'double': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Double); +- break; +- +- case 'string': +- case 'NULL': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_String); +- break; +- +- case 'boolean': +- // Add support for encoding/decoding of booleans, since they +- // are supported in PHP +- // by +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean); +- break; +- +- case 'unknown type': +- default: +- $XML_RPC_val = false; +- } +- return $XML_RPC_val; +-} +- +-/* +- * Local variables: +- * tab-width: 4 +- * c-basic-offset: 4 +- * c-hanging-comment-ender-p: nil +- * End: +- */ +- +-?> +-XML_RPC-1.3.1/Server.php100644 1750 144 47770 10260516576 10104 +- * @author Stig Bakken +- * @author Martin Jansen +- * @author Daniel Convissor +- * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group +- * @version CVS: $Id: Server.php,v 1.26 2005/05/09 21:39:47 danielc Exp $ +- * @link http://pear.php.net/package/XML_RPC +- */ +- +- +-/** +- * Pull in the XML_RPC class +- */ +-require_once 'XML/RPC.php'; +- +- +-/** +- * signature for system.listMethods: return = array, +- * parameters = a string or nothing +- * @global array $GLOBALS['XML_RPC_Server_listMethods_sig'] +- */ +-$GLOBALS['XML_RPC_Server_listMethods_sig'] = array( +- array($GLOBALS['XML_RPC_Array'], +- $GLOBALS['XML_RPC_String'] +- ), +- array($GLOBALS['XML_RPC_Array']) +-); +- +-/** +- * docstring for system.listMethods +- * @global string $GLOBALS['XML_RPC_Server_listMethods_doc'] +- */ +-$GLOBALS['XML_RPC_Server_listMethods_doc'] = 'This method lists all the' +- . ' methods that the XML-RPC server knows how to dispatch'; +- +-/** +- * signature for system.methodSignature: return = array, +- * parameters = string +- * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig'] +- */ +-$GLOBALS['XML_RPC_Server_methodSignature_sig'] = array( +- array($GLOBALS['XML_RPC_Array'], +- $GLOBALS['XML_RPC_String'] +- ) +-); +- +-/** +- * docstring for system.methodSignature +- * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc'] +- */ +-$GLOBALS['XML_RPC_Server_methodSignature_doc'] = 'Returns an array of known' +- . ' signatures (an array of arrays) for the method name passed. If' +- . ' no signatures are known, returns a none-array (test for type !=' +- . ' array to detect missing signature)'; +- +-/** +- * signature for system.methodHelp: return = string, +- * parameters = string +- * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig'] +- */ +-$GLOBALS['XML_RPC_Server_methodHelp_sig'] = array( +- array($GLOBALS['XML_RPC_String'], +- $GLOBALS['XML_RPC_String'] +- ) +-); +- +-/** +- * docstring for methodHelp +- * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc'] +- */ +-$GLOBALS['XML_RPC_Server_methodHelp_doc'] = 'Returns help text if defined' +- . ' for the method passed, otherwise returns an empty string'; +- +-/** +- * dispatch map for the automatically declared XML-RPC methods. +- * @global array $GLOBALS['XML_RPC_Server_dmap'] +- */ +-$GLOBALS['XML_RPC_Server_dmap'] = array( +- 'system.listMethods' => array( +- 'function' => 'XML_RPC_Server_listMethods', +- 'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc'] +- ), +- 'system.methodHelp' => array( +- 'function' => 'XML_RPC_Server_methodHelp', +- 'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc'] +- ), +- 'system.methodSignature' => array( +- 'function' => 'XML_RPC_Server_methodSignature', +- 'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc'] +- ) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_debuginfo'] +- */ +-$GLOBALS['XML_RPC_Server_debuginfo'] = ''; +- +- +-/** +- * Lists all the methods that the XML-RPC server knows how to dispatch +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_listMethods($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $v = new XML_RPC_Value(); +- $outAr = array(); +- foreach ($server->dmap as $key => $val) { +- $outAr[] = new XML_RPC_Value($key, 'string'); +- } +- foreach ($XML_RPC_Server_dmap as $key => $val) { +- $outAr[] = new XML_RPC_Value($key, 'string'); +- } +- $v->addArray($outAr); +- return new XML_RPC_Response($v); +-} +- +-/** +- * Returns an array of known signatures (an array of arrays) +- * for the given method +- * +- * If no signatures are known, returns a none-array +- * (test for type != array to detect missing signature) +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_methodSignature($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $methName = $m->getParam(0); +- $methName = $methName->scalarval(); +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $server->dmap; +- $sysCall = 0; +- } +- // print "\n"; +- if (isset($dmap[$methName])) { +- if ($dmap[$methName]['signature']) { +- $sigs = array(); +- $thesigs = $dmap[$methName]['signature']; +- for ($i = 0; $i < sizeof($thesigs); $i++) { +- $cursig = array(); +- $inSig = $thesigs[$i]; +- for ($j = 0; $j < sizeof($inSig); $j++) { +- $cursig[] = new XML_RPC_Value($inSig[$j], 'string'); +- } +- $sigs[] = new XML_RPC_Value($cursig, 'array'); +- } +- $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array')); +- } else { +- $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string')); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], +- $XML_RPC_str['introspect_unknown']); +- } +- return $r; +-} +- +-/** +- * Returns help text if defined for the method passed, otherwise returns +- * an empty string +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_methodHelp($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $methName = $m->getParam(0); +- $methName = $methName->scalarval(); +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $server->dmap; +- $sysCall = 0; +- } +- // print "\n"; +- if (isset($dmap[$methName])) { +- if ($dmap[$methName]['docstring']) { +- $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']), +- 'string'); +- } else { +- $r = new XML_RPC_Response(new XML_RPC_Value('', 'string')); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], +- $XML_RPC_str['introspect_unknown']); +- } +- return $r; +-} +- +-/** +- * @return void +- */ +-function XML_RPC_Server_debugmsg($m) +-{ +- global $XML_RPC_Server_debuginfo; +- $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n"; +-} +- +- +-/** +- * A server for receiving and replying to XML RPC requests +- * +- * +- * $server = new XML_RPC_Server( +- * array( +- * 'isan8' => +- * array( +- * 'function' => 'is_8', +- * 'signature' => +- * array( +- * array('boolean', 'int'), +- * array('boolean', 'int', 'boolean'), +- * array('boolean', 'string'), +- * array('boolean', 'string', 'boolean'), +- * ), +- * 'docstring' => 'Is the value an 8?' +- * ), +- * ), +- * 1, +- * 0 +- * ); +- * +- * +- * @category Web Services +- * @package XML_RPC +- * @author Edd Dumbill +- * @author Stig Bakken +- * @author Martin Jansen +- * @author Daniel Convissor +- * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group +- * @version Release: 1.3.1 +- * @link http://pear.php.net/package/XML_RPC +- */ +-class XML_RPC_Server +-{ +- /** +- * The dispatch map, listing the methods this server provides. +- * @var array +- */ +- var $dmap = array(); +- +- /** +- * The present response's encoding +- * @var string +- * @see XML_RPC_Message::getEncoding() +- */ +- var $encoding = ''; +- +- /** +- * Debug mode (0 = off, 1 = on) +- * @var integer +- */ +- var $debug = 0; +- +- /** +- * The response's HTTP headers +- * @var string +- */ +- var $server_headers = ''; +- +- /** +- * The response's XML payload +- * @var string +- */ +- var $server_payload = ''; +- +- +- /** +- * Constructor for the XML_RPC_Server class +- * +- * @param array $dispMap the dispatch map. An associative array +- * explaining each function. The keys of the main +- * array are the procedure names used by the +- * clients. The value is another associative array +- * that contains up to three elements: +- * + The 'function' element's value is the name +- * of the function or method that gets called. +- * To define a class' method: 'class::method'. +- * + The 'signature' element (optional) is an +- * array describing the return values and +- * parameters +- * + The 'docstring' element (optional) is a +- * string describing what the method does +- * @param int $serviceNow should the HTTP response be sent now? +- * (1 = yes, 0 = no) +- * @param int $debug should debug output be displayed? +- * (1 = yes, 0 = no) +- * +- * @return void +- */ +- function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) +- { +- global $HTTP_RAW_POST_DATA; +- +- if ($debug) { +- $this->debug = 1; +- } else { +- $this->debug = 0; +- } +- +- $this->dmap = $dispMap; +- +- if ($serviceNow) { +- $this->service(); +- } else { +- $this->createServerPayload(); +- $this->createServerHeaders(); +- } +- } +- +- /** +- * @return string the debug information if debug debug mode is on +- */ +- function serializeDebug() +- { +- global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA; +- +- if ($this->debug) { +- XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n" +- . $HTTP_RAW_POST_DATA +- . "\n" . '^^^ END POST DATA ^^^'); +- } +- +- if ($XML_RPC_Server_debuginfo != '') { +- return "\n"; +- } else { +- return ''; +- } +- } +- +- /** +- * Sends the response +- * +- * The encoding and content-type are determined by +- * XML_RPC_Message::getEncoding() +- * +- * @return void +- * +- * @uses XML_RPC_Server::createServerPayload(), +- * XML_RPC_Server::createServerHeaders() +- */ +- function service() +- { +- $this->createServerPayload(); +- $this->createServerHeaders(); +- header($this->server_headers); +- print $this->server_payload; +- } +- +- /** +- * Generates the payload and puts it in the $server_payload property +- * +- * @return void +- * +- * @uses XML_RPC_Server::parseRequest(), XML_RPC_Server::$encoding, +- * XML_RPC_Response::serialize(), XML_RPC_Server::serializeDebug() +- */ +- function createServerPayload() +- { +- $r = $this->parseRequest(); +- $this->server_payload = 'encoding . '"?>' . "\n" +- . $this->serializeDebug() +- . $r->serialize(); +- } +- +- /** +- * Determines the HTTP headers and puts them in the $server_headers +- * property +- * +- * @return boolean TRUE if okay, FALSE if $server_payload isn't set. +- * +- * @uses XML_RPC_Server::createServerPayload(), +- * XML_RPC_Server::$server_headers +- */ +- function createServerHeaders() +- { +- if (!$this->server_payload) { +- return false; +- } +- $this->server_headers = 'Content-Length: ' +- . strlen($this->server_payload) . "\r\n" +- . 'Content-Type: text/xml;' +- . ' charset=' . $this->encoding; +- return true; +- } +- +- /** +- * @return array +- */ +- function verifySignature($in, $sig) +- { +- for ($i = 0; $i < sizeof($sig); $i++) { +- // check each possible signature in turn +- $cursig = $sig[$i]; +- if (sizeof($cursig) == $in->getNumParams() + 1) { +- $itsOK = 1; +- for ($n = 0; $n < $in->getNumParams(); $n++) { +- $p = $in->getParam($n); +- // print "\n"; +- if ($p->kindOf() == 'scalar') { +- $pt = $p->scalartyp(); +- } else { +- $pt = $p->kindOf(); +- } +- // $n+1 as first type of sig is return type +- if ($pt != $cursig[$n+1]) { +- $itsOK = 0; +- $pno = $n+1; +- $wanted = $cursig[$n+1]; +- $got = $pt; +- break; +- } +- } +- if ($itsOK) { +- return array(1); +- } +- } +- } +- if (isset($wanted)) { +- return array(0, "Wanted ${wanted}, got ${got} at param ${pno}"); +- } else { +- $allowed = array(); +- foreach ($sig as $val) { +- end($val); +- $allowed[] = key($val); +- } +- $allowed = array_unique($allowed); +- $last = count($allowed) - 1; +- if ($last > 0) { +- $allowed[$last] = 'or ' . $allowed[$last]; +- } +- return array(0, +- 'Signature permits ' . implode(', ', $allowed) +- . ' parameters but the request had ' +- . $in->getNumParams()); +- } +- } +- +- /** +- * @return object a new XML_RPC_Response object +- * +- * @uses XML_RPC_Message::getEncoding(), XML_RPC_Server::$encoding +- */ +- function parseRequest($data = '') +- { +- global $XML_RPC_xh, $HTTP_RAW_POST_DATA, +- $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml, +- $XML_RPC_defencoding, $XML_RPC_Server_dmap; +- +- if ($data == '') { +- $data = $HTTP_RAW_POST_DATA; +- } +- +- $this->encoding = XML_RPC_Message::getEncoding($data); +- $parser_resource = xml_parser_create($this->encoding); +- $parser = (int) $parser_resource; +- +- $XML_RPC_xh[$parser] = array(); +- $XML_RPC_xh[$parser]['st'] = ''; +- $XML_RPC_xh[$parser]['cm'] = 0; +- $XML_RPC_xh[$parser]['isf'] = 0; +- $XML_RPC_xh[$parser]['params'] = array(); +- $XML_RPC_xh[$parser]['method'] = ''; +- +- $plist = ''; +- +- // decompose incoming XML into request structure +- +- xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true); +- xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee'); +- xml_set_character_data_handler($parser_resource, 'XML_RPC_cd'); +- if (!xml_parse($parser_resource, $data, 1)) { +- // return XML error as a faultCode +- $r = new XML_RPC_Response(0, +- $XML_RPC_errxml+xml_get_error_code($parser_resource), +- sprintf('XML error: %s at line %d', +- xml_error_string(xml_get_error_code($parser_resource)), +- xml_get_current_line_number($parser_resource))); +- xml_parser_free($parser_resource); +- } else { +- xml_parser_free($parser_resource); +- $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']); +- // now add parameters in +- for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) { +- // print '\n"; +- $plist .= "$i - " . $XML_RPC_xh[$parser]['params'][$i] . " \n"; +- eval('$m->addParam(' . $XML_RPC_xh[$parser]['params'][$i] . ');'); +- } +- XML_RPC_Server_debugmsg($plist); +- +- // now to deal with the method +- $methName = $XML_RPC_xh[$parser]['method']; +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $this->dmap; +- $sysCall = 0; +- } +- +- if (isset($dmap[$methName]['function']) +- && is_string($dmap[$methName]['function']) +- && strpos($dmap[$methName]['function'], '::') !== false) +- { +- $dmap[$methName]['function'] = +- explode('::', $dmap[$methName]['function']); +- } +- +- if (isset($dmap[$methName]['function']) +- && is_callable($dmap[$methName]['function'])) +- { +- // dispatch if exists +- if (isset($dmap[$methName]['signature'])) { +- $sr = $this->verifySignature($m, +- $dmap[$methName]['signature'] ); +- } +- if (!isset($dmap[$methName]['signature']) || $sr[0]) { +- // if no signature or correct signature +- if ($sysCall) { +- $r = call_user_func($dmap[$methName]['function'], $this, $m); +- } else { +- $r = call_user_func($dmap[$methName]['function'], $m); +- } +- if (!is_a($r, 'XML_RPC_Response')) { +- $r = new XML_RPC_Response(0, $XML_RPC_err['not_response_object'], +- $XML_RPC_str['not_response_object']); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], +- $XML_RPC_str['incorrect_params'] +- . ': ' . $sr[1]); +- } +- } else { +- // else prepare error response +- $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'], +- $XML_RPC_str['unknown_method']); +- } +- } +- return $r; +- } +- +- /** +- * Echos back the input packet as a string value +- * +- * @return void +- * +- * Useful for debugging. +- */ +- function echoInput() +- { +- global $HTTP_RAW_POST_DATA; +- +- $r = new XML_RPC_Response(0); +- $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); +- print $r->serialize(); +- } +-} +- +-/* +- * Local variables: +- * tab-width: 4 +- * c-basic-offset: 4 +- * c-hanging-comment-ender-p: nil +- * End: +- */ +- +-?> +-package.xml100644 1750 144 22507 10260516576 6427 +- +- +- XML_RPC +- PHP implementation of the XML-RPC protocol +- A PEAR-ified version of Useful Inc's XML-RPC for PHP. +- +-It has support for HTTP/HTTPS transport, proxies and authentication. +- +- +- +- ssb +- Stig Bakken +- stig@php.net +- lead +- +- +- danielc +- Daniel Convissor +- danielc@php.net +- lead +- +- +- +- 1.3.1 +- 2005-06-29 +- PHP License +- stable +- * Security fix. Update highly recommended! +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- 1.3.0RC3 +- 2005-05-10 +- beta +- * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. +-* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. +-* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. +-* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. +-* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). +-* Use <br /> instead of <br> in XML_RPC_Value::dump(). +- +- +- +- 1.3.0RC2 +- 2005-05-05 +- beta +- * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. +-* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. +-* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. +-* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. +- +- +- +- 1.3.0RC1 +- 2005-04-07 +- beta +- * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. +-* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. +-* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. +-* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. +-* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. +-* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. +- +- +- +- 1.2.2 +- 2005-03-07 +- stable +- * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. +- +- +- +- 1.2.1 +- 2005-03-01 +- stable +- * Add isset() check before examining the dispatch map. Bug 3658. +- +- +- +- 1.2.0 +- 2005-02-27 +- stable +- * Provide the "stable" release. +-* Add package2.xml for compatibility with PEAR 1.4.0. +-* For changes since 1.1.0, see the changelogs for the various RC releases. +- +- +- +- 1.2.0RC7 +- 2005-02-22 +- beta +- * Add the setSendEncoding() method and $send_encoding +- property to XML_RPC_Message. Request 3537. +-* Allow class methods to be mapped using either syntax: +- 'function' => 'hello::sayHello', +- or +- 'function' => array('hello', 'sayhello'), +- Bug 3363. +-* Use 8192 instead of 32768 for bytes in fread() +- in parseResponseFile(). Bug 3340. +- +- +- +- 1.2.0RC6 +- 2005-01-25 +- beta +- * Don't put the protocol in the Host field of the POST data. (danielc) +- +- +- +- 1.2.0RC5 +- 2005-01-24 +- beta +- * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. +- +- +- +- 1.2.0RC4 +- 2005-01-24 +- beta +- * When a connection attempt fails, have the method return 0. (danielc) +-* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) +-* Add tests for setting the client properties. (danielc) +-* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) +-* Bundle the tests with the package. (danielc) +- +- +- +- 1.2.0RC3 +- 2005-01-19 +- beta +- * ssl uses port 443, not 445. +- +- +- +- 1.2.0RC2 +- 2005-01-11 +- beta +- * Handle ssl:// in the $server string. (danielc) +-* Also default to port 445 for ssl:// requests as well. (danielc) +-* Enhance debugging in the server. (danielc) +- +- +- +- 1.2.0RC1 +- 2004-12-30 +- beta +- * Make things work with SSL. Bug 2489. (nkukard lbsd net) +-* Allow array function callbacks (Matt Kane) +-* Some minor speed-ups (Matt Kane) +-* Add Dump.php to the package (Christian Weiske) +-* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) +-* Silence fsockopen() errors. Bug 1714. (danielc) +-* Encode empty arrays as an array. Bug 1493. (danielc) +-* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) +-* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) +-* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) +-* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) +-* Allow raiseError() to be called statically. (danielc) +-* Stop double escaping of character entities. Bug 987. (danielc) +- NOTICE: the following have been removed: +- * XML_RPC_dh() +- * $GLOBALS['XML_RPC_entities'] +- * XML_RPC_entity_decode() +- * XML_RPC_lookup_entity() +-* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) +- +- +- +- 1.1.0 +- 2004-03-15 +- stable +- * Added support for sequential arrays to XML_RPC_encode() (mroch) +-* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) +-* Remove "require_once 'PEAR.php'", include only when needed to raise an error +-* Replace echo and error_log() with raiseError() (mroch) +-* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) +-* be tolerant of junk after methodResponse (Luca Mariano, mroch) +-* Silent notice even in the error log (pierre) +-* fix include of shared xml extension on win32 (pierre) +- +- +- +- 1.0.4 +- 2002-10-02 +- stable +- * added HTTP proxy authorization support (thanks to Arnaud Limbourg) +- +- +- +- 1.0.3 +- 2002-05-19 +- stable +- * fix bug when parsing responses with boolean types +- +- +- +- 1.0.2 +- 2002-04-16 +- stable +- * E_ALL fixes +-* fix HTTP response header parsing +- +- +- +- 1.0.1 +- 2001-09-25 +- stable +- This is a PEAR-ified version of Useful Inc's 1.0.1 release. +-Includes an urgent security fix identified by Dan Libby <dan@libby.com>. +- +- +- +- +- +\ Kein Zeilenumbruch am Dateiende. +diff -Nura php-4.4.0/pear/packages/XML_RPC-1.4.0.tar hardening-patch-4.4.0-0.4.2/pear/packages/XML_RPC-1.4.0.tar +--- php-4.4.0/pear/packages/XML_RPC-1.4.0.tar 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/pear/packages/XML_RPC-1.4.0.tar 2005-08-22 23:59:57.000000000 +0200 +@@ -0,0 +1,3933 @@ ++package2.xml100666 0 0 37144 10277724746 6362 ++ ++ XML_RPC ++ pear.php.net ++ PHP implementation of the XML-RPC protocol ++ A PEAR-ified version of Useful Inc's XML-RPC for PHP. ++ ++It has support for HTTP/HTTPS transport, proxies and authentication. ++ ++ Stig Bakken ++ ssb ++ stig@php.net ++ no ++ ++ ++ Daniel Convissor ++ danielc ++ danielc@php.net ++ yes ++ ++ 2005-08-14 ++ ++ ++ 1.4.0 ++ 1.4.0 ++ ++ ++ stable ++ stable ++ ++ PHP License ++ * MAJOR SECURITY FIX: eliminate use of eval(). ++* Using socket_get_status() because stream_get_meta_data() was introduced in 4.3.0, but we need to support 4.2.0. Bug 4805. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ PEAR ++ pear.php.net ++ 1.4.0a1 ++ 1.4.0a12 ++ ++ ++ ++ ++ 4.2.0 ++ 6.0.0 ++ ++ ++ 1.4.0a1 ++ ++ ++ ++ ++ ++ ++ ++ 1.3.3 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ 2005-07-15 ++ PHP License ++ * Eliminate memory leak by resetting $XML_RPC_xh each time parseResponse() is called. Bug 4780. ++* Using socket_set_timeout() because stream_set_timeout() was introduced in 4.3.0, but we need to support 4.2.0. Bug 4805. ++ ++ ++ ++ 1.3.2 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ 2005-07-07 ++ PHP License ++ * Eliminate path disclosure vulnerabilities by suppressing error messages when eval()'ing. ++* Eliminate path disclosure vulnerability by catching bogus parameters submitted to XML_RPC_Value::serializeval(). ++* In XML_RPC_Server::service(), only call createServerPayload() and createServerHeaders() if necessary. Fixes compatibility issue introduced in Release 1.3.0RC1 for users who set the $serviceNow parameter of XML_RPC_Server() to 0. Bug 4757. ++* Change "var $errstring" to "var $errstr". Bug 4582. Was put into CVS version 1.75 of RPC.php but didn't make it into RELEASE_1_3_1. ++ ++ ++ ++ 1.3.1 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ 2005-06-29 ++ PHP License ++ * Security fix. Update highly recommended! ++ ++ ++ ++ 1.3.0 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ 2005-06-13 ++ PHP License ++ * Stable release. See earlier releases for changes since 1.2.2. ++ ++ ++ ++ 1.3.0RC3 ++ 1.3.0 ++ ++ ++ beta ++ stable ++ ++ 2005-05-10 ++ PHP License ++ * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. ++* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. ++* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. ++* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. ++* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). ++* Use <br /> instead of <br> in XML_RPC_Value::dump(). ++ ++ ++ ++ 1.3.0RC2 ++ 1.3.0 ++ ++ ++ beta ++ beta ++ ++ 2005-05-05 ++ PHP License ++ * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. ++* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. ++* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. ++* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. ++ ++ ++ ++ 1.3.0RC1 ++ 1.3.0 ++ ++ ++ beta ++ beta ++ ++ 2005-04-07 ++ PHP License ++ * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. ++* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. ++* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. ++* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. ++* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. ++* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. ++ ++ ++ ++ 1.2.2 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-03-07 ++ PHP License ++ * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. ++ ++ ++ ++ 1.2.1 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-03-01 ++ PHP License ++ * Add isset() check before examining the dispatch map. Bug 3658. ++ ++ ++ ++ 1.2.0 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-02-27 ++ PHP License ++ * Provide the "stable" release. ++* Add package2.xml for compatibility with PEAR 1.4.0. ++* For changes since 1.1.0, see the changelogs for the various RC releases. ++ ++ ++ ++ 1.2.0RC7 ++ 1.2.0RC7 ++ ++ ++ beta ++ beta ++ ++ 2005-02-22 ++ PHP License ++ * Add the setSendEncoding() method and $send_encoding ++ property to XML_RPC_Message. Request 3537. ++* Allow class methods to be mapped using either syntax: ++ 'function' => 'hello::sayHello', ++ or ++ 'function' => array('hello', 'sayhello'), ++ Bug 3363. ++* Use 8192 instead of 32768 for bytes in fread() ++ in parseResponseFile(). Bug 3340. ++ ++ ++ ++ 1.2.0RC6 ++ 1.2.0RC6 ++ ++ ++ beta ++ beta ++ ++ 2005-01-25 ++ PHP License ++ * Don't put the protocol in the Host field of the POST data. (danielc) ++ ++ ++ ++ 1.2.0RC5 ++ 1.2.0RC5 ++ ++ ++ beta ++ beta ++ ++ 2005-01-24 ++ PHP License ++ * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. ++ ++ ++ ++ 1.2.0RC4 ++ 1.2.0RC4 ++ ++ ++ beta ++ beta ++ ++ 2005-01-24 ++ PHP License ++ * When a connection attempt fails, have the method return 0. (danielc) ++* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) ++* Add tests for setting the client properties. (danielc) ++* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) ++* Bundle the tests with the package. (danielc) ++ ++ ++ ++ 1.2.0RC3 ++ 1.2.0RC3 ++ ++ ++ beta ++ beta ++ ++ 2005-01-19 ++ PHP License ++ * ssl uses port 443, not 445. ++ ++ ++ ++ 1.2.0RC2 ++ 1.2.0RC2 ++ ++ ++ beta ++ beta ++ ++ 2005-01-11 ++ PHP License ++ * Handle ssl:// in the $server string. (danielc) ++* Also default to port 445 for ssl:// requests as well. (danielc) ++* Enhance debugging in the server. (danielc) ++ ++ ++ ++ 1.2.0RC1 ++ 1.2.0RC1 ++ ++ ++ beta ++ beta ++ ++ 2004-12-30 ++ PHP License ++ * Make things work with SSL. Bug 2489. (nkukard lbsd net) ++* Allow array function callbacks (Matt Kane) ++* Some minor speed-ups (Matt Kane) ++* Add Dump.php to the package (Christian Weiske) ++* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) ++* Silence fsockopen() errors. Bug 1714. (danielc) ++* Encode empty arrays as an array. Bug 1493. (danielc) ++* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) ++* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) ++* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) ++* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) ++* Allow raiseError() to be called statically. (danielc) ++* Stop double escaping of character entities. Bug 987. (danielc) ++ NOTICE: the following have been removed: ++ * XML_RPC_dh() ++ * $GLOBALS['XML_RPC_entities'] ++ * XML_RPC_entity_decode() ++ * XML_RPC_lookup_entity() ++* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) ++ ++ ++ ++ 1.1.0 ++ 1.1.0 ++ ++ ++ stable ++ stable ++ ++ 2004-03-15 ++ PHP License ++ * Added support for sequential arrays to XML_RPC_encode() (mroch) ++* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) ++* Remove "require_once 'PEAR.php'", include only when needed to raise an error ++* Replace echo and error_log() with raiseError() (mroch) ++* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) ++* be tolerant of junk after methodResponse (Luca Mariano, mroch) ++* Silent notice even in the error log (pierre) ++* fix include of shared xml extension on win32 (pierre) ++ ++ ++ ++ 1.0.4 ++ 1.0.4 ++ ++ ++ stable ++ stable ++ ++ 2002-10-02 ++ PHP License ++ * added HTTP proxy authorization support (thanks to Arnaud Limbourg) ++ ++ ++ ++ 1.0.3 ++ 1.0.3 ++ ++ ++ stable ++ stable ++ ++ 2002-05-19 ++ PHP License ++ * fix bug when parsing responses with boolean types ++ ++ ++ ++ 1.0.2 ++ 1.0.2 ++ ++ ++ stable ++ stable ++ ++ 2002-04-16 ++ PHP License ++ * E_ALL fixes ++* fix HTTP response header parsing ++ ++ ++ ++ 1.0.1 ++ 1.0.1 ++ ++ ++ stable ++ stable ++ ++ 2001-09-25 ++ PHP License ++ This is a PEAR-ified version of Useful Inc's 1.0.1 release. ++Includes an urgent security fix identified by Dan Libby <dan@libby.com>. ++ ++ ++ ++XML_RPC-1.4.0/tests/protoport.php100666 0 0 25543 10277724745 11707 ++ * @copyright 2005 The PHP Group ++ * @license http://www.php.net/license/3_0.txt PHP License ++ * @version CVS: $Id: protoport.php,v 1.4 2005/01/24 17:48:47 danielc Exp $ ++ * @link http://pear.php.net/package/XML_RPC ++ * @since File available since Release 1.2 ++ */ ++ ++/* ++ * If the package version number is found in the left hand ++ * portion of the if() expression below, that means this file has ++ * come from the PEAR installer. Therefore, let's test the ++ * installed version of XML_RPC which should be in the include path. ++ * ++ * If the version has not been substituted in the if() expression, ++ * this file has likely come from a CVS checkout or a .tar file. ++ * Therefore, we'll assume the tests should use the version of ++ * XML_RPC that has come from there as well. ++ */ ++if ('1.4.0' != '@'.'package_version'.'@') { ++ /** ++ * Get the needed class from the PEAR installation ++ */ ++ require_once 'XML/RPC.php'; ++} else { ++ /** ++ * Get the needed class from the parent directory ++ */ ++ require_once '../RPC.php'; ++} ++ ++/** ++ * Compare the test result to the expected result ++ * ++ * If the test fails, echo out the results. ++ * ++ * @param array $expect the array of object properties you expect ++ * from the test ++ * @param object $actual the object results from the test ++ * @param string $test_name the name of the test ++ * ++ * @return void ++ */ ++function compare($expect, $actual, $test_name) { ++ $actual = get_object_vars($actual); ++ if (count(array_diff($actual, $expect))) { ++ echo "$test_name failed.\nExpect: "; ++ print_r($expect); ++ echo "Actual: "; ++ print_r($actual); ++ echo "\n"; ++ } ++} ++ ++if (php_sapi_name() != 'cli') { ++ echo "
\n";
++}
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver');
++compare($x, $c, 'defaults');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver');
++compare($x, $c, 'defaults with http');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver');
++compare($x, $c, 'defaults with https');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver');
++compare($x, $c, 'defaults with ssl');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 65);
++compare($x, $c, 'port 65');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 65);
++compare($x, $c, 'port 65 with http');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 65);
++compare($x, $c, 'port 65 with https');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65);
++compare($x, $c, 'port 65 with ssl');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 0,
++                        'theproxy');
++compare($x, $c, 'defaults proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 0,
++                        'http://theproxy');
++compare($x, $c, 'defaults with http proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 0,
++                        'https://theproxy');
++compare($x, $c, 'defaults with https proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 0,
++                        'ssl://theproxy');
++compare($x, $c, 'defaults with ssl proxy');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 65,
++                        'theproxy', 6565);
++compare($x, $c, 'port 65 proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 65,
++                        'http://theproxy', 6565);
++compare($x, $c, 'port 65 with http proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 65,
++                        'https://theproxy', 6565);
++compare($x, $c, 'port 65 with https proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65,
++                        'ssl://theproxy', 6565);
++compare($x, $c, 'port 65 with ssl proxy 6565');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 443,
++                        'theproxy', 443);
++compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 0,
++                        'ssl://theproxy', 6565);
++compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
++XML_RPC-1.4.0/tests/test_Dump.php100666      0      0        3042 10277724745  11551 new XML_RPC_Value('das ist der Titel', 'string'),
++    'startDate'=>new XML_RPC_Value(mktime(0,0,0,13,11,2004), 'dateTime.iso8601'),
++    'endDate'  =>new XML_RPC_Value(mktime(0,0,0,15,11,2004), 'dateTime.iso8601'),
++    'error'    =>'string',
++    'arkey'    => new XML_RPC_Value( array(
++        new XML_RPC_Value('simple string'),
++        new XML_RPC_Value(12345, 'int')
++        ), 'array')
++    )
++    ,'struct');
++
++XML_RPC_Dump($val);
++
++echo '==============' . "\r\n";
++$val2 = new XML_RPC_Value(44353, 'int');
++XML_RPC_Dump($val2);
++
++echo '==============' . "\r\n";
++$val3 = new XML_RPC_Value('this should be a string', 'string');
++XML_RPC_Dump($val3);
++
++echo '==============' . "\r\n";
++$val4 = new XML_RPC_Value(true, 'boolean');
++XML_RPC_Dump($val4);
++XML_RPC-1.4.0/Dump.php100666      0      0       12074 10277724745   7375 
++ * @version    CVS: $Id: Dump.php,v 1.7 2005/01/24 03:47:55 danielc Exp $
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++
++
++/**
++ * Pull in the XML_RPC class
++ */
++require_once 'XML/RPC.php';
++
++
++/**
++ * Generates the dump of the XML_RPC_Value and echoes it
++ *
++ * @param object $value  the XML_RPC_Value object to dump
++ *
++ * @return void
++ */
++function XML_RPC_Dump($value)
++{
++    $dumper = new XML_RPC_Dump();
++    echo $dumper->generateDump($value);
++}
++
++
++/**
++ * Class which generates a dump of a XML_RPC_Value object
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Christian Weiske 
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Dump
++{
++    /**
++     * The indentation array cache
++     * @var array
++     */
++    var $arIndent      = array();
++
++    /**
++     * The spaces used for indenting the XML
++     * @var string
++     */
++    var $strBaseIndent = '    ';
++
++    /**
++     * Returns the dump in XML format without printing it out
++     *
++     * @param object $value   the XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  the dump
++     */
++    function generateDump($value, $nLevel = 0)
++    {
++        if (!is_object($value) && get_class($value) != 'xml_rpc_value') {
++            require_once 'PEAR.php';
++            PEAR::raiseError('Tried to dump non-XML_RPC_Value variable' . "\r\n",
++                             0, PEAR_ERROR_PRINT);
++            if (is_object($value)) {
++                $strType = get_class($value);
++            } else {
++                $strType = gettype($value);
++            }
++            return $this->getIndent($nLevel) . 'NOT A XML_RPC_Value: '
++                   . $strType . "\r\n";
++        }
++
++        switch ($value->kindOf()) {
++        case 'struct':
++            $ret = $this->genStruct($value, $nLevel);
++            break;
++        case 'array':
++            $ret = $this->genArray($value, $nLevel);
++            break;
++        case 'scalar':
++            $ret = $this->genScalar($value->scalarval(), $nLevel);
++            break;
++        default:
++            require_once 'PEAR.php';
++            PEAR::raiseError('Illegal type "' . $value->kindOf()
++                             . '" in XML_RPC_Value' . "\r\n", 0,
++                             PEAR_ERROR_PRINT);
++        }
++
++        return $ret;
++    }
++
++    /**
++     * Returns the scalar value dump
++     *
++     * @param object $value   the scalar XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genScalar($value, $nLevel)
++    {
++        if (gettype($value) == 'object') {
++            $strClass = ' ' . get_class($value);
++        } else {
++            $strClass = '';
++        }
++        return $this->getIndent($nLevel) . gettype($value) . $strClass
++               . ' ' . $value . "\r\n";
++    }
++
++    /**
++     * Returns the dump of a struct
++     *
++     * @param object $value   the struct XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genStruct($value, $nLevel)
++    {
++        $value->structreset();
++        $strOutput = $this->getIndent($nLevel) . 'struct' . "\r\n";
++        while (list($key, $keyval) = $value->structeach()) {
++            $strOutput .= $this->getIndent($nLevel + 1) . $key . "\r\n";
++            $strOutput .= $this->generateDump($keyval, $nLevel + 2);
++        }
++        return $strOutput;
++    }
++
++    /**
++     * Returns the dump of an array
++     *
++     * @param object $value   the array XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genArray($value, $nLevel)
++    {
++        $nSize     = $value->arraysize();
++        $strOutput = $this->getIndent($nLevel) . 'array' . "\r\n";
++        for($nA = 0; $nA < $nSize; $nA++) {
++            $strOutput .= $this->getIndent($nLevel + 1) . $nA . "\r\n";
++            $strOutput .= $this->generateDump($value->arraymem($nA),
++                                              $nLevel + 2);
++        }
++        return $strOutput;
++    }
++
++    /**
++     * Returns the indent for a specific level and caches it for faster use
++     *
++     * @param int $nLevel  the level
++     *
++     * @return string  the indented string
++     */
++    function getIndent($nLevel)
++    {
++        if (!isset($this->arIndent[$nLevel])) {
++            $this->arIndent[$nLevel] = str_repeat($this->strBaseIndent, $nLevel);
++        }
++        return $this->arIndent[$nLevel];
++    }
++}
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * c-hanging-comment-ender-p: nil
++ * End:
++ */
++
++?>
++XML_RPC-1.4.0/RPC.php100666      0      0      156232 10277724745   7141 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    CVS: $Id: RPC.php,v 1.83 2005/08/14 20:25:35 danielc Exp $
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++
++
++if (!function_exists('xml_parser_create')) {
++    PEAR::loadExtension('xml');
++}
++
++/**#@+
++ * Error constants
++ */
++/**
++ * Parameter values don't match parameter types
++ */
++define('XML_RPC_ERROR_INVALID_TYPE', 101);
++/**
++ * Parameter declared to be numeric but the values are not
++ */
++define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102);
++/**
++ * Communication error
++ */
++define('XML_RPC_ERROR_CONNECTION_FAILED', 103);
++/**
++ * The array or struct has already been started
++ */
++define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
++/**
++ * Incorrect parameters submitted
++ */
++define('XML_RPC_ERROR_INCORRECT_PARAMS', 105);
++/**
++ * Programming error by developer
++ */
++define('XML_RPC_ERROR_PROGRAMMING', 106);
++/**#@-*/
++
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_I4']
++ */
++$GLOBALS['XML_RPC_I4'] = 'i4';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Int']
++ */
++$GLOBALS['XML_RPC_Int'] = 'int';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Boolean']
++ */
++$GLOBALS['XML_RPC_Boolean'] = 'boolean';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Double']
++ */
++$GLOBALS['XML_RPC_Double'] = 'double';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_String']
++ */
++$GLOBALS['XML_RPC_String'] = 'string';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_DateTime']
++ */
++$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Base64']
++ */
++$GLOBALS['XML_RPC_Base64'] = 'base64';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Array']
++ */
++$GLOBALS['XML_RPC_Array'] = 'array';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Struct']
++ */
++$GLOBALS['XML_RPC_Struct'] = 'struct';
++
++
++/**
++ * Data type meta-types
++ * @global array $GLOBALS['XML_RPC_Types']
++ */
++$GLOBALS['XML_RPC_Types'] = array(
++    $GLOBALS['XML_RPC_I4']       => 1,
++    $GLOBALS['XML_RPC_Int']      => 1,
++    $GLOBALS['XML_RPC_Boolean']  => 1,
++    $GLOBALS['XML_RPC_String']   => 1,
++    $GLOBALS['XML_RPC_Double']   => 1,
++    $GLOBALS['XML_RPC_DateTime'] => 1,
++    $GLOBALS['XML_RPC_Base64']   => 1,
++    $GLOBALS['XML_RPC_Array']    => 2,
++    $GLOBALS['XML_RPC_Struct']   => 3,
++);
++
++
++/**
++ * Error message numbers
++ * @global array $GLOBALS['XML_RPC_err']
++ */
++$GLOBALS['XML_RPC_err'] = array(
++    'unknown_method'      => 1,
++    'invalid_return'      => 2,
++    'incorrect_params'    => 3,
++    'introspect_unknown'  => 4,
++    'http_error'          => 5,
++    'not_response_object' => 6,
++    'invalid_request'     => 7,
++);
++
++/**
++ * Error message strings
++ * @global array $GLOBALS['XML_RPC_str']
++ */
++$GLOBALS['XML_RPC_str'] = array(
++    'unknown_method'      => 'Unknown method',
++    'invalid_return'      => 'Invalid return payload: enable debugging to examine incoming payload',
++    'incorrect_params'    => 'Incorrect parameters passed to method',
++    'introspect_unknown'  => 'Can\'t introspect: method unknown',
++    'http_error'          => 'Didn\'t receive 200 OK from remote server.',
++    'not_response_object' => 'The requested method didn\'t return an XML_RPC_Response object.',
++    'invalid_request'     => 'Invalid request payload',
++);
++
++
++/**
++ * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
++ * @global string $GLOBALS['XML_RPC_defencoding']
++ */
++$GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
++
++/**
++ * User error codes start at 800
++ * @global int $GLOBALS['XML_RPC_erruser']
++ */
++$GLOBALS['XML_RPC_erruser'] = 800;
++
++/**
++ * XML parse error codes start at 100
++ * @global int $GLOBALS['XML_RPC_errxml']
++ */
++$GLOBALS['XML_RPC_errxml'] = 100;
++
++
++/**
++ * Compose backslashes for escaping regexp
++ * @global string $GLOBALS['XML_RPC_backslash']
++ */
++$GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
++
++
++/**
++ * Valid parents of XML elements
++ * @global array $GLOBALS['XML_RPC_valid_parents']
++ */
++$GLOBALS['XML_RPC_valid_parents'] = array(
++    'BOOLEAN' => array('VALUE'),
++    'I4' => array('VALUE'),
++    'INT' => array('VALUE'),
++    'STRING' => array('VALUE'),
++    'DOUBLE' => array('VALUE'),
++    'DATETIME.ISO8601' => array('VALUE'),
++    'BASE64' => array('VALUE'),
++    'ARRAY' => array('VALUE'),
++    'STRUCT' => array('VALUE'),
++    'PARAM' => array('PARAMS'),
++    'METHODNAME' => array('METHODCALL'),
++    'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),
++    'MEMBER' => array('STRUCT'),
++    'NAME' => array('MEMBER'),
++    'DATA' => array('ARRAY'),
++    'FAULT' => array('METHODRESPONSE'),
++    'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
++);
++
++
++/**
++ * Stores state during parsing
++ *
++ * quick explanation of components:
++ *   + ac     = accumulates values
++ *   + qt     = decides if quotes are needed for evaluation
++ *   + cm     = denotes struct or array (comma needed)
++ *   + isf    = indicates a fault
++ *   + lv     = indicates "looking for a value": implements the logic
++ *               to allow values with no types to be strings
++ *   + params = stores parameters in method calls
++ *   + method = stores method name
++ *
++ * @global array $GLOBALS['XML_RPC_xh']
++ */
++$GLOBALS['XML_RPC_xh'] = array();
++
++
++/**
++ * Start element handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_se($parser_resource, $name, $attrs)
++{
++    global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String, $XML_RPC_valid_parents;
++    $parser = (int) $parser_resource;
++
++    // if invalid xmlrpc already detected, skip all processing
++    if ($XML_RPC_xh[$parser]['isf'] >= 2) {
++        return;
++    }
++
++    // check for correct element nesting
++    // top level element can only be of 2 types
++    if (count($XML_RPC_xh[$parser]['stack']) == 0) {
++        if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') {
++            $XML_RPC_xh[$parser]['isf'] = 2;
++            $XML_RPC_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element';
++            return;
++        }
++    } else {
++        // not top level element: see if parent is OK
++        if (!in_array($XML_RPC_xh[$parser]['stack'][0], $XML_RPC_valid_parents[$name])) {
++            $name = preg_replace('[^a-zA-Z0-9._-]', '', $name);
++            $XML_RPC_xh[$parser]['isf'] = 2;
++            $XML_RPC_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$XML_RPC_xh[$parser]['stack'][0]}";
++            return;
++        }
++    }
++
++    switch ($name) {
++    case 'STRUCT':
++        $XML_RPC_xh[$parser]['cm']++;
++
++        // turn quoting off
++        $XML_RPC_xh[$parser]['qt'] = 0;
++
++        $cur_val = array();
++        $cur_val['value'] = array();
++        $cur_val['members'] = 1;
++        array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
++        break;
++
++    case 'ARRAY':
++        $XML_RPC_xh[$parser]['cm']++;
++
++        // turn quoting off
++        $XML_RPC_xh[$parser]['qt'] = 0;
++
++        $cur_val = array();
++        $cur_val['value'] = array();
++        $cur_val['members'] = 0;
++        array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
++        break;
++
++    case 'NAME':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        break;
++
++    case 'FAULT':
++        $XML_RPC_xh[$parser]['isf'] = 1;
++        break;
++
++    case 'PARAM':
++        $XML_RPC_xh[$parser]['valuestack'] = array();
++        break;
++
++    case 'VALUE':
++        $XML_RPC_xh[$parser]['lv'] = 1;
++        $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        // look for a value: if this is still 1 by the
++        // time we reach the first data segment then the type is string
++        // by implication and we need to add in a quote
++        break;
++
++    case 'I4':
++    case 'INT':
++    case 'STRING':
++    case 'BOOLEAN':
++    case 'DOUBLE':
++    case 'DATETIME.ISO8601':
++    case 'BASE64':
++        $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
++
++        if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
++            $XML_RPC_xh[$parser]['qt'] = 1;
++
++            if ($name == 'DATETIME.ISO8601') {
++                $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
++            }
++
++        } elseif ($name == 'BASE64') {
++            $XML_RPC_xh[$parser]['qt'] = 2;
++        } else {
++            // No quoting is required here -- but
++            // at the end of the element we must check
++            // for data format errors.
++            $XML_RPC_xh[$parser]['qt'] = 0;
++        }
++        break;
++
++    case 'MEMBER':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        break;
++
++    case 'DATA':
++    case 'METHODCALL':
++    case 'METHODNAME':
++    case 'METHODRESPONSE':
++    case 'PARAMS':
++        // valid elements that add little to processing
++        break;
++    }
++
++
++    // Save current element to stack
++    array_unshift($XML_RPC_xh[$parser]['stack'], $name);
++
++    if ($name != 'VALUE') {
++        $XML_RPC_xh[$parser]['lv'] = 0;
++    }
++}
++
++/**
++ * End element handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_ee($parser_resource, $name)
++{
++    global $XML_RPC_xh, $XML_RPC_Types, $XML_RPC_String;
++    $parser = (int) $parser_resource;
++
++    if ($XML_RPC_xh[$parser]['isf'] >= 2) {
++        return;
++    }
++
++    // push this element from stack
++    // NB: if XML validates, correct opening/closing is guaranteed and
++    // we do not have to check for $name == $curr_elem.
++    // we also checked for proper nesting at start of elements...
++    $curr_elem = array_shift($XML_RPC_xh[$parser]['stack']);
++
++    switch ($name) {
++    case 'STRUCT':
++    case 'ARRAY':
++    $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
++    $XML_RPC_xh[$parser]['value'] = $cur_val['value'];
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++        $XML_RPC_xh[$parser]['cm']--;
++        break;
++
++    case 'NAME':
++    $XML_RPC_xh[$parser]['valuestack'][0]['name'] = $XML_RPC_xh[$parser]['ac'];
++        break;
++
++    case 'BOOLEAN':
++        // special case here: we translate boolean 1 or 0 into PHP
++        // constants true or false
++        if ($XML_RPC_xh[$parser]['ac'] == '1') {
++            $XML_RPC_xh[$parser]['ac'] = 'true';
++        } else {
++            $XML_RPC_xh[$parser]['ac'] = 'false';
++        }
++
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++        // Drop through intentionally.
++
++    case 'I4':
++    case 'INT':
++    case 'STRING':
++    case 'DOUBLE':
++    case 'DATETIME.ISO8601':
++    case 'BASE64':
++        if ($XML_RPC_xh[$parser]['qt'] == 1) {
++            // we use double quotes rather than single so backslashification works OK
++            $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
++        } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
++            $XML_RPC_xh[$parser]['value'] = base64_decode($XML_RPC_xh[$parser]['ac']);
++        } elseif ($name == 'BOOLEAN') {
++            $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
++        } else {
++            // we have an I4, INT or a DOUBLE
++            // we must check that only 0123456789-. are characters here
++            if (!ereg("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
++                XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
++                                         XML_RPC_ERROR_NON_NUMERIC_FOUND);
++                $XML_RPC_xh[$parser]['value'] = XML_RPC_ERROR_NON_NUMERIC_FOUND;
++            } else {
++                // it's ok, add it on
++                $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
++            }
++        }
++
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
++        break;
++
++    case 'VALUE':
++        // deal with a string value
++        if (strlen($XML_RPC_xh[$parser]['ac']) > 0 &&
++            $XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
++            $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
++        }
++
++        $temp = new XML_RPC_Value($XML_RPC_xh[$parser]['value'], $XML_RPC_xh[$parser]['vt']);
++
++        $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
++        if (is_array($cur_val)) {
++            if ($cur_val['members']==0) {
++                $cur_val['value'][] = $temp;
++            } else {
++                $XML_RPC_xh[$parser]['value'] = $temp;
++            }
++            array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
++        } else {
++            $XML_RPC_xh[$parser]['value'] = $temp;
++        }
++        break;
++
++    case 'MEMBER':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++
++        $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
++        if (is_array($cur_val)) {
++            if ($cur_val['members']==1) {
++                $cur_val['value'][$cur_val['name']] = $XML_RPC_xh[$parser]['value'];
++            }
++            array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
++        }
++        break;
++
++    case 'DATA':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        break;
++
++    case 'PARAM':
++        $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['value'];
++        break;
++
++    case 'METHODNAME':
++    case 'RPCMETHODNAME':
++        $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", '',
++                                                      $XML_RPC_xh[$parser]['ac']);
++        break;
++    }
++
++    // if it's a valid type name, set the type
++    if (isset($XML_RPC_Types[strtolower($name)])) {
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++    }
++}
++
++/**
++ * Character data handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_cd($parser_resource, $data)
++{
++    global $XML_RPC_xh, $XML_RPC_backslash;
++    $parser = (int) $parser_resource;
++
++    if ($XML_RPC_xh[$parser]['lv'] != 3) {
++        // "lookforvalue==3" means that we've found an entire value
++        // and should discard any further character data
++
++        if ($XML_RPC_xh[$parser]['lv'] == 1) {
++            // if we've found text and we're just in a  then
++            // turn quoting on, as this will be a string
++            $XML_RPC_xh[$parser]['qt'] = 1;
++            // and say we've found a value
++            $XML_RPC_xh[$parser]['lv'] = 2;
++        }
++
++        // replace characters that eval would
++        // do special things with
++        if (!isset($XML_RPC_xh[$parser]['ac'])) {
++            $XML_RPC_xh[$parser]['ac'] = '';
++        }
++        $XML_RPC_xh[$parser]['ac'] .= $data;
++    }
++}
++
++/**
++ * The common methods and properties for all of the XML_RPC classes
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Base {
++
++    /**
++     * PEAR Error handling
++     *
++     * @return object  PEAR_Error object
++     */
++    function raiseError($msg, $code)
++    {
++        include_once 'PEAR.php';
++        if (is_object(@$this)) {
++            return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
++        } else {
++            return PEAR::raiseError('XML_RPC: ' . $msg, $code);
++        }
++    }
++
++    /**
++     * Tell whether something is a PEAR_Error object
++     *
++     * @param mixed $value  the item to check
++     *
++     * @return bool  whether $value is a PEAR_Error object or not
++     *
++     * @access public
++     */
++    function isError($value)
++    {
++        return is_a($value, 'PEAR_Error');
++    }
++}
++
++/**
++ * The methods and properties for submitting XML RPC requests
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Client extends XML_RPC_Base {
++
++    /**
++     * The path and name of the RPC server script you want the request to go to
++     * @var string
++     */
++    var $path = '';
++
++    /**
++     * The name of the remote server to connect to
++     * @var string
++     */
++    var $server = '';
++
++    /**
++     * The protocol to use in contacting the remote server
++     * @var string
++     */
++    var $protocol = 'http://';
++
++    /**
++     * The port for connecting to the remote server
++     *
++     * The default is 80 for http:// connections
++     * and 443 for https:// and ssl:// connections.
++     *
++     * @var integer
++     */
++    var $port = 80;
++
++    /**
++     * A user name for accessing the RPC server
++     * @var string
++     * @see XML_RPC_Client::setCredentials()
++     */
++    var $username = '';
++
++    /**
++     * A password for accessing the RPC server
++     * @var string
++     * @see XML_RPC_Client::setCredentials()
++     */
++    var $password = '';
++
++    /**
++     * The name of the proxy server to use, if any
++     * @var string
++     */
++    var $proxy = '';
++
++    /**
++     * The protocol to use in contacting the proxy server, if any
++     * @var string
++     */
++    var $proxy_protocol = 'http://';
++
++    /**
++     * The port for connecting to the proxy server
++     *
++     * The default is 8080 for http:// connections
++     * and 443 for https:// and ssl:// connections.
++     *
++     * @var integer
++     */
++    var $proxy_port = 8080;
++
++    /**
++     * A user name for accessing the proxy server
++     * @var string
++     */
++    var $proxy_user = '';
++
++    /**
++     * A password for accessing the proxy server
++     * @var string
++     */
++    var $proxy_pass = '';
++
++    /**
++     * The error number, if any
++     * @var integer
++     */
++    var $errno = 0;
++
++    /**
++     * The error message, if any
++     * @var string
++     */
++    var $errstr = '';
++
++    /**
++     * The current debug mode (1 = on, 0 = off)
++     * @var integer
++     */
++    var $debug = 0;
++
++    /**
++     * The HTTP headers for the current request.
++     * @var string
++     */
++    var $headers = '';
++
++
++    /**
++     * Sets the object's properties
++     *
++     * @param string  $path        the path and name of the RPC server script
++     *                              you want the request to go to
++     * @param string  $server      the URL of the remote server to connect to.
++     *                              If this parameter doesn't specify a
++     *                              protocol and $port is 443, ssl:// is
++     *                              assumed.
++     * @param integer $port        a port for connecting to the remote server.
++     *                              Defaults to 80 for http:// connections and
++     *                              443 for https:// and ssl:// connections.
++     * @param string  $proxy       the URL of the proxy server to use, if any.
++     *                              If this parameter doesn't specify a
++     *                              protocol and $port is 443, ssl:// is
++     *                              assumed.
++     * @param integer $proxy_port  a port for connecting to the remote server.
++     *                              Defaults to 8080 for http:// connections and
++     *                              443 for https:// and ssl:// connections.
++     * @param string  $proxy_user  a user name for accessing the proxy server
++     * @param string  $proxy_pass  a password for accessing the proxy server
++     *
++     * @return void
++     */
++    function XML_RPC_Client($path, $server, $port = 0,
++                            $proxy = '', $proxy_port = 0,
++                            $proxy_user = '', $proxy_pass = '')
++    {
++        $this->path       = $path;
++        $this->proxy_user = $proxy_user;
++        $this->proxy_pass = $proxy_pass;
++
++        preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match);
++        if ($match[1] == '') {
++            if ($port == 443) {
++                $this->server   = $match[2];
++                $this->protocol = 'ssl://';
++                $this->port     = 443;
++            } else {
++                $this->server = $match[2];
++                if ($port) {
++                    $this->port = $port;
++                }
++            }
++        } elseif ($match[1] == 'http://') {
++            $this->server = $match[2];
++            if ($port) {
++                $this->port = $port;
++            }
++        } else {
++            $this->server   = $match[2];
++            $this->protocol = 'ssl://';
++            if ($port) {
++                $this->port = $port;
++            } else {
++                $this->port = 443;
++            }
++        }
++
++        if ($proxy) {
++            preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match);
++            if ($match[1] == '') {
++                if ($proxy_port == 443) {
++                    $this->proxy          = $match[2];
++                    $this->proxy_protocol = 'ssl://';
++                    $this->proxy_port     = 443;
++                } else {
++                    $this->proxy = $match[2];
++                    if ($proxy_port) {
++                        $this->proxy_port = $proxy_port;
++                    }
++                }
++            } elseif ($match[1] == 'http://') {
++                $this->proxy = $match[2];
++                if ($proxy_port) {
++                    $this->proxy_port = $proxy_port;
++                }
++            } else {
++                $this->proxy          = $match[2];
++                $this->proxy_protocol = 'ssl://';
++                if ($proxy_port) {
++                    $this->proxy_port = $proxy_port;
++                } else {
++                    $this->proxy_port = 443;
++                }
++            }
++        }
++    }
++
++    /**
++     * Change the current debug mode
++     *
++     * @param int $in  where 1 = on, 0 = off
++     *
++     * @return void
++     */
++    function setDebug($in)
++    {
++        if ($in) {
++            $this->debug = 1;
++        } else {
++            $this->debug = 0;
++        }
++    }
++
++    /**
++     * Set username and password properties for connecting to the RPC server
++     *
++     * @param string $u  the user name
++     * @param string $p  the password
++     *
++     * @return void
++     *
++     * @see XML_RPC_Client::$username, XML_RPC_Client::$password
++     */
++    function setCredentials($u, $p)
++    {
++        $this->username = $u;
++        $this->password = $p;
++    }
++
++    /**
++     * Transmit the RPC request via HTTP 1.0 protocol
++     *
++     * @param object $msg       the XML_RPC_Message object
++     * @param int    $timeout   how many seconds to wait for the request
++     *
++     * @return object  an XML_RPC_Response object.  0 is returned if any
++     *                  problems happen.
++     *
++     * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
++     *      XML_RPC_Client::setCredentials()
++     */
++    function send($msg, $timeout = 0)
++    {
++        if (strtolower(get_class($msg)) != 'xml_rpc_message') {
++            $this->errstr = 'send()\'s $msg parameter must be an'
++                          . ' XML_RPC_Message object.';
++            $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING);
++            return 0;
++        }
++        $msg->debug = $this->debug;
++        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
++                                        $timeout, $this->username,
++                                        $this->password);
++    }
++
++    /**
++     * Transmit the RPC request via HTTP 1.0 protocol
++     *
++     * Requests should be sent using XML_RPC_Client send() rather than
++     * calling this method directly.
++     *
++     * @param object $msg       the XML_RPC_Message object
++     * @param string $server    the server to send the request to
++     * @param int    $port      the server port send the request to
++     * @param int    $timeout   how many seconds to wait for the request
++     *                           before giving up
++     * @param string $username  a user name for accessing the RPC server
++     * @param string $password  a password for accessing the RPC server
++     *
++     * @return object  an XML_RPC_Response object.  0 is returned if any
++     *                  problems happen.
++     *
++     * @access protected
++     * @see XML_RPC_Client::send()
++     */
++    function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
++                               $username = '', $password = '')
++    {
++        /*
++         * If we're using a proxy open a socket to the proxy server
++         * instead to the xml-rpc server
++         */
++        if ($this->proxy) {
++            if ($this->proxy_protocol == 'http://') {
++                $protocol = '';
++            } else {
++                $protocol = $this->proxy_protocol;
++            }
++            if ($timeout > 0) {
++                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
++                                 $this->errno, $this->errstr, $timeout);
++            } else {
++                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
++                                 $this->errno, $this->errstr);
++            }
++        } else {
++            if ($this->protocol == 'http://') {
++                $protocol = '';
++            } else {
++                $protocol = $this->protocol;
++            }
++            if ($timeout > 0) {
++                $fp = @fsockopen($protocol . $server, $port,
++                                 $this->errno, $this->errstr, $timeout);
++            } else {
++                $fp = @fsockopen($protocol . $server, $port,
++                                 $this->errno, $this->errstr);
++            }
++        }
++
++        /*
++         * Just raising the error without returning it is strange,
++         * but keep it here for backwards compatibility.
++         */
++        if (!$fp && $this->proxy) {
++            $this->raiseError('Connection to proxy server '
++                              . $this->proxy . ':' . $this->proxy_port
++                              . ' failed. ' . $this->errstr,
++                              XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        } elseif (!$fp) {
++            $this->raiseError('Connection to RPC server '
++                              . $server . ':' . $port
++                              . ' failed. ' . $this->errstr,
++                              XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        }
++
++        if ($timeout) {
++            /*
++             * Using socket_set_timeout() because stream_set_timeout()
++             * was introduced in 4.3.0, but we need to support 4.2.0.
++             */
++            socket_set_timeout($fp, $timeout);
++        }
++
++        // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly
++        if ($username != $this->username) {
++            $this->setCredentials($username, $password);
++        }
++
++        // Only create the payload if it was not created previously
++        if (empty($msg->payload)) {
++            $msg->createPayload();
++        }
++        $this->createHeaders($msg);
++
++        $op  = $this->headers . "\r\n\r\n";
++        $op .= $msg->payload;
++
++        if (!fputs($fp, $op, strlen($op))) {
++            $this->errstr = 'Write error';
++            return 0;
++        }
++        $resp = $msg->parseResponseFile($fp);
++
++        $meta = socket_get_status($fp);
++        if ($meta['timed_out']) {
++            fclose($fp);
++            $this->errstr = 'RPC server did not send response before timeout.';
++            $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        }
++
++        fclose($fp);
++        return $resp;
++    }
++
++    /**
++     * Determines the HTTP headers and puts it in the $headers property
++     *
++     * @param object $msg       the XML_RPC_Message object
++     *
++     * @return boolean  TRUE if okay, FALSE if the message payload isn't set.
++     *
++     * @access protected
++     */
++    function createHeaders($msg)
++    {
++        if (empty($msg->payload)) {
++            return false;
++        }
++        if ($this->proxy) {
++            $this->headers = 'POST ' . $this->protocol . $this->server;
++            if ($this->proxy_port) {
++                $this->headers .= ':' . $this->port;
++            }
++        } else {
++           $this->headers = 'POST ';
++        }
++        $this->headers .= $this->path. " HTTP/1.0\r\n";
++
++        $this->headers .= "User-Agent: PEAR XML_RPC\r\n";
++        $this->headers .= 'Host: ' . $this->server . "\r\n";
++
++        if ($this->proxy && $this->proxy_user) {
++            $this->headers .= 'Proxy-Authorization: Basic '
++                     . base64_encode("$this->proxy_user:$this->proxy_pass")
++                     . "\r\n";
++        }
++
++        // thanks to Grant Rauscher  for this
++        if ($this->username) {
++            $this->headers .= 'Authorization: Basic '
++                     . base64_encode("$this->username:$this->password")
++                     . "\r\n";
++        }
++
++        $this->headers .= "Content-Type: text/xml\r\n";
++        $this->headers .= 'Content-Length: ' . strlen($msg->payload);
++        return true;
++    }
++}
++
++/**
++ * The methods and properties for interpreting responses to XML RPC requests
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Response extends XML_RPC_Base
++{
++    var $xv;
++    var $fn;
++    var $fs;
++    var $hdrs;
++
++    /**
++     * @return void
++     */
++    function XML_RPC_Response($val, $fcode = 0, $fstr = '')
++    {
++        if ($fcode != 0) {
++            $this->fn = $fcode;
++            $this->fs = htmlspecialchars($fstr);
++        } else {
++            $this->xv = $val;
++        }
++    }
++
++    /**
++     * @return int  the error code
++     */
++    function faultCode()
++    {
++        if (isset($this->fn)) {
++            return $this->fn;
++        } else {
++            return 0;
++        }
++    }
++
++    /**
++     * @return string  the error string
++     */
++    function faultString()
++    {
++        return $this->fs;
++    }
++
++    /**
++     * @return mixed  the value
++     */
++    function value()
++    {
++        return $this->xv;
++    }
++
++    /**
++     * @return string  the error message in XML format
++     */
++    function serialize()
++    {
++        $rs = "\n";
++        if ($this->fn) {
++            $rs .= "
++  
++    
++      
++        faultCode
++        " . $this->fn . "
++      
++      
++        faultString
++        " . $this->fs . "
++      
++    
++  
++";
++        } else {
++            $rs .= "\n\n" . $this->xv->serialize() .
++        "\n";
++        }
++        $rs .= "\n";
++        return $rs;
++    }
++}
++
++/**
++ * The methods and properties for composing XML RPC messages
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Message extends XML_RPC_Base
++{
++    /**
++     * The current debug mode (1 = on, 0 = off)
++     * @var integer
++     */
++    var $debug = 0;
++
++    /**
++     * The encoding to be used for outgoing messages
++     *
++     * Defaults to the value of $GLOBALS['XML_RPC_defencoding']
++     *
++     * @var string
++     * @see XML_RPC_Message::setSendEncoding(),
++     *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
++     */
++    var $send_encoding = '';
++
++    /**
++     * The method presently being evaluated
++     * @var string
++     */
++    var $methodname = '';
++
++    /**
++     * @var array
++     */
++    var $params = array();
++
++    /**
++     * The XML message being generated
++     * @var string
++     */
++    var $payload = '';
++
++    /**
++     * @return void
++     */
++    function XML_RPC_Message($meth, $pars = 0)
++    {
++        $this->methodname = $meth;
++        if (is_array($pars) && sizeof($pars) > 0) {
++            for ($i = 0; $i < sizeof($pars); $i++) {
++                $this->addParam($pars[$i]);
++            }
++        }
++    }
++
++    /**
++     * Produces the XML declaration including the encoding attribute
++     *
++     * The encoding is determined by this class' $send_encoding
++     * property.  If the $send_encoding property is not set, use
++     * $GLOBALS['XML_RPC_defencoding'].
++     *
++     * @return string  the XML declaration and  element
++     *
++     * @see XML_RPC_Message::setSendEncoding(),
++     *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
++     */
++    function xml_header()
++    {
++        global $XML_RPC_defencoding;
++        if (!$this->send_encoding) {
++            $this->send_encoding = $XML_RPC_defencoding;
++        }
++        return 'send_encoding . '"?>'
++               . "\n\n";
++    }
++
++    /**
++     * @return string  the closing  tag
++     */
++    function xml_footer()
++    {
++        return "\n";
++    }
++
++    /**
++     * @return void
++     *
++     * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
++     */
++    function createPayload()
++    {
++        $this->payload = $this->xml_header();
++        $this->payload .= '' . $this->methodname . "\n";
++        $this->payload .= "\n";
++        for ($i = 0; $i < sizeof($this->params); $i++) {
++            $p = $this->params[$i];
++            $this->payload .= "\n" . $p->serialize() . "\n";
++        }
++        $this->payload .= "\n";
++        $this->payload .= $this->xml_footer();
++        $this->payload = ereg_replace("[\r\n]+", "\r\n", $this->payload);
++    }
++
++    /**
++     * @return string  the name of the method
++     */
++    function method($meth = '')
++    {
++        if ($meth != '') {
++            $this->methodname = $meth;
++        }
++        return $this->methodname;
++    }
++
++    /**
++     * @return string  the payload
++     */
++    function serialize()
++    {
++        $this->createPayload();
++        return $this->payload;
++    }
++
++    /**
++     * @return void
++     */
++    function addParam($par)
++    {
++        $this->params[] = $par;
++    }
++
++    /**
++     * Obtains an XML_RPC_Value object for the given parameter
++     *
++     * @param int $i  the index number of the parameter to obtain
++     *
++     * @return object  the XML_RPC_Value object.
++     *                  If the parameter doesn't exist, an XML_RPC_Response object.
++     *
++     * @since Returns XML_RPC_Response object on error since Release 1.3.0
++     */
++    function getParam($i)
++    {
++        global $XML_RPC_err, $XML_RPC_str;
++
++        if (isset($this->params[$i])) {
++            return $this->params[$i];
++        } else {
++            $this->raiseError('The submitted request did not contain this parameter',
++                              XML_RPC_ERROR_INCORRECT_PARAMS);
++            return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
++                                        $XML_RPC_str['incorrect_params']);
++        }
++    }
++
++    /**
++     * @return int  the number of parameters
++     */
++    function getNumParams()
++    {
++        return sizeof($this->params);
++    }
++
++    /**
++     * Sets the XML declaration's encoding attribute
++     *
++     * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
++     *
++     * @return void
++     *
++     * @see XML_RPC_Message::$send_encoding, XML_RPC_Message::xml_header()
++     * @since Method available since Release 1.2.0
++     */
++    function setSendEncoding($type)
++    {
++        $this->send_encoding = $type;
++    }
++
++    /**
++     * Determine the XML's encoding via the encoding attribute
++     * in the XML declaration
++     *
++     * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
++     * or US-ASCII, $XML_RPC_defencoding will be returned.
++     *
++     * @param string $data  the XML that will be parsed
++     *
++     * @return string  the encoding to be used
++     *
++     * @link   http://php.net/xml_parser_create
++     * @since  Method available since Release 1.2.0
++     */
++    function getEncoding($data)
++    {
++        global $XML_RPC_defencoding;
++
++        if (preg_match('/<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]/i',
++                       $data, $match))
++        {
++            $match[1] = trim(strtoupper($match[1]));
++            switch ($match[1]) {
++                case 'ISO-8859-1':
++                case 'UTF-8':
++                case 'US-ASCII':
++                    return $match[1];
++                    break;
++
++                default:
++                    return $XML_RPC_defencoding;
++            }
++        } else {
++            return $XML_RPC_defencoding;
++        }
++    }
++
++    /**
++     * @return object  a new XML_RPC_Response object
++     */
++    function parseResponseFile($fp)
++    {
++        $ipd = '';
++        while ($data = @fread($fp, 8192)) {
++            $ipd .= $data;
++        }
++        return $this->parseResponse($ipd);
++    }
++
++    /**
++     * @return object  a new XML_RPC_Response object
++     */
++    function parseResponse($data = '')
++    {
++        global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
++
++        $encoding = $this->getEncoding($data);
++        $parser_resource = xml_parser_create($encoding);
++        $parser = (int) $parser_resource;
++
++        $XML_RPC_xh = array();
++        $XML_RPC_xh[$parser] = array();
++
++        $XML_RPC_xh[$parser]['cm'] = 0;
++        $XML_RPC_xh[$parser]['isf'] = 0;
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = '';
++        $XML_RPC_xh[$parser]['stack'] = array();
++        $XML_RPC_xh[$parser]['valuestack'] = array();
++
++        xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
++        xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
++        xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
++
++        $hdrfnd = 0;
++        if ($this->debug) {
++            print "\n
---GOT---\n";
++            print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
++            print "\n---END---
\n"; ++ } ++ ++ // See if response is a 200 or a 100 then a 200, else raise error. ++ // But only do this if we're using the HTTP protocol. ++ if (ereg('^HTTP', $data) && ++ !ereg('^HTTP/[0-9\.]+ 200 ', $data) && ++ !preg_match('@^HTTP/[0-9\.]+ 10[0-9]([A-Za-z ]+)?[\r\n]+HTTP/[0-9\.]+ 200@', $data)) ++ { ++ $errstr = substr($data, 0, strpos($data, "\n") - 1); ++ error_log('HTTP error, got response: ' . $errstr); ++ $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], ++ $XML_RPC_str['http_error'] . ' (' . ++ $errstr . ')'); ++ xml_parser_free($parser_resource); ++ return $r; ++ } ++ ++ // gotta get rid of headers here ++ if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) { ++ $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos); ++ $data = substr($data, $brpos + 4); ++ $hdrfnd = 1; ++ } ++ ++ /* ++ * be tolerant of junk after methodResponse ++ * (e.g. javascript automatically inserted by free hosts) ++ * thanks to Luca Mariano ++ */ ++ $data = substr($data, 0, strpos($data, "") + 17); ++ ++ if (!xml_parse($parser_resource, $data, sizeof($data))) { ++ // thanks to Peter Kocks ++ if (xml_get_current_line_number($parser_resource) == 1) { ++ $errstr = 'XML error at line 1, check URL'; ++ } else { ++ $errstr = sprintf('XML error: %s at line %d', ++ xml_error_string(xml_get_error_code($parser_resource)), ++ xml_get_current_line_number($parser_resource)); ++ } ++ error_log($errstr); ++ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], ++ $XML_RPC_str['invalid_return']); ++ xml_parser_free($parser_resource); ++ return $r; ++ } ++ ++ xml_parser_free($parser_resource); ++ ++ if ($this->debug) { ++ print "\n
---PARSED---\n";
++            var_dump($XML_RPC_xh[$parser]['value']);
++            print "---END---
\n"; ++ } ++ ++ if ($XML_RPC_xh[$parser]['isf'] > 1) { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], ++ $XML_RPC_str['invalid_return'].' '.$XML_RPC_xh[$parser]['isf_reason']); ++ } elseif (!is_object($XML_RPC_xh[$parser]['value'])) { ++ // then something odd has happened ++ // and it's time to generate a client side error ++ // indicating something odd went on ++ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], ++ $XML_RPC_str['invalid_return']); ++ } else { ++ $v = $XML_RPC_xh[$parser]['value']; ++ $allOK=1; ++ if ($XML_RPC_xh[$parser]['isf']) { ++ $f = $v->structmem('faultCode'); ++ $fs = $v->structmem('faultString'); ++ $r = new XML_RPC_Response($v, $f->scalarval(), ++ $fs->scalarval()); ++ } else { ++ $r = new XML_RPC_Response($v); ++ } ++ } ++ $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]); ++ return $r; ++ } ++} ++ ++/** ++ * The methods and properties that represent data in XML RPC format ++ * ++ * @category Web Services ++ * @package XML_RPC ++ * @author Edd Dumbill ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version Release: 1.4.0 ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++class XML_RPC_Value extends XML_RPC_Base ++{ ++ var $me = array(); ++ var $mytype = 0; ++ ++ /** ++ * @return void ++ */ ++ function XML_RPC_Value($val = -1, $type = '') ++ { ++ global $XML_RPC_Types; ++ $this->me = array(); ++ $this->mytype = 0; ++ if ($val != -1 || $type != '') { ++ if ($type == '') { ++ $type = 'string'; ++ } ++ if (!array_key_exists($type, $XML_RPC_Types)) { ++ // XXX ++ // need some way to report this error ++ } elseif ($XML_RPC_Types[$type] == 1) { ++ $this->addScalar($val, $type); ++ } elseif ($XML_RPC_Types[$type] == 2) { ++ $this->addArray($val); ++ } elseif ($XML_RPC_Types[$type] == 3) { ++ $this->addStruct($val); ++ } ++ } ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addScalar($val, $type = 'string') ++ { ++ global $XML_RPC_Types, $XML_RPC_Boolean; ++ ++ if ($this->mytype == 1) { ++ $this->raiseError('Scalar can have only one value', ++ XML_RPC_ERROR_INVALID_TYPE); ++ return 0; ++ } ++ $typeof = $XML_RPC_Types[$type]; ++ if ($typeof != 1) { ++ $this->raiseError("Not a scalar type (${typeof})", ++ XML_RPC_ERROR_INVALID_TYPE); ++ return 0; ++ } ++ ++ if ($type == $XML_RPC_Boolean) { ++ if (strcasecmp($val, 'true') == 0 ++ || $val == 1 ++ || ($val == true && strcasecmp($val, 'false'))) ++ { ++ $val = 1; ++ } else { ++ $val = 0; ++ } ++ } ++ ++ if ($this->mytype == 2) { ++ // we're adding to an array here ++ $ar = $this->me['array']; ++ $ar[] = new XML_RPC_Value($val, $type); ++ $this->me['array'] = $ar; ++ } else { ++ // a scalar, so set the value and remember we're scalar ++ $this->me[$type] = $val; ++ $this->mytype = $typeof; ++ } ++ return 1; ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addArray($vals) ++ { ++ global $XML_RPC_Types; ++ if ($this->mytype != 0) { ++ $this->raiseError( ++ 'Already initialized as a [' . $this->kindOf() . ']', ++ XML_RPC_ERROR_ALREADY_INITIALIZED); ++ return 0; ++ } ++ $this->mytype = $XML_RPC_Types['array']; ++ $this->me['array'] = $vals; ++ return 1; ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addStruct($vals) ++ { ++ global $XML_RPC_Types; ++ if ($this->mytype != 0) { ++ $this->raiseError( ++ 'Already initialized as a [' . $this->kindOf() . ']', ++ XML_RPC_ERROR_ALREADY_INITIALIZED); ++ return 0; ++ } ++ $this->mytype = $XML_RPC_Types['struct']; ++ $this->me['struct'] = $vals; ++ return 1; ++ } ++ ++ /** ++ * @return void ++ */ ++ function dump($ar) ++ { ++ reset($ar); ++ foreach ($ar as $key => $val) { ++ echo "$key => $val
"; ++ if ($key == 'array') { ++ foreach ($val as $key2 => $val2) { ++ echo "-- $key2 => $val2
"; ++ } ++ } ++ } ++ } ++ ++ /** ++ * @return string the data type of the current value ++ */ ++ function kindOf() ++ { ++ switch ($this->mytype) { ++ case 3: ++ return 'struct'; ++ ++ case 2: ++ return 'array'; ++ ++ case 1: ++ return 'scalar'; ++ ++ default: ++ return 'undef'; ++ } ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serializedata($typ, $val) ++ { ++ $rs = ''; ++ global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean; ++ if (!array_key_exists($typ, $XML_RPC_Types)) { ++ // XXX ++ // need some way to report this error ++ return; ++ } ++ switch ($XML_RPC_Types[$typ]) { ++ case 3: ++ // struct ++ $rs .= "\n"; ++ reset($val); ++ foreach ($val as $key2 => $val2) { ++ $rs .= "${key2}\n"; ++ $rs .= $this->serializeval($val2); ++ $rs .= "\n"; ++ } ++ $rs .= ''; ++ break; ++ ++ case 2: ++ // array ++ $rs .= "\n\n"; ++ for ($i = 0; $i < sizeof($val); $i++) { ++ $rs .= $this->serializeval($val[$i]); ++ } ++ $rs .= "\n"; ++ break; ++ ++ case 1: ++ switch ($typ) { ++ case $XML_RPC_Base64: ++ $rs .= "<${typ}>" . base64_encode($val) . ""; ++ break; ++ case $XML_RPC_Boolean: ++ $rs .= "<${typ}>" . ($val ? '1' : '0') . ""; ++ break; ++ case $XML_RPC_String: ++ $rs .= "<${typ}>" . htmlspecialchars($val). ""; ++ break; ++ default: ++ $rs .= "<${typ}>${val}"; ++ } ++ } ++ return $rs; ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serialize() ++ { ++ return $this->serializeval($this); ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serializeval($o) ++ { ++ if (!is_object($o) || empty($o->me) || !is_array($o->me)) { ++ return ''; ++ } ++ $ar = $o->me; ++ reset($ar); ++ list($typ, $val) = each($ar); ++ return '' . $this->serializedata($typ, $val) . "\n"; ++ } ++ ++ /** ++ * @return mixed the contents of the element requested ++ */ ++ function structmem($m) ++ { ++ return $this->me['struct'][$m]; ++ } ++ ++ /** ++ * @return void ++ */ ++ function structreset() ++ { ++ reset($this->me['struct']); ++ } ++ ++ /** ++ * @return the key/value pair of the struct's current element ++ */ ++ function structeach() ++ { ++ return each($this->me['struct']); ++ } ++ ++ /** ++ * @return mixed the current value ++ */ ++ function getval() ++ { ++ // UNSTABLE ++ global $XML_RPC_BOOLEAN, $XML_RPC_Base64; ++ ++ reset($this->me); ++ $b = current($this->me); ++ ++ // contributed by I Sofer, 2001-03-24 ++ // add support for nested arrays to scalarval ++ // i've created a new method here, so as to ++ // preserve back compatibility ++ ++ if (is_array($b)) { ++ foreach ($b as $id => $cont) { ++ $b[$id] = $cont->scalarval(); ++ } ++ } ++ ++ // add support for structures directly encoding php objects ++ if (is_object($b)) { ++ $t = get_object_vars($b); ++ foreach ($t as $id => $cont) { ++ $t[$id] = $cont->scalarval(); ++ } ++ foreach ($t as $id => $cont) { ++ $b->$id = $cont; ++ } ++ } ++ ++ // end contrib ++ return $b; ++ } ++ ++ /** ++ * @return mixed ++ */ ++ function scalarval() ++ { ++ global $XML_RPC_Boolean, $XML_RPC_Base64; ++ reset($this->me); ++ return current($this->me); ++ } ++ ++ /** ++ * @return string ++ */ ++ function scalartyp() ++ { ++ global $XML_RPC_I4, $XML_RPC_Int; ++ reset($this->me); ++ $a = key($this->me); ++ if ($a == $XML_RPC_I4) { ++ $a = $XML_RPC_Int; ++ } ++ return $a; ++ } ++ ++ /** ++ * @return mixed the struct's current element ++ */ ++ function arraymem($m) ++ { ++ return $this->me['array'][$m]; ++ } ++ ++ /** ++ * @return int the number of elements in the array ++ */ ++ function arraysize() ++ { ++ reset($this->me); ++ list($a, $b) = each($this->me); ++ return sizeof($b); ++ } ++ ++ /** ++ * Determines if the item submitted is an XML_RPC_Value object ++ * ++ * @param mixed $val the variable to be evaluated ++ * ++ * @return bool TRUE if the item is an XML_RPC_Value object ++ * ++ * @static ++ * @since Method available since Release 1.3.0 ++ */ ++ function isValue($val) ++ { ++ return (strtolower(get_class($val)) == 'xml_rpc_value'); ++ } ++} ++ ++/** ++ * Return an ISO8601 encoded string ++ * ++ * While timezones ought to be supported, the XML-RPC spec says: ++ * ++ * "Don't assume a timezone. It should be specified by the server in its ++ * documentation what assumptions it makes about timezones." ++ * ++ * This routine always assumes localtime unless $utc is set to 1, in which ++ * case UTC is assumed and an adjustment for locale is made when encoding. ++ * ++ * @return string the formatted date ++ */ ++function XML_RPC_iso8601_encode($timet, $utc = 0) ++{ ++ if (!$utc) { ++ $t = strftime('%Y%m%dT%H:%M:%S', $timet); ++ } else { ++ if (function_exists('gmstrftime')) { ++ // gmstrftime doesn't exist in some versions ++ // of PHP ++ $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); ++ } else { ++ $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); ++ } ++ } ++ return $t; ++} ++ ++/** ++ * Convert a datetime string into a Unix timestamp ++ * ++ * While timezones ought to be supported, the XML-RPC spec says: ++ * ++ * "Don't assume a timezone. It should be specified by the server in its ++ * documentation what assumptions it makes about timezones." ++ * ++ * This routine always assumes localtime unless $utc is set to 1, in which ++ * case UTC is assumed and an adjustment for locale is made when encoding. ++ * ++ * @return int the unix timestamp of the date submitted ++ */ ++function XML_RPC_iso8601_decode($idate, $utc = 0) ++{ ++ $t = 0; ++ if (ereg('([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})', $idate, $regs)) { ++ if ($utc) { ++ $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); ++ } else { ++ $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); ++ } ++ } ++ return $t; ++} ++ ++/** ++ * Converts an XML_RPC_Value object into native PHP types ++ * ++ * @param object $XML_RPC_val the XML_RPC_Value object to decode ++ * ++ * @return mixed the PHP values ++ */ ++function XML_RPC_decode($XML_RPC_val) ++{ ++ $kind = $XML_RPC_val->kindOf(); ++ ++ if ($kind == 'scalar') { ++ return $XML_RPC_val->scalarval(); ++ ++ } elseif ($kind == 'array') { ++ $size = $XML_RPC_val->arraysize(); ++ $arr = array(); ++ for ($i = 0; $i < $size; $i++) { ++ $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i)); ++ } ++ return $arr; ++ ++ } elseif ($kind == 'struct') { ++ $XML_RPC_val->structreset(); ++ $arr = array(); ++ while (list($key, $value) = $XML_RPC_val->structeach()) { ++ $arr[$key] = XML_RPC_decode($value); ++ } ++ return $arr; ++ } ++} ++ ++/** ++ * Converts native PHP types into an XML_RPC_Value object ++ * ++ * @param mixed $php_val the PHP value or variable you want encoded ++ * ++ * @return object the XML_RPC_Value object ++ */ ++function XML_RPC_encode($php_val) ++{ ++ global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double, $XML_RPC_String, ++ $XML_RPC_Array, $XML_RPC_Struct; ++ ++ $type = gettype($php_val); ++ $XML_RPC_val = new XML_RPC_Value; ++ ++ switch ($type) { ++ case 'array': ++ if (empty($php_val)) { ++ $XML_RPC_val->addArray($php_val); ++ break; ++ } ++ $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); ++ if (empty($tmp)) { ++ $arr = array(); ++ foreach ($php_val as $k => $v) { ++ $arr[$k] = XML_RPC_encode($v); ++ } ++ $XML_RPC_val->addArray($arr); ++ break; ++ } ++ // fall though if it's not an enumerated array ++ ++ case 'object': ++ $arr = array(); ++ foreach ($php_val as $k => $v) { ++ $arr[$k] = XML_RPC_encode($v); ++ } ++ $XML_RPC_val->addStruct($arr); ++ break; ++ ++ case 'integer': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Int); ++ break; ++ ++ case 'double': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Double); ++ break; ++ ++ case 'string': ++ case 'NULL': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_String); ++ break; ++ ++ case 'boolean': ++ // Add support for encoding/decoding of booleans, since they ++ // are supported in PHP ++ // by ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean); ++ break; ++ ++ case 'unknown type': ++ default: ++ $XML_RPC_val = false; ++ } ++ return $XML_RPC_val; ++} ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * c-hanging-comment-ender-p: nil ++ * End: ++ */ ++ ++?> ++XML_RPC-1.4.0/Server.php100666 0 0 51010 10277724745 7727 ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version CVS: $Id: Server.php,v 1.29 2005/08/14 20:25:35 danielc Exp $ ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++ ++ ++/** ++ * Pull in the XML_RPC class ++ */ ++require_once 'XML/RPC.php'; ++ ++ ++/** ++ * signature for system.listMethods: return = array, ++ * parameters = a string or nothing ++ * @global array $GLOBALS['XML_RPC_Server_listMethods_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_listMethods_sig'] = array( ++ array($GLOBALS['XML_RPC_Array'], ++ $GLOBALS['XML_RPC_String'] ++ ), ++ array($GLOBALS['XML_RPC_Array']) ++); ++ ++/** ++ * docstring for system.listMethods ++ * @global string $GLOBALS['XML_RPC_Server_listMethods_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_listMethods_doc'] = 'This method lists all the' ++ . ' methods that the XML-RPC server knows how to dispatch'; ++ ++/** ++ * signature for system.methodSignature: return = array, ++ * parameters = string ++ * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_methodSignature_sig'] = array( ++ array($GLOBALS['XML_RPC_Array'], ++ $GLOBALS['XML_RPC_String'] ++ ) ++); ++ ++/** ++ * docstring for system.methodSignature ++ * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_methodSignature_doc'] = 'Returns an array of known' ++ . ' signatures (an array of arrays) for the method name passed. If' ++ . ' no signatures are known, returns a none-array (test for type !=' ++ . ' array to detect missing signature)'; ++ ++/** ++ * signature for system.methodHelp: return = string, ++ * parameters = string ++ * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_methodHelp_sig'] = array( ++ array($GLOBALS['XML_RPC_String'], ++ $GLOBALS['XML_RPC_String'] ++ ) ++); ++ ++/** ++ * docstring for methodHelp ++ * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_methodHelp_doc'] = 'Returns help text if defined' ++ . ' for the method passed, otherwise returns an empty string'; ++ ++/** ++ * dispatch map for the automatically declared XML-RPC methods. ++ * @global array $GLOBALS['XML_RPC_Server_dmap'] ++ */ ++$GLOBALS['XML_RPC_Server_dmap'] = array( ++ 'system.listMethods' => array( ++ 'function' => 'XML_RPC_Server_listMethods', ++ 'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc'] ++ ), ++ 'system.methodHelp' => array( ++ 'function' => 'XML_RPC_Server_methodHelp', ++ 'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc'] ++ ), ++ 'system.methodSignature' => array( ++ 'function' => 'XML_RPC_Server_methodSignature', ++ 'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc'] ++ ) ++); ++ ++/** ++ * @global string $GLOBALS['XML_RPC_Server_debuginfo'] ++ */ ++$GLOBALS['XML_RPC_Server_debuginfo'] = ''; ++ ++ ++/** ++ * Lists all the methods that the XML-RPC server knows how to dispatch ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_listMethods($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $v = new XML_RPC_Value(); ++ $outAr = array(); ++ foreach ($server->dmap as $key => $val) { ++ $outAr[] = new XML_RPC_Value($key, 'string'); ++ } ++ foreach ($XML_RPC_Server_dmap as $key => $val) { ++ $outAr[] = new XML_RPC_Value($key, 'string'); ++ } ++ $v->addArray($outAr); ++ return new XML_RPC_Response($v); ++} ++ ++/** ++ * Returns an array of known signatures (an array of arrays) ++ * for the given method ++ * ++ * If no signatures are known, returns a none-array ++ * (test for type != array to detect missing signature) ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_methodSignature($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $methName = $m->getParam(0); ++ $methName = $methName->scalarval(); ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $server->dmap; ++ $sysCall = 0; ++ } ++ // print "\n"; ++ if (isset($dmap[$methName])) { ++ if ($dmap[$methName]['signature']) { ++ $sigs = array(); ++ $thesigs = $dmap[$methName]['signature']; ++ for ($i = 0; $i < sizeof($thesigs); $i++) { ++ $cursig = array(); ++ $inSig = $thesigs[$i]; ++ for ($j = 0; $j < sizeof($inSig); $j++) { ++ $cursig[] = new XML_RPC_Value($inSig[$j], 'string'); ++ } ++ $sigs[] = new XML_RPC_Value($cursig, 'array'); ++ } ++ $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array')); ++ } else { ++ $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string')); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], ++ $XML_RPC_str['introspect_unknown']); ++ } ++ return $r; ++} ++ ++/** ++ * Returns help text if defined for the method passed, otherwise returns ++ * an empty string ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_methodHelp($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $methName = $m->getParam(0); ++ $methName = $methName->scalarval(); ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $server->dmap; ++ $sysCall = 0; ++ } ++ ++ if (isset($dmap[$methName])) { ++ if ($dmap[$methName]['docstring']) { ++ $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']), ++ 'string'); ++ } else { ++ $r = new XML_RPC_Response(new XML_RPC_Value('', 'string')); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], ++ $XML_RPC_str['introspect_unknown']); ++ } ++ return $r; ++} ++ ++/** ++ * @return void ++ */ ++function XML_RPC_Server_debugmsg($m) ++{ ++ global $XML_RPC_Server_debuginfo; ++ $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n"; ++} ++ ++ ++/** ++ * A server for receiving and replying to XML RPC requests ++ * ++ * ++ * $server = new XML_RPC_Server( ++ * array( ++ * 'isan8' => ++ * array( ++ * 'function' => 'is_8', ++ * 'signature' => ++ * array( ++ * array('boolean', 'int'), ++ * array('boolean', 'int', 'boolean'), ++ * array('boolean', 'string'), ++ * array('boolean', 'string', 'boolean'), ++ * ), ++ * 'docstring' => 'Is the value an 8?' ++ * ), ++ * ), ++ * 1, ++ * 0 ++ * ); ++ * ++ * ++ * @category Web Services ++ * @package XML_RPC ++ * @author Edd Dumbill ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version Release: 1.4.0 ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++class XML_RPC_Server ++{ ++ /** ++ * The dispatch map, listing the methods this server provides. ++ * @var array ++ */ ++ var $dmap = array(); ++ ++ /** ++ * The present response's encoding ++ * @var string ++ * @see XML_RPC_Message::getEncoding() ++ */ ++ var $encoding = ''; ++ ++ /** ++ * Debug mode (0 = off, 1 = on) ++ * @var integer ++ */ ++ var $debug = 0; ++ ++ /** ++ * The response's HTTP headers ++ * @var string ++ */ ++ var $server_headers = ''; ++ ++ /** ++ * The response's XML payload ++ * @var string ++ */ ++ var $server_payload = ''; ++ ++ ++ /** ++ * Constructor for the XML_RPC_Server class ++ * ++ * @param array $dispMap the dispatch map. An associative array ++ * explaining each function. The keys of the main ++ * array are the procedure names used by the ++ * clients. The value is another associative array ++ * that contains up to three elements: ++ * + The 'function' element's value is the name ++ * of the function or method that gets called. ++ * To define a class' method: 'class::method'. ++ * + The 'signature' element (optional) is an ++ * array describing the return values and ++ * parameters ++ * + The 'docstring' element (optional) is a ++ * string describing what the method does ++ * @param int $serviceNow should the HTTP response be sent now? ++ * (1 = yes, 0 = no) ++ * @param int $debug should debug output be displayed? ++ * (1 = yes, 0 = no) ++ * ++ * @return void ++ */ ++ function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) ++ { ++ global $HTTP_RAW_POST_DATA; ++ ++ if ($debug) { ++ $this->debug = 1; ++ } else { ++ $this->debug = 0; ++ } ++ ++ $this->dmap = $dispMap; ++ ++ if ($serviceNow) { ++ $this->service(); ++ } else { ++ $this->createServerPayload(); ++ $this->createServerHeaders(); ++ } ++ } ++ ++ /** ++ * @return string the debug information if debug debug mode is on ++ */ ++ function serializeDebug() ++ { ++ global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA; ++ ++ if ($this->debug) { ++ XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n" ++ . $HTTP_RAW_POST_DATA ++ . "\n" . '^^^ END POST DATA ^^^'); ++ } ++ ++ if ($XML_RPC_Server_debuginfo != '') { ++ return "\n"; ++ } else { ++ return ''; ++ } ++ } ++ ++ /** ++ * Sends the response ++ * ++ * The encoding and content-type are determined by ++ * XML_RPC_Message::getEncoding() ++ * ++ * @return void ++ * ++ * @uses XML_RPC_Server::createServerPayload(), ++ * XML_RPC_Server::createServerHeaders() ++ */ ++ function service() ++ { ++ if (!$this->server_payload) { ++ $this->createServerPayload(); ++ } ++ if (!$this->server_headers) { ++ $this->createServerHeaders(); ++ } ++ header($this->server_headers); ++ print $this->server_payload; ++ } ++ ++ /** ++ * Generates the payload and puts it in the $server_payload property ++ * ++ * @return void ++ * ++ * @uses XML_RPC_Server::parseRequest(), XML_RPC_Server::$encoding, ++ * XML_RPC_Response::serialize(), XML_RPC_Server::serializeDebug() ++ */ ++ function createServerPayload() ++ { ++ $r = $this->parseRequest(); ++ $this->server_payload = 'encoding . '"?>' . "\n" ++ . $this->serializeDebug() ++ . $r->serialize(); ++ } ++ ++ /** ++ * Determines the HTTP headers and puts them in the $server_headers ++ * property ++ * ++ * @return boolean TRUE if okay, FALSE if $server_payload isn't set. ++ * ++ * @uses XML_RPC_Server::createServerPayload(), ++ * XML_RPC_Server::$server_headers ++ */ ++ function createServerHeaders() ++ { ++ if (!$this->server_payload) { ++ return false; ++ } ++ $this->server_headers = 'Content-Length: ' ++ . strlen($this->server_payload) . "\r\n" ++ . 'Content-Type: text/xml;' ++ . ' charset=' . $this->encoding; ++ return true; ++ } ++ ++ /** ++ * @return array ++ */ ++ function verifySignature($in, $sig) ++ { ++ for ($i = 0; $i < sizeof($sig); $i++) { ++ // check each possible signature in turn ++ $cursig = $sig[$i]; ++ if (sizeof($cursig) == $in->getNumParams() + 1) { ++ $itsOK = 1; ++ for ($n = 0; $n < $in->getNumParams(); $n++) { ++ $p = $in->getParam($n); ++ // print "\n"; ++ if ($p->kindOf() == 'scalar') { ++ $pt = $p->scalartyp(); ++ } else { ++ $pt = $p->kindOf(); ++ } ++ // $n+1 as first type of sig is return type ++ if ($pt != $cursig[$n+1]) { ++ $itsOK = 0; ++ $pno = $n+1; ++ $wanted = $cursig[$n+1]; ++ $got = $pt; ++ break; ++ } ++ } ++ if ($itsOK) { ++ return array(1); ++ } ++ } ++ } ++ if (isset($wanted)) { ++ return array(0, "Wanted ${wanted}, got ${got} at param ${pno}"); ++ } else { ++ $allowed = array(); ++ foreach ($sig as $val) { ++ end($val); ++ $allowed[] = key($val); ++ } ++ $allowed = array_unique($allowed); ++ $last = count($allowed) - 1; ++ if ($last > 0) { ++ $allowed[$last] = 'or ' . $allowed[$last]; ++ } ++ return array(0, ++ 'Signature permits ' . implode(', ', $allowed) ++ . ' parameters but the request had ' ++ . $in->getNumParams()); ++ } ++ } ++ ++ /** ++ * @return object a new XML_RPC_Response object ++ * ++ * @uses XML_RPC_Message::getEncoding(), XML_RPC_Server::$encoding ++ */ ++ function parseRequest($data = '') ++ { ++ global $XML_RPC_xh, $HTTP_RAW_POST_DATA, ++ $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml, ++ $XML_RPC_defencoding, $XML_RPC_Server_dmap; ++ ++ if ($data == '') { ++ $data = $HTTP_RAW_POST_DATA; ++ } ++ ++ $this->encoding = XML_RPC_Message::getEncoding($data); ++ $parser_resource = xml_parser_create($this->encoding); ++ $parser = (int) $parser_resource; ++ ++ $XML_RPC_xh[$parser] = array(); ++ $XML_RPC_xh[$parser]['cm'] = 0; ++ $XML_RPC_xh[$parser]['isf'] = 0; ++ $XML_RPC_xh[$parser]['params'] = array(); ++ $XML_RPC_xh[$parser]['method'] = ''; ++ $XML_RPC_xh[$parser]['stack'] = array(); ++ $XML_RPC_xh[$parser]['valuestack'] = array(); ++ ++ $plist = ''; ++ ++ // decompose incoming XML into request structure ++ ++ xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true); ++ xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee'); ++ xml_set_character_data_handler($parser_resource, 'XML_RPC_cd'); ++ if (!xml_parse($parser_resource, $data, 1)) { ++ // return XML error as a faultCode ++ $r = new XML_RPC_Response(0, ++ $XML_RPC_errxml+xml_get_error_code($parser_resource), ++ sprintf('XML error: %s at line %d', ++ xml_error_string(xml_get_error_code($parser_resource)), ++ xml_get_current_line_number($parser_resource))); ++ xml_parser_free($parser_resource); ++ } elseif ($XML_RPC_xh[$parser]['isf']>1) { ++ $r = new XML_RPC_Response(0, ++ $XML_RPC_err['invalid_request'], ++ $XML_RPC_str['invalid_request'] ++ . ': ' ++ . $XML_RPC_xh[$parser]['isf_reason']); ++ xml_parser_free($parser_resource); ++ } else { ++ xml_parser_free($parser_resource); ++ $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']); ++ // now add parameters in ++ for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) { ++ // print '\n"; ++ $plist .= "$i - " . var_export($XML_RPC_xh[$parser]['params'][$i], true) . " \n"; ++ $m->addParam($XML_RPC_xh[$parser]['params'][$i]); ++ } ++ XML_RPC_Server_debugmsg($plist); ++ ++ // now to deal with the method ++ $methName = $XML_RPC_xh[$parser]['method']; ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $this->dmap; ++ $sysCall = 0; ++ } ++ ++ if (isset($dmap[$methName]['function']) ++ && is_string($dmap[$methName]['function']) ++ && strpos($dmap[$methName]['function'], '::') !== false) ++ { ++ $dmap[$methName]['function'] = ++ explode('::', $dmap[$methName]['function']); ++ } ++ ++ if (isset($dmap[$methName]['function']) ++ && is_callable($dmap[$methName]['function'])) ++ { ++ // dispatch if exists ++ if (isset($dmap[$methName]['signature'])) { ++ $sr = $this->verifySignature($m, ++ $dmap[$methName]['signature'] ); ++ } ++ if (!isset($dmap[$methName]['signature']) || $sr[0]) { ++ // if no signature or correct signature ++ if ($sysCall) { ++ $r = call_user_func($dmap[$methName]['function'], $this, $m); ++ } else { ++ $r = call_user_func($dmap[$methName]['function'], $m); ++ } ++ if (!is_a($r, 'XML_RPC_Response')) { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['not_response_object'], ++ $XML_RPC_str['not_response_object']); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], ++ $XML_RPC_str['incorrect_params'] ++ . ': ' . $sr[1]); ++ } ++ } else { ++ // else prepare error response ++ $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'], ++ $XML_RPC_str['unknown_method']); ++ } ++ } ++ return $r; ++ } ++ ++ /** ++ * Echos back the input packet as a string value ++ * ++ * @return void ++ * ++ * Useful for debugging. ++ */ ++ function echoInput() ++ { ++ global $HTTP_RAW_POST_DATA; ++ ++ $r = new XML_RPC_Response(0); ++ $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); ++ print $r->serialize(); ++ } ++} ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * c-hanging-comment-ender-p: nil ++ * End: ++ */ ++ ++?> ++package.xml100666 0 0 25606 10277724746 6300 ++ ++ ++ XML_RPC ++ PHP implementation of the XML-RPC protocol ++ A PEAR-ified version of Useful Inc's XML-RPC for PHP. ++ ++It has support for HTTP/HTTPS transport, proxies and authentication. ++ ++ ++ ++ ssb ++ Stig Bakken ++ stig@php.net ++ lead ++ ++ ++ danielc ++ Daniel Convissor ++ danielc@php.net ++ lead ++ ++ ++ ++ 1.4.0 ++ 2005-08-14 ++ PHP License ++ stable ++ * MAJOR SECURITY FIX: eliminate use of eval(). ++* Using socket_get_status() because stream_get_meta_data() was introduced in 4.3.0, but we need to support 4.2.0. Bug 4805. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 1.3.3 ++ 2005-07-15 ++ stable ++ * Eliminate memory leak by resetting $XML_RPC_xh each time parseResponse() is called. Bug 4780. ++* Using socket_set_timeout() because stream_set_timeout() was introduced in 4.3.0, but we need to support 4.2.0. Bug 4805. ++ ++ ++ ++ 1.3.2 ++ 2005-07-07 ++ stable ++ * Eliminate path disclosure vulnerabilities by suppressing error messages when eval()'ing. ++* Eliminate path disclosure vulnerability by catching bogus parameters submitted to XML_RPC_Value::serializeval(). ++* In XML_RPC_Server::service(), only call createServerPayload() and createServerHeaders() if necessary. Fixes compatibility issue introduced in Release 1.3.0RC1 for users who set the $serviceNow parameter of XML_RPC_Server() to 0. Bug 4757. ++* Change "var $errstring" to "var $errstr". Bug 4582. Was put into CVS version 1.75 of RPC.php but didn't make it into RELEASE_1_3_1. ++ ++ ++ ++ 1.3.1 ++ 2005-06-29 ++ stable ++ * Security fix. Update highly recommended! ++ ++ ++ ++ 1.3.0 ++ 2005-06-13 ++ stable ++ * Stable release. See earlier releases for changes since 1.2.2. ++ ++ ++ ++ 1.3.0RC3 ++ 2005-05-10 ++ beta ++ * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. ++* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. ++* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. ++* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. ++* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). ++* Use <br /> instead of <br> in XML_RPC_Value::dump(). ++ ++ ++ ++ 1.3.0RC2 ++ 2005-05-05 ++ beta ++ * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. ++* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. ++* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. ++* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. ++ ++ ++ ++ 1.3.0RC1 ++ 2005-04-07 ++ beta ++ * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. ++* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. ++* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. ++* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. ++* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. ++* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. ++ ++ ++ ++ 1.2.2 ++ 2005-03-07 ++ stable ++ * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. ++ ++ ++ ++ 1.2.1 ++ 2005-03-01 ++ stable ++ * Add isset() check before examining the dispatch map. Bug 3658. ++ ++ ++ ++ 1.2.0 ++ 2005-02-27 ++ stable ++ * Provide the "stable" release. ++* Add package2.xml for compatibility with PEAR 1.4.0. ++* For changes since 1.1.0, see the changelogs for the various RC releases. ++ ++ ++ ++ 1.2.0RC7 ++ 2005-02-22 ++ beta ++ * Add the setSendEncoding() method and $send_encoding ++ property to XML_RPC_Message. Request 3537. ++* Allow class methods to be mapped using either syntax: ++ 'function' => 'hello::sayHello', ++ or ++ 'function' => array('hello', 'sayhello'), ++ Bug 3363. ++* Use 8192 instead of 32768 for bytes in fread() ++ in parseResponseFile(). Bug 3340. ++ ++ ++ ++ 1.2.0RC6 ++ 2005-01-25 ++ beta ++ * Don't put the protocol in the Host field of the POST data. (danielc) ++ ++ ++ ++ 1.2.0RC5 ++ 2005-01-24 ++ beta ++ * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. ++ ++ ++ ++ 1.2.0RC4 ++ 2005-01-24 ++ beta ++ * When a connection attempt fails, have the method return 0. (danielc) ++* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) ++* Add tests for setting the client properties. (danielc) ++* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) ++* Bundle the tests with the package. (danielc) ++ ++ ++ ++ 1.2.0RC3 ++ 2005-01-19 ++ beta ++ * ssl uses port 443, not 445. ++ ++ ++ ++ 1.2.0RC2 ++ 2005-01-11 ++ beta ++ * Handle ssl:// in the $server string. (danielc) ++* Also default to port 445 for ssl:// requests as well. (danielc) ++* Enhance debugging in the server. (danielc) ++ ++ ++ ++ 1.2.0RC1 ++ 2004-12-30 ++ beta ++ * Make things work with SSL. Bug 2489. (nkukard lbsd net) ++* Allow array function callbacks (Matt Kane) ++* Some minor speed-ups (Matt Kane) ++* Add Dump.php to the package (Christian Weiske) ++* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) ++* Silence fsockopen() errors. Bug 1714. (danielc) ++* Encode empty arrays as an array. Bug 1493. (danielc) ++* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) ++* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) ++* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) ++* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) ++* Allow raiseError() to be called statically. (danielc) ++* Stop double escaping of character entities. Bug 987. (danielc) ++ NOTICE: the following have been removed: ++ * XML_RPC_dh() ++ * $GLOBALS['XML_RPC_entities'] ++ * XML_RPC_entity_decode() ++ * XML_RPC_lookup_entity() ++* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) ++ ++ ++ ++ 1.1.0 ++ 2004-03-15 ++ stable ++ * Added support for sequential arrays to XML_RPC_encode() (mroch) ++* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) ++* Remove "require_once 'PEAR.php'", include only when needed to raise an error ++* Replace echo and error_log() with raiseError() (mroch) ++* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) ++* be tolerant of junk after methodResponse (Luca Mariano, mroch) ++* Silent notice even in the error log (pierre) ++* fix include of shared xml extension on win32 (pierre) ++ ++ ++ ++ 1.0.4 ++ 2002-10-02 ++ stable ++ * added HTTP proxy authorization support (thanks to Arnaud Limbourg) ++ ++ ++ ++ 1.0.3 ++ 2002-05-19 ++ stable ++ * fix bug when parsing responses with boolean types ++ ++ ++ ++ 1.0.2 ++ 2002-04-16 ++ stable ++ * E_ALL fixes ++* fix HTTP response header parsing ++ ++ ++ ++ 1.0.1 ++ 2001-09-25 ++ stable ++ This is a PEAR-ified version of Useful Inc's 1.0.1 release. ++Includes an urgent security fix identified by Dan Libby <dan@libby.com>. ++ ++ ++ ++ ++ +\ Kein Zeilenumbruch am Dateiende. +diff -Nura php-4.4.0/php.ini-dist hardening-patch-4.4.0-0.4.2/php.ini-dist +--- php-4.4.0/php.ini-dist 2005-04-28 15:14:45.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/php.ini-dist 2005-09-07 18:40:29.105945520 +0200 +@@ -1112,6 +1112,185 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's Executor options ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++; White-/blacklist for function calls during normal execution ++;hphp.executor.func.whitelist = ord,chr ++;hphp.executor.func.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for function calls during eval() execution ++;hphp.executor.eval.whitelist = ord,chr ++;hphp.executor.eval.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nura php-4.4.0/php.ini-recommended hardening-patch-4.4.0-0.4.2/php.ini-recommended +--- php-4.4.0/php.ini-recommended 2005-04-28 15:14:46.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/php.ini-recommended 2005-09-07 18:40:29.106945368 +0200 +@@ -1110,6 +1110,185 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's Executor options ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++; White-/blacklist for function calls during normal execution ++;hphp.executor.func.whitelist = ord,chr ++;hphp.executor.func.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for function calls during eval() execution ++;hphp.executor.eval.whitelist = ord,chr ++;hphp.executor.eval.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nura php-4.4.0/README.input_filter hardening-patch-4.4.0-0.4.2/README.input_filter +--- php-4.4.0/README.input_filter 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/README.input_filter 2005-09-07 18:40:29.107945216 +0200 +@@ -0,0 +1,193 @@ ++Input Filter Support ported from PHP 5 ++-------------------------------------- ++ ++XSS (Cross Site Scripting) hacks are becoming more and more prevalent, ++and can be quite difficult to prevent. Whenever you accept user data ++and somehow display this data back to users, you are likely vulnerable ++to XSS hacks. ++ ++The Input Filter support in PHP 5 is aimed at providing the framework ++through which a company-wide or site-wide security policy can be ++enforced. It is implemented as a SAPI hook and is called from the ++treat_data and post handler functions. To implement your own security ++policy you will need to write a standard PHP extension. ++ ++A simple implementation might look like the following. This stores the ++original raw user data and adds a my_get_raw() function while the normal ++$_POST, $_GET and $_COOKIE arrays are only populated with stripped ++data. In this simple example all I am doing is calling strip_tags() on ++the data. If register_globals is turned on, the default globals that ++are created will be stripped ($foo) while a $RAW_foo is created with the ++original user input. ++ ++ZEND_BEGIN_MODULE_GLOBALS(my_input_filter) ++ zval *post_array; ++ zval *get_array; ++ zval *cookie_array; ++ZEND_END_MODULE_GLOBALS(my_input_filter) ++ ++#ifdef ZTS ++#define IF_G(v) TSRMG(my_input_filter_globals_id, zend_my_input_filter_globals *, v) ++#else ++#define IF_G(v) (my_input_filter_globals.v) ++#endif ++ ++ZEND_DECLARE_MODULE_GLOBALS(my_input_filter) ++ ++function_entry my_input_filter_functions[] = { ++ PHP_FE(my_get_raw, NULL) ++ {NULL, NULL, NULL} ++}; ++ ++zend_module_entry my_input_filter_module_entry = { ++ STANDARD_MODULE_HEADER, ++ "my_input_filter", ++ my_input_filter_functions, ++ PHP_MINIT(my_input_filter), ++ PHP_MSHUTDOWN(my_input_filter), ++ NULL, ++ PHP_RSHUTDOWN(my_input_filter), ++ PHP_MINFO(my_input_filter), ++ "0.1", ++ STANDARD_MODULE_PROPERTIES ++}; ++ ++PHP_MINIT_FUNCTION(my_input_filter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(my_input_filter, php_my_input_filter_init_globals, NULL); ++ ++ REGISTER_LONG_CONSTANT("POST", PARSE_POST, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("GET", PARSE_GET, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("COOKIE", PARSE_COOKIE, CONST_CS | CONST_PERSISTENT); ++ ++ sapi_register_input_filter(my_sapi_input_filter); ++ return SUCCESS; ++} ++ ++PHP_RSHUTDOWN_FUNCTION(my_input_filter) ++{ ++ if(IF_G(get_array)) { ++ zval_ptr_dtor(&IF_G(get_array)); ++ IF_G(get_array) = NULL; ++ } ++ if(IF_G(post_array)) { ++ zval_ptr_dtor(&IF_G(post_array)); ++ IF_G(post_array) = NULL; ++ } ++ if(IF_G(cookie_array)) { ++ zval_ptr_dtor(&IF_G(cookie_array)); ++ IF_G(cookie_array) = NULL; ++ } ++ return SUCCESS; ++} ++ ++PHP_MINFO_FUNCTION(my_input_filter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_row( 2, "My Input Filter Support", "enabled" ); ++ php_info_print_table_row( 2, "Revision", "$Revision: 1.1 $"); ++ php_info_print_table_end(); ++} ++ ++/* The filter handler. If you return 1 from it, then PHP also registers the ++ * (modified) variable. Returning 0 prevents PHP from registering the variable; ++ * you can use this if your filter already registers the variable under a ++ * different name, or if you just don't want the variable registered at all. */ ++SAPI_INPUT_FILTER_FUNC(my_sapi_input_filter) ++{ ++ zval new_var; ++ zval *array_ptr = NULL; ++ char *raw_var; ++ int var_len; ++ ++ assert(*val != NULL); ++ ++ switch(arg) { ++ case PARSE_GET: ++ if(!IF_G(get_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(get_array) = array_ptr; ++ break; ++ case PARSE_POST: ++ if(!IF_G(post_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(post_array) = array_ptr; ++ break; ++ case PARSE_COOKIE: ++ if(!IF_G(cookie_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(cookie_array) = array_ptr; ++ break; ++ } ++ Z_STRLEN(new_var) = val_len; ++ Z_STRVAL(new_var) = estrndup(*val, val_len); ++ Z_TYPE(new_var) = IS_STRING; ++ ++ var_len = strlen(var); ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ ++ php_register_variable_ex(raw_var, &new_var, array_ptr TSRMLS_DC); ++ ++ php_strip_tags(*val, val_len, NULL, NULL, 0); ++ ++ *new_val_len = strlen(*val); ++ return 1; ++} ++ ++PHP_FUNCTION(my_get_raw) ++{ ++ long arg; ++ char *var; ++ int var_len; ++ zval **tmp; ++ zval *array_ptr = NULL; ++ HashTable *hash_ptr; ++ char *raw_var; ++ ++ if(zend_parse_parameters(2 TSRMLS_CC, "ls", &arg, &var, &var_len) == FAILURE) { ++ return; ++ } ++ ++ switch(arg) { ++ case PARSE_GET: ++ array_ptr = IF_G(get_array); ++ break; ++ case PARSE_POST: ++ array_ptr = IF_G(post_array); ++ break; ++ case PARSE_COOKIE: ++ array_ptr = IF_G(post_array); ++ break; ++ } ++ ++ if(!array_ptr) RETURN_FALSE; ++ ++ /* ++ * I'm changing the variable name here because when running with register_globals on, ++ * the variable will end up in the global symbol table ++ */ ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ hash_ptr = HASH_OF(array_ptr); ++ ++ if(zend_hash_find(hash_ptr, raw_var, var_len+5, (void **)&tmp) == SUCCESS) { ++ *return_value = **tmp; ++ zval_copy_ctor(return_value); ++ } else { ++ RETVAL_FALSE; ++ } ++ efree(raw_var); ++} ++ +diff -Nura php-4.4.0/sapi/apache/mod_php4.c hardening-patch-4.4.0-0.4.2/sapi/apache/mod_php4.c +--- php-4.4.0/sapi/apache/mod_php4.c 2005-05-19 18:14:46.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/sapi/apache/mod_php4.c 2005-09-07 18:40:29.107945216 +0200 +@@ -452,7 +452,7 @@ + sapi_apache_get_fd, + sapi_apache_force_http_10, + sapi_apache_get_target_uid, +- sapi_apache_get_target_gid ++ sapi_apache_get_target_gid, + }; + /* }}} */ + +@@ -898,7 +898,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component("PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component("PHP/" PHP_VERSION); ++#endif + } + } + #endif +diff -Nura php-4.4.0/sapi/apache2filter/sapi_apache2.c hardening-patch-4.4.0-0.4.2/sapi/apache2filter/sapi_apache2.c +--- php-4.4.0/sapi/apache2filter/sapi_apache2.c 2005-04-08 22:35:02.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/sapi/apache2filter/sapi_apache2.c 2005-09-07 18:40:29.108945064 +0200 +@@ -556,7 +556,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nura php-4.4.0/sapi/apache2handler/sapi_apache2.c hardening-patch-4.4.0-0.4.2/sapi/apache2handler/sapi_apache2.c +--- php-4.4.0/sapi/apache2handler/sapi_apache2.c 2005-04-08 22:35:02.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/sapi/apache2handler/sapi_apache2.c 2005-09-07 18:40:29.108945064 +0200 +@@ -340,7 +340,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nura php-4.4.0/sapi/cgi/cgi_main.c hardening-patch-4.4.0-0.4.2/sapi/cgi/cgi_main.c +--- php-4.4.0/sapi/cgi/cgi_main.c 2005-04-28 16:24:47.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/sapi/cgi/cgi_main.c 2005-09-07 18:40:29.109944912 +0200 +@@ -1440,11 +1440,19 @@ + SG(headers_sent) = 1; + SG(request_info).no_headers = 1; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit(1); + break; +diff -Nura php-4.4.0/sapi/cli/php_cli.c hardening-patch-4.4.0-0.4.2/sapi/cli/php_cli.c +--- php-4.4.0/sapi/cli/php_cli.c 2005-03-22 16:09:36.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/sapi/cli/php_cli.c 2005-09-07 18:40:29.110944760 +0200 +@@ -652,11 +652,19 @@ + if (php_request_startup(TSRMLS_C)==FAILURE) { + goto err; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit_status=1; + goto out; +diff -Nura php-4.4.0/TSRM/TSRM.h hardening-patch-4.4.0-0.4.2/TSRM/TSRM.h +--- php-4.4.0/TSRM/TSRM.h 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/TSRM/TSRM.h 2005-09-07 18:40:29.111944608 +0200 +@@ -33,6 +33,13 @@ + # define TSRM_API + #endif + ++#if HARDENING_PATCH ++# if HAVE_REALPATH ++# undef realpath ++# define realpath php_realpath ++# endif ++#endif ++ + /* Only compile multi-threading functions if we're in ZTS mode */ + #ifdef ZTS + +@@ -90,6 +97,7 @@ + + #define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts + ++ + #ifdef __cplusplus + extern "C" { + #endif +diff -Nura php-4.4.0/TSRM/tsrm_virtual_cwd.c hardening-patch-4.4.0-0.4.2/TSRM/tsrm_virtual_cwd.c +--- php-4.4.0/TSRM/tsrm_virtual_cwd.c 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/TSRM/tsrm_virtual_cwd.c 2005-09-07 18:40:29.111944608 +0200 +@@ -192,6 +192,165 @@ + return p; + } + ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved) ++{ ++ struct stat sb; ++ char *p, *q, *s; ++ size_t left_len, resolved_len; ++ unsigned symlinks; ++ int serrno, slen; ++ int is_dir = 1; ++ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; ++ ++ serrno = errno; ++ symlinks = 0; ++ if (path[0] == '/') { ++ resolved[0] = '/'; ++ resolved[1] = '\0'; ++ if (path[1] == '\0') ++ return (resolved); ++ resolved_len = 1; ++ left_len = strlcpy(left, path + 1, sizeof(left)); ++ } else { ++ if (getcwd(resolved, PATH_MAX) == NULL) { ++ strlcpy(resolved, ".", PATH_MAX); ++ return (NULL); ++ } ++ resolved_len = strlen(resolved); ++ left_len = strlcpy(left, path, sizeof(left)); ++ } ++ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ ++ /* ++ * Iterate over path components in `left'. ++ */ ++ while (left_len != 0) { ++ /* ++ * Extract the next path component and adjust `left' ++ * and its length. ++ */ ++ p = strchr(left, '/'); ++ s = p ? p : left + left_len; ++ if (s - left >= sizeof(next_token)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ memcpy(next_token, left, s - left); ++ next_token[s - left] = '\0'; ++ left_len -= s - left; ++ if (p != NULL) ++ memmove(left, s + 1, left_len + 1); ++ if (resolved[resolved_len - 1] != '/') { ++ if (resolved_len + 1 >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ resolved[resolved_len++] = '/'; ++ resolved[resolved_len] = '\0'; ++ } ++ if (next_token[0] == '\0') ++ continue; ++ else if (strcmp(next_token, ".") == 0) ++ continue; ++ else if (strcmp(next_token, "..") == 0) { ++ /* ++ * Strip the last path component except when we have ++ * single "/" ++ */ ++ if (!is_dir) { ++ errno = ENOENT; ++ return (NULL); ++ } ++ if (resolved_len > 1) { ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ continue; ++ } ++ ++ /* ++ * Append the next path component and lstat() it. If ++ * lstat() fails we still can return successfully if ++ * there are no more path components left. ++ */ ++ resolved_len = strlcat(resolved, next_token, PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ if (lstat(resolved, &sb) != 0) { ++ if (errno == ENOENT && p == NULL) { ++ errno = serrno; ++ return (resolved); ++ } ++ return (NULL); ++ } ++ if (S_ISLNK(sb.st_mode)) { ++ if (symlinks++ > MAXSYMLINKS) { ++ errno = ELOOP; ++ return (NULL); ++ } ++ slen = readlink(resolved, symlink, sizeof(symlink) - 1); ++ if (slen < 0) ++ return (NULL); ++ symlink[slen] = '\0'; ++ if (symlink[0] == '/') { ++ resolved[1] = 0; ++ resolved_len = 1; ++ } else if (resolved_len > 1) { ++ /* Strip the last path component. */ ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ ++ /* ++ * If there are any path components left, then ++ * append them to symlink. The result is placed ++ * in `left'. ++ */ ++ if (p != NULL) { ++ if (symlink[slen - 1] != '/') { ++ if (slen + 1 >= sizeof(symlink)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ symlink[slen] = '/'; ++ symlink[slen + 1] = 0; ++ } ++ left_len = strlcat(symlink, left, sizeof(left)); ++ if (left_len >= sizeof(left)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ } ++ left_len = strlcpy(left, symlink, sizeof(left)); ++ } else { ++ if (S_ISDIR(sb.st_mode)) { ++ is_dir = 1; ++ } else { ++ is_dir = 0; ++ } ++ } ++ } ++ ++ /* ++ * Remove trailing slash except when the resolved pathname ++ * is a single "/". ++ */ ++ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') ++ resolved[resolved_len - 1] = '\0'; ++ return (resolved); ++} ++#endif ++ + CWD_API void virtual_cwd_startup(void) + { + char cwd[MAXPATHLEN]; +@@ -314,8 +473,7 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now +- return 1; */ ++ return 1; + } + } + } else { /* Concat current directory with relative path and then run realpath() on it */ +@@ -341,9 +499,8 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now + free(tmp); +- return 1; */ ++ return 1; + } + } + free(tmp); +diff -Nura php-4.4.0/TSRM/tsrm_virtual_cwd.h hardening-patch-4.4.0-0.4.2/TSRM/tsrm_virtual_cwd.h +--- php-4.4.0/TSRM/tsrm_virtual_cwd.h 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/TSRM/tsrm_virtual_cwd.h 2005-09-07 18:40:29.112944456 +0200 +@@ -128,6 +128,22 @@ + + typedef int (*verify_path_func)(const cwd_state *); + ++#ifndef HAVE_STRLCPY ++CWD_API size_t php_strlcpy(char *dst, const char *src, size_t siz); ++#undef strlcpy ++#define strlcpy php_strlcpy ++#endif ++ ++#ifndef HAVE_STRLCAT ++CWD_API size_t php_strlcat(char *dst, const char *src, size_t siz); ++#undef strlcat ++#define strlcat php_strlcat ++#endif ++ ++ ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved); ++#endif + CWD_API void virtual_cwd_startup(void); + CWD_API void virtual_cwd_shutdown(void); + CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC); +diff -Nura php-4.4.0/Zend/zend_alloc.c hardening-patch-4.4.0-0.4.2/Zend/zend_alloc.c +--- php-4.4.0/Zend/zend_alloc.c 2005-04-07 22:54:33.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_alloc.c 2005-09-07 18:40:29.113944304 +0200 +@@ -56,6 +56,11 @@ + # define END_MAGIC_SIZE 0 + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++# define CANARY_SIZE sizeof(unsigned int) ++#else ++# define CANARY_SIZE 0 ++#endif + + # if MEMORY_LIMIT + # if ZEND_DEBUG +@@ -95,9 +100,17 @@ + if (p==AG(head)) { \ + AG(head) = p->pNext; \ + } else { \ ++ if (p != p->pLast->pNext) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pLast->pNext = p->pNext; \ + } \ + if (p->pNext) { \ ++ if (p != p->pNext->pLast) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pNext->pLast = p->pLast; \ + } + +@@ -129,6 +142,12 @@ + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (size > LONG_MAX - sizeof(zend_mem_header) - MEM_HEADER_PADDING - END_MAGIC_SIZE - CANARY_SIZE) { ++ zend_security_log(S_MEMORY, "emalloc() - requested size would result in integer overflow"); ++ exit(1); ++ } ++#endif + CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size); + + if (!ZEND_DISABLE_MEMORY_CACHE && (CACHE_INDEX < MAX_CACHED_MEMORY) && (AG(cache_count)[CACHE_INDEX] > 0)) { +@@ -146,6 +165,10 @@ + AG(cache_stats)[CACHE_INDEX][1]++; + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->cached = 0; + p->size = size; + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); +@@ -161,7 +184,7 @@ + AG(allocated_memory_peak) = AG(allocated_memory); + } + #endif +- p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE + CANARY_SIZE); + } + + HANDLE_BLOCK_INTERRUPTIONS(); +@@ -191,7 +214,10 @@ + # endif + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif +- ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); + } +@@ -218,17 +244,36 @@ + return emalloc_rel(lval + offset); + } + } +- ++ ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by safe_emalloc()"); ++#endif + zend_error(E_ERROR, "Possible integer overflow in memory allocation (%ld * %ld + %ld)", nmemb, size, offset); + return 0; + } + + ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p = (zend_mem_header *) ((char *)ptr - sizeof(zend_mem_header) - MEM_HEADER_PADDING); + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (p->canary != HG(canary_1)) goto efree_canary_mismatch; ++ memcpy(&canary_2, (((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), CANARY_SIZE); ++ if (canary_2 != HG(canary_2)) { ++efree_canary_mismatch: ++ zend_security_log(S_MEMORY, "canary mismatch on efree() - heap overflow or double efree detected"); ++ exit(1); ++ } ++ /* to catch double efree()s */ ++ memset((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), 0, CANARY_SIZE); ++ p->canary = 0; ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + tsrm_error(TSRM_ERROR_LEVEL_ERROR, "Memory block allocated at %s:(%d) on thread %x freed at %s:(%d) on thread %x, ignoring", +@@ -273,6 +318,9 @@ + size_t _size = nmemb * size; + + if (nmemb && (_size/nmemb!=size)) { ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by ecalloc()"); ++#endif + fprintf(stderr,"FATAL: ecalloc(): Unable to allocate %ld * %ld bytes\n", (long) nmemb, (long) size); + #if ZEND_DEBUG && HAVE_KILL && HAVE_GETPID + kill(getpid(), SIGSEGV); +@@ -292,6 +340,9 @@ + + ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p; + zend_mem_header *orig; + DECLARE_CACHE_VARS(); +@@ -303,6 +354,16 @@ + + p = orig = (zend_mem_header *) ((char *)ptr-sizeof(zend_mem_header)-MEM_HEADER_PADDING); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (p->canary != HG(canary_1)) goto erealloc_canary_mismatch; ++ memcpy(&canary_2, (((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), CANARY_SIZE); ++ if (canary_2 != HG(canary_2)) { ++erealloc_canary_mismatch: ++ zend_security_log(S_MEMORY, "canary mismatch on erealloc() - heap overflow detected"); ++ exit(1); ++ } ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + void *new_p; +@@ -326,7 +387,7 @@ + } + #endif + REMOVE_POINTER_FROM_LIST(p); +- p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE+CANARY_SIZE); + if (!p) { + if (!allow_failure) { + fprintf(stderr,"FATAL: erealloc(): Unable to allocate %ld bytes\n", (long) size); +@@ -348,6 +409,9 @@ + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->size = size; + + HANDLE_UNBLOCK_INTERRUPTIONS(); +@@ -422,6 +486,10 @@ + { + AG(head) = NULL; + ++#if HARDENING_PATCH_MM_PROTECT ++ HG(canary_1) = zend_canary(); ++ HG(canary_2) = zend_canary(); ++#endif + #if MEMORY_LIMIT + AG(memory_limit) = 1<<30; /* ridiculous limit, effectively no limit */ + AG(allocated_memory) = 0; +diff -Nura php-4.4.0/Zend/zend_alloc.h hardening-patch-4.4.0-0.4.2/Zend/zend_alloc.h +--- php-4.4.0/Zend/zend_alloc.h 2005-06-07 15:37:33.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_alloc.h 2005-09-07 18:40:29.113944304 +0200 +@@ -32,6 +32,9 @@ + #define MEM_BLOCK_CACHED_MAGIC 0xFB8277DCL + + typedef struct _zend_mem_header { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary; ++#endif + #if ZEND_DEBUG + long magic; + char *filename; +diff -Nura php-4.4.0/Zend/zend_builtin_functions.c hardening-patch-4.4.0-0.4.2/Zend/zend_builtin_functions.c +--- php-4.4.0/Zend/zend_builtin_functions.c 2005-06-23 14:20:47.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_builtin_functions.c 2005-09-07 18:40:29.115944000 +0200 +@@ -49,6 +49,9 @@ + static ZEND_FUNCTION(crash); + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++static ZEND_FUNCTION(heap_overflow); ++#endif + static ZEND_FUNCTION(get_included_files); + static ZEND_FUNCTION(is_subclass_of); + static ZEND_FUNCTION(is_a); +@@ -101,6 +104,9 @@ + ZEND_FE(crash, NULL) + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ ZEND_FE(heap_overflow, NULL) ++#endif + ZEND_FE(get_included_files, NULL) + ZEND_FALIAS(get_required_files, get_included_files, NULL) + ZEND_FE(is_subclass_of, NULL) +@@ -805,6 +811,19 @@ + + #endif /* ZEND_DEBUG */ + ++ ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ZEND_FUNCTION(heap_overflow) ++{ ++ char *nowhere = emalloc(10); ++ ++ memcpy(nowhere, "something1234567890", sizeof("something1234567890")); ++ ++ efree(nowhere); ++} ++#endif ++ ++ + /* {{{ proto array get_included_files(void) + Returns an array with the file names that were include_once()'d */ + ZEND_FUNCTION(get_included_files) +diff -Nura php-4.4.0/Zend/zend.c hardening-patch-4.4.0-0.4.2/Zend/zend.c +--- php-4.4.0/Zend/zend.c 2005-06-09 12:14:25.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend.c 2005-09-07 18:49:42.847763968 +0200 +@@ -53,6 +53,12 @@ + ZEND_API void (*zend_unblock_interruptions)(void); + ZEND_API void (*zend_ticks_function)(int ticks); + ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); ++#if HARDENING_PATCH ++ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + + void (*zend_on_timeout)(int seconds TSRMLS_DC); + +@@ -70,9 +76,289 @@ + return SUCCESS; + } + ++#if HARDENING_PATCH ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog) = S_ALL & ~S_SQL | S_MEMORY | S_INTERNAL; ++ } else { ++ EG(hphp_log_syslog) = atoi(new_value) | S_MEMORY | S_INTERNAL; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_facility) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_facility) = LOG_USER; ++ } else { ++ EG(hphp_log_syslog_facility) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_priority) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_priority) = LOG_ALERT; ++ } else { ++ EG(hphp_log_syslog_priority) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_sapi) ++{ ++ if (!new_value) { ++ EG(hphp_log_sapi) = S_ALL & ~S_SQL | S_INTERNAL; ++ } else { ++ EG(hphp_log_sapi) = atoi(new_value) | S_INTERNAL; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_script) ++{ ++ if (!new_value) { ++ EG(hphp_log_script) = S_ALL & (~S_MEMORY) & (~S_INTERNAL); ++ } else { ++ EG(hphp_log_script) = atoi(new_value) & (~S_MEMORY) & (~S_INTERNAL); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_scriptname) ++{ ++ if (!new_value) { ++ EG(hphp_log_scriptname) = NULL; ++ } else { ++ if (EG(hphp_log_scriptname)) { ++ pefree(EG(hphp_log_scriptname),1); ++ } ++ EG(hphp_log_scriptname) = pestrdup(new_value,1); ++ } ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_eval_whitelist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++eval_whitelist_destroy: ++ if (HG(eval_whitelist)) { ++ zend_hash_destroy(HG(eval_whitelist)); ++ efree(HG(eval_whitelist)); ++ } ++ HG(eval_whitelist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto eval_whitelist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(eval_whitelist)); ++ zend_hash_init(HG(eval_whitelist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(eval_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(eval_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_eval_blacklist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++eval_blacklist_destroy: ++ if (HG(eval_blacklist)) { ++ zend_hash_destroy(HG(eval_blacklist)); ++ efree(HG(eval_blacklist)); ++ } ++ HG(eval_blacklist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto eval_blacklist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(eval_blacklist)); ++ zend_hash_init(HG(eval_blacklist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(eval_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(eval_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_func_whitelist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++func_whitelist_destroy: ++ if (HG(func_whitelist)) { ++ zend_hash_destroy(HG(func_whitelist)); ++ efree(HG(func_whitelist)); ++ } ++ HG(func_whitelist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto func_whitelist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(func_whitelist)); ++ zend_hash_init(HG(func_whitelist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(func_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(func_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_func_blacklist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++func_blacklist_destroy: ++ if (HG(func_blacklist)) { ++ zend_hash_destroy(HG(func_blacklist)); ++ efree(HG(func_blacklist)); ++ } ++ HG(func_blacklist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto func_blacklist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(func_blacklist)); ++ zend_hash_init(HG(func_blacklist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(func_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(func_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ ++ return SUCCESS; ++} ++ ++#endif + + ZEND_INI_BEGIN() + ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) ++#if HARDENING_PATCH ++ ZEND_INI_ENTRY("hphp.log.syslog", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog) ++ ZEND_INI_ENTRY("hphp.log.syslog.facility", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_facility) ++ ZEND_INI_ENTRY("hphp.log.syslog.priority", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_priority) ++ ZEND_INI_ENTRY("hphp.log.sapi", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_sapi) ++ ZEND_INI_ENTRY("hphp.log.script", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_script) ++ ZEND_INI_ENTRY("hphp.log.script.name", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_scriptname) ++ STD_ZEND_INI_BOOLEAN("hphp.log.use-x-forwarded-for", "0", ZEND_INI_SYSTEM, OnUpdateBool, hphp_log_use_x_forwarded_for, zend_executor_globals, executor_globals) ++ ++ ZEND_INI_ENTRY("hphp.executor.eval.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_eval_whitelist) ++ ZEND_INI_ENTRY("hphp.executor.eval.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_eval_blacklist) ++ ZEND_INI_ENTRY("hphp.executor.func.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_func_whitelist) ++ ZEND_INI_ENTRY("hphp.executor.func.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_func_blacklist) ++ ++ STD_ZEND_INI_ENTRY("hphp.executor.max_depth", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateLong, hphp_executor_max_depth, zend_executor_globals, executor_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.sql.bailout_on_error", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, hphp_sql_bailout_on_error, hardened_globals_struct, hardened_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.multiheader", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, hphp_multiheader, hardened_globals_struct, hardened_globals) ++#endif + ZEND_INI_END() + + +@@ -354,6 +640,7 @@ + zend_init_rsrc_plist(TSRMLS_C); + EG(lambda_count)=0; + EG(user_error_handler) = NULL; ++ EG(in_code_type) = 0; + EG(in_execution) = 0; + EG(current_execute_data) = NULL; + } +@@ -420,6 +707,14 @@ + extern zend_scanner_globals language_scanner_globals; + #endif + ++ /* Set up Hardening-Patch utility functions first */ ++#if HARDENING_PATCH ++ zend_security_log = utility_functions->security_log_function; ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ zend_is_valid_include = utility_functions->is_valid_include; ++#endif ++ + #ifdef ZTS + ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); + #else +@@ -623,6 +918,7 @@ + } + CG(unclean_shutdown) = 1; + CG(in_compilation) = EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(current_execute_data) = NULL; + longjmp(EG(bailout), FAILURE); + } +diff -Nura php-4.4.0/Zend/zend_canary.c hardening-patch-4.4.0-0.4.2/Zend/zend_canary.c +--- php-4.4.0/Zend/zend_canary.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_canary.c 2005-09-07 18:40:29.116943848 +0200 +@@ -0,0 +1,58 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: zend_canary.c,v 1.1 2004/11/26 12:45:41 ionic Exp $ */ ++ ++#include "zend.h" ++ ++#include ++#include ++ ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++ZEND_API unsigned int zend_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-4.4.0/Zend/zend_compile.c hardening-patch-4.4.0-0.4.2/Zend/zend_compile.c +--- php-4.4.0/Zend/zend_compile.c 2005-06-24 13:48:30.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_compile.c 2005-09-07 18:40:29.118943544 +0200 +@@ -763,6 +763,13 @@ + op_array.function_name = name; + op_array.arg_types = NULL; + op_array.return_reference = return_reference; ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array.created_by_eval = 1; ++ } else { ++ op_array.created_by_eval = 0; ++ } ++#endif + + if (is_method) { + if (zend_hash_add(&CG(active_class_entry)->function_table, name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)) == FAILURE) { +diff -Nura php-4.4.0/Zend/zend_compile.h hardening-patch-4.4.0-0.4.2/Zend/zend_compile.h +--- php-4.4.0/Zend/zend_compile.h 2005-06-06 11:30:09.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_compile.h 2005-09-07 18:40:29.118943544 +0200 +@@ -106,6 +106,9 @@ + char *filename; + + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; ++#if HARDENING_PATCH ++ zend_bool created_by_eval; ++#endif + }; + + +@@ -549,6 +552,7 @@ + #define ZEND_USER_FUNCTION 2 + #define ZEND_OVERLOADED_FUNCTION 3 + #define ZEND_EVAL_CODE 4 ++#define ZEND_SANDBOX_CODE 6 + + #define ZEND_INTERNAL_CLASS 1 + #define ZEND_USER_CLASS 2 +diff -Nura php-4.4.0/Zend/zend_constants.c hardening-patch-4.4.0-0.4.2/Zend/zend_constants.c +--- php-4.4.0/Zend/zend_constants.c 2004-07-13 21:29:45.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_constants.c 2005-09-07 18:48:20.315310808 +0200 +@@ -111,6 +111,73 @@ + REGISTER_MAIN_LONG_CONSTANT("E_USER_NOTICE", E_USER_NOTICE, CONST_PERSISTENT | CONST_CS); + + REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("S_MEMORY", S_MEMORY, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_VARS", S_VARS, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_FILES", S_FILES, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INCLUDE", S_INCLUDE, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_SQL", S_SQL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_EXECUTOR", S_EXECUTOR, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_MISC", S_MISC, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INTERNAL", S_INTERNAL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_ALL", S_ALL, CONST_PERSISTENT | CONST_CS); ++ ++ /* error levels */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRIT", LOG_CRIT, CONST_CS | CONST_PERSISTENT); /* critical conditions */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ERR", LOG_ERR, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_WARNING", LOG_WARNING, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOTICE", LOG_NOTICE, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_INFO", LOG_INFO, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DEBUG", LOG_DEBUG, CONST_CS | CONST_PERSISTENT); ++ /* facility: type of program logging the message */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_KERN", LOG_KERN, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_USER", LOG_USER, CONST_CS | CONST_PERSISTENT); /* generic user level */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_MAIL", LOG_MAIL, CONST_CS | CONST_PERSISTENT); /* log to email */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DAEMON", LOG_DAEMON, CONST_CS | CONST_PERSISTENT); /* other system daemons */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTH", LOG_AUTH, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_SYSLOG", LOG_SYSLOG, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LPR", LOG_LPR, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NEWS ++ /* No LOG_NEWS on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NEWS", LOG_NEWS, CONST_CS | CONST_PERSISTENT); /* usenet new */ ++#endif ++#ifdef LOG_UUCP ++ /* No LOG_UUCP on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_UUCP", LOG_UUCP, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_CRON ++ /* apparently some systems don't have this one */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRON", LOG_CRON, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_AUTHPRIV ++ /* AIX doesn't have LOG_AUTHPRIV */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTHPRIV", LOG_AUTHPRIV, CONST_CS | CONST_PERSISTENT); ++#endif ++#if !defined(PHP_WIN32) && !defined(NETWARE) ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL0", LOG_LOCAL0, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL1", LOG_LOCAL1, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL2", LOG_LOCAL2, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL3", LOG_LOCAL3, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL4", LOG_LOCAL4, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL5", LOG_LOCAL5, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL6", LOG_LOCAL6, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL7", LOG_LOCAL7, CONST_CS | CONST_PERSISTENT); ++#endif ++ /* options */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PID", LOG_PID, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CONS", LOG_CONS, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ODELAY", LOG_ODELAY, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NDELAY", LOG_NDELAY, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NOWAIT ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOWAIT", LOG_NOWAIT, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_PERROR ++ /* AIX doesn't have LOG_PERROR */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ ++#endif ++#endif + + /* true/false constants */ + { +diff -Nura php-4.4.0/Zend/zend_errors.h hardening-patch-4.4.0-0.4.2/Zend/zend_errors.h +--- php-4.4.0/Zend/zend_errors.h 2002-12-31 17:22:59.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_errors.h 2005-09-07 18:42:19.580150888 +0200 +@@ -36,5 +36,17 @@ + #define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE) + #define E_CORE (E_CORE_ERROR | E_CORE_WARNING) + ++#if HARDENING_PATCH ++#define S_MEMORY (1<<0L) ++#define S_VARS (1<<1L) ++#define S_FILES (1<<2L) ++#define S_INCLUDE (1<<3L) ++#define S_SQL (1<<4L) ++#define S_EXECUTOR (1<<5L) ++#define S_MISC (1<<30L) ++#define S_INTERNAL (1<<29L) ++#define S_ALL (S_MEMORY | S_VARS | S_INCLUDE | S_FILES | S_MISC | S_SQL | S_EXECUTOR) ++#endif ++ + #endif /* ZEND_ERRORS_H */ + +diff -Nura php-4.4.0/Zend/zend_execute_API.c hardening-patch-4.4.0-0.4.2/Zend/zend_execute_API.c +--- php-4.4.0/Zend/zend_execute_API.c 2005-05-18 19:58:09.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_execute_API.c 2005-09-07 18:40:29.120943240 +0200 +@@ -142,6 +142,7 @@ + EG(class_table) = CG(class_table); + + EG(in_execution) = 0; ++ EG(in_code_type) = 0; + + zend_ptr_stack_init(&EG(argument_stack)); + +@@ -431,12 +432,14 @@ + zend_execute_data execute_data; + + /* Initialize execute_data */ ++ memset(&execute_data, 0, sizeof(execute_data)); + EX(fbc) = NULL; + EX(object).ptr = NULL; + EX(ce) = NULL; + EX(Ts) = NULL; + EX(op_array) = NULL; + EX(opline) = NULL; ++ EX(execute_depth) = 0; + + *retval_ptr_ptr = NULL; + +@@ -494,6 +497,39 @@ + zval_dtor(&function_name_copy); + return FAILURE; + } ++#if HARDENING_PATCH ++ if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), function_name_copy.value.str.val, function_name_copy.value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", function_name_copy.value.str.val); ++ zval_dtor(&function_name_copy); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), function_name_copy.value.str.val, function_name_copy.value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", function_name_copy.value.str.val); ++ zval_dtor(&function_name_copy); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), function_name_copy.value.str.val, function_name_copy.value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", function_name_copy.value.str.val); ++ zval_dtor(&function_name_copy); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), function_name_copy.value.str.val, function_name_copy.value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", function_name_copy.value.str.val); ++ zval_dtor(&function_name_copy); ++ zend_bailout(); ++ } ++ } ++ } ++#endif + zval_dtor(&function_name_copy); + + for (i=0; itype = type; + EG(return_value_ptr_ptr) = &local_retval_ptr; + EG(active_op_array) = new_op_array; + EG(no_extensions)=1; +@@ -673,6 +709,10 @@ + return retval; + } + ++ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) ++{ ++ return (zend_eval_string_ex(str, retval_ptr, string_name, ZEND_EVAL_CODE TSRMLS_CC)); ++} + + void execute_new_code(TSRMLS_D) + { +diff -Nura php-4.4.0/Zend/zend_execute.c hardening-patch-4.4.0-0.4.2/Zend/zend_execute.c +--- php-4.4.0/Zend/zend_execute.c 2005-06-27 08:15:48.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_execute.c 2005-09-07 18:40:29.122942936 +0200 +@@ -1042,6 +1042,7 @@ + zend_execute_data execute_data; + + /* Initialize execute_data */ ++ memset(&execute_data, 0, sizeof(execute_data)); + EX(fbc) = NULL; + EX(ce) = NULL; + EX(object).ptr = NULL; +@@ -1053,9 +1054,21 @@ + } + EX(prev_execute_data) = EG(current_execute_data); + EX(original_in_execution)=EG(in_execution); ++ EX(original_in_code_type)=EG(in_code_type); + + EG(current_execute_data) = &execute_data; + ++#if HARDENING_PATCH ++ EX(execute_depth) = 0; ++ ++ if ((op_array->type == ZEND_EVAL_CODE || op_array->created_by_eval) && EG(in_code_type) != ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } else if (op_array->type == ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_SANDBOX_CODE; ++ op_array->type = ZEND_EVAL_CODE; ++ } ++#endif ++ + EG(in_execution) = 1; + if (op_array->start_op) { + EX(opline) = op_array->start_op; +@@ -1087,6 +1100,19 @@ + } + } + ++#if HARDENING_PATCH ++ if (EX(prev_execute_data) == NULL) { ++ EX(execute_depth) = 0; ++ } else { ++ EX(execute_depth) = EX(prev_execute_data)->execute_depth + 1; ++ } ++ ++ if (EG(hphp_executor_max_depth) > 0 && EX(execute_depth) > EG(hphp_executor_max_depth)) { ++ zend_security_log(S_EXECUTOR, "Maximum execution depth of %u violated", EG(hphp_executor_max_depth)); ++ zend_bailout(); ++ } ++#endif ++ + while (1) { + #ifdef ZEND_WIN32 + if (EG(timed_out)) { +@@ -1631,6 +1657,36 @@ + if (zend_hash_find(active_function_table, function_name->value.str.val, function_name->value.str.len+1, (void **) &function)==FAILURE) { + zend_error(E_ERROR, "Call to undefined function: %s()", function_name->value.str.val); + } ++#if HARDENING_PATCH ++ if (active_function_table == EG(function_table)) { ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), function_name->value.str.val, function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", function_name->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), function_name->value.str.val, function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", function_name->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), function_name->value.str.val, function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", function_name->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), function_name->value.str.val, function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", function_name->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++#endif ++ + zval_dtor(&tmp); + EX(fbc) = function; + overloaded_function_call_cont: +@@ -1646,6 +1702,35 @@ + if (zend_hash_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { + zend_error(E_ERROR, "Unknown function: %s()", fname->value.str.val); + } ++#if HARDENING_PATCH ++ if (EX(function_state).function->type==ZEND_INTERNAL_FUNCTION) { ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++#endif + FREE_OP(EX(Ts), &EX(opline)->op1, EG(free_op1)); + zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(object).ptr, EX(ce)); + EX(object).ptr = NULL; +@@ -1816,6 +1901,7 @@ + efree(EX(Ts)); + } + EG(in_execution) = EX(original_in_execution); ++ EG(in_code_type) = EX(original_in_code_type); + EG(current_execute_data) = EX(prev_execute_data); + return; + } +@@ -2195,7 +2281,12 @@ + int dummy = 1; + zend_file_handle file_handle = {0}; + ++#if HARDENING_PATCH_INC_PROTECT ++ if (zend_is_valid_include(inc_filename) ++ && zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#else + if (zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#endif + && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) { + + file_handle.filename = inc_filename->value.str.val; +@@ -2224,6 +2315,11 @@ + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: ++#if HARDENING_PATCH_INC_PROTECT ++ if (!zend_is_valid_include(inc_filename)) { ++ break; ++ } ++#endif + new_op_array = compile_filename(EX(opline)->op2.u.constant.value.lval, inc_filename TSRMLS_CC); + break; + case ZEND_EVAL: { +diff -Nura php-4.4.0/Zend/zend_execute_globals.h hardening-patch-4.4.0-0.4.2/Zend/zend_execute_globals.h +--- php-4.4.0/Zend/zend_execute_globals.h 2005-06-06 11:30:09.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_execute_globals.h 2005-09-07 18:40:29.122942936 +0200 +@@ -60,6 +60,8 @@ + object_info object; + temp_variable *Ts; + zend_bool original_in_execution; ++ zend_uint original_in_code_type; ++ zend_uint execute_depth; + zend_op_array *op_array; + struct _zend_execute_data *prev_execute_data; + } zend_execute_data; +diff -Nura php-4.4.0/Zend/zend_extensions.c hardening-patch-4.4.0-0.4.2/Zend/zend_extensions.c +--- php-4.4.0/Zend/zend_extensions.c 2003-03-19 19:00:57.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_extensions.c 2005-09-07 18:40:29.123942784 +0200 +@@ -54,23 +54,44 @@ + return FAILURE; + } + ++ /* check if module is compiled against Hardening-Patch */ ++ if (extension_version_info->zend_extension_api_no < 1000000000) { ++ fprintf(stderr, "%s is not compiled with Hardening-Patch.\n" ++ "The Hardening-Patch version %d is installed.\n\n", ++ new_extension->name, ++ HARDENING_PATCH_ZEND_EXTENSION_API_NO); ++ DL_UNLOAD(handle); ++ return FAILURE; ++ } ++ ++ ++ /* check if module is compiled against correct Hardening-Patch version */ ++ if (extension_version_info->zend_extension_api_no != HARDENING_PATCH_ZEND_EXTENSION_API_NO) { ++ fprintf(stderr, "%s requires Hardening-Patch version %d.\n" ++ "The Hardening-Patch version %d is installed.\n\n", ++ new_extension->name, ++ extension_version_info->zend_extension_api_no, ++ HARDENING_PATCH_ZEND_EXTENSION_API_NO); ++ DL_UNLOAD(handle); ++ return FAILURE; ++ } + + /* allow extension to proclaim compatibility with any Zend version */ +- if (extension_version_info->zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) { +- if (extension_version_info->zend_extension_api_no > ZEND_EXTENSION_API_NO) { ++ if (extension_version_info->real_zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) { ++ if (extension_version_info->real_zend_extension_api_no > ZEND_EXTENSION_API_NO) { + fprintf(stderr, "%s requires Zend Engine API version %d.\n" + "The Zend Engine API version %d which is installed, is outdated.\n\n", + new_extension->name, +- extension_version_info->zend_extension_api_no, ++ extension_version_info->real_zend_extension_api_no, + ZEND_EXTENSION_API_NO); + DL_UNLOAD(handle); + return FAILURE; +- } else if (extension_version_info->zend_extension_api_no < ZEND_EXTENSION_API_NO) { ++ } else if (extension_version_info->real_zend_extension_api_no < ZEND_EXTENSION_API_NO) { + fprintf(stderr, "%s requires Zend Engine API version %d.\n" + "The Zend Engine API version %d which is installed, is newer.\n" + "Contact %s at %s for a later version of %s.\n\n", + new_extension->name, +- extension_version_info->zend_extension_api_no, ++ extension_version_info->real_zend_extension_api_no, + ZEND_EXTENSION_API_NO, + new_extension->author, + new_extension->URL, +diff -Nura php-4.4.0/Zend/zend_extensions.h hardening-patch-4.4.0-0.4.2/Zend/zend_extensions.h +--- php-4.4.0/Zend/zend_extensions.h 2005-06-06 11:44:59.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_extensions.h 2005-09-07 18:40:29.123942784 +0200 +@@ -23,6 +23,9 @@ + + #include "zend_compile.h" + ++/* Create own API version number for Hardening-Patch */ ++ ++#define HARDENING_PATCH_ZEND_EXTENSION_API_NO 1001050805 + #define ZEND_EXTENSION_API_NO 20050606 + + typedef struct _zend_extension_version_info { +@@ -30,6 +33,7 @@ + char *required_zend_version; + unsigned char thread_safe; + unsigned char debug; ++ int real_zend_extension_api_no; + } zend_extension_version_info; + + +@@ -96,7 +100,7 @@ + + + #define ZEND_EXTENSION() \ +- ZEND_EXT_API zend_extension_version_info extension_version_info = { ZEND_EXTENSION_API_NO, ZEND_VERSION, ZTS_V, ZEND_DEBUG } ++ ZEND_EXT_API zend_extension_version_info extension_version_info = { HARDENING_PATCH_ZEND_EXTENSION_API_NO, ZEND_VERSION, ZTS_V, ZEND_DEBUG, ZEND_EXTENSION_API_NO } + + #define STANDARD_ZEND_EXTENSION_PROPERTIES NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1 + #define COMPAT_ZEND_EXTENSION_PROPERTIES NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1 +diff -Nura php-4.4.0/Zend/zend_globals.h hardening-patch-4.4.0-0.4.2/Zend/zend_globals.h +--- php-4.4.0/Zend/zend_globals.h 2004-11-04 00:15:05.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_globals.h 2005-09-07 18:40:29.124942632 +0200 +@@ -163,6 +163,16 @@ + + int error_reporting; + int orig_error_reporting; ++#if HARDENING_PATCH ++ int hphp_log_syslog; ++ int hphp_log_syslog_facility; ++ int hphp_log_syslog_priority; ++ int hphp_log_sapi; ++ int hphp_log_script; ++ char *hphp_log_scriptname; ++ zend_bool hphp_log_use_x_forwarded_for; ++ long hphp_executor_max_depth; ++#endif + int exit_status; + + zend_op_array *active_op_array; +@@ -176,6 +186,7 @@ + int ticks_count; + + zend_bool in_execution; ++ zend_uint in_code_type; + zend_bool bailout_set; + zend_bool full_tables_cleanup; + +diff -Nura php-4.4.0/Zend/zend.h hardening-patch-4.4.0-0.4.2/Zend/zend.h +--- php-4.4.0/Zend/zend.h 2005-01-25 14:08:41.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend.h 2005-09-07 18:40:29.124942632 +0200 +@@ -275,9 +275,10 @@ + struct _zval_struct { + /* Variable information */ + zvalue_value value; /* value */ ++ zend_uint refcount; ++ zend_ushort flags; + zend_uchar type; /* active type */ + zend_uchar is_ref; +- zend_ushort refcount; + }; + + +@@ -338,6 +339,12 @@ + void (*ticks_function)(int ticks); + void (*on_timeout)(int seconds TSRMLS_DC); + zend_bool (*open_function)(const char *filename, struct _zend_file_handle *); ++#if HARDENING_PATCH ++ void (*security_log_function)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ int (*is_valid_include)(zval *z); ++#endif + } zend_utility_functions; + + +@@ -469,7 +476,16 @@ + extern ZEND_API void (*zend_ticks_function)(int ticks); + extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); + extern void (*zend_on_timeout)(int seconds TSRMLS_DC); ++#if HARDENING_PATCH ++extern ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++extern ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ZEND_API unsigned int zend_canary(void); ++#endif + + ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 2, 3); + +@@ -576,6 +592,11 @@ + + #define ZEND_MAX_RESERVED_RESOURCES 4 + ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#include "php_syslog.h" ++#endif ++ + #endif /* ZEND_H */ + + /* +diff -Nura php-4.4.0/Zend/zend_hash.c hardening-patch-4.4.0-0.4.2/Zend/zend_hash.c +--- php-4.4.0/Zend/zend_hash.c 2005-04-28 09:34:32.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_hash.c 2005-09-07 18:40:29.125942480 +0200 +@@ -26,6 +26,17 @@ + # include + #endif + ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int zend_hash_canary = 0x1234567; ++ zend_bool zend_hash_canary_inited = 0; ++#endif ++ ++#define CHECK_HASH_CANARY(hash) \ ++ if (zend_hash_canary != (hash)->canary) { \ ++ zend_security_log(S_MEMORY, "Zend HashTable canary was overwritten"); \ ++ exit(1); \ ++ } ++ + #define HANDLE_NUMERIC(key, length, func) { \ + register char *tmp=key; \ + \ +@@ -175,6 +186,9 @@ + { + uint i = 3; + Bucket **tmp; ++#if HARDENING_PATCH_HASH_PROTECT ++ TSRMLS_FETCH(); ++#endif + + SET_INCONSISTENT(HT_OK); + +@@ -184,6 +198,13 @@ + + ht->nTableSize = 1 << i; + ht->nTableMask = ht->nTableSize - 1; ++#if HARDENING_PATCH_HASH_PROTECT ++ if (zend_hash_canary_inited==0) { ++ zend_hash_canary = zend_canary(); ++ zend_hash_canary_inited = 1; ++ } ++ ht->canary = zend_hash_canary; ++#endif + ht->pDestructor = pDestructor; + ht->pListHead = NULL; + ht->pListTail = NULL; +@@ -259,6 +280,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -327,6 +351,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -402,6 +429,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -450,7 +480,7 @@ + IS_CONSISTENT(ht); + + if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */ +- t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); ++ t = (Bucket **) perealloc(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); + if (t) { + HANDLE_BLOCK_INTERRUPTIONS(); + ht->arBuckets = t; +@@ -460,6 +490,7 @@ + HANDLE_UNBLOCK_INTERRUPTIONS(); + return SUCCESS; + } ++ zend_error(E_ERROR, "zend_hash_do_resize - out of memory"); + return FAILURE; + } + return SUCCESS; +@@ -524,6 +555,9 @@ + ht->pInternalPointer = p->pListNext; + } + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +@@ -553,6 +587,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -579,6 +616,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -608,6 +648,9 @@ + HANDLE_BLOCK_INTERRUPTIONS(); + + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +diff -Nura php-4.4.0/Zend/zend_hash.h hardening-patch-4.4.0-0.4.2/Zend/zend_hash.h +--- php-4.4.0/Zend/zend_hash.h 2002-12-31 17:23:03.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_hash.h 2005-09-07 18:40:29.126942328 +0200 +@@ -54,6 +54,9 @@ + } Bucket; + + typedef struct _hashtable { ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int canary; ++#endif + uint nTableSize; + uint nTableMask; + uint nNumOfElements; +diff -Nura php-4.4.0/Zend/zend_ini.h hardening-patch-4.4.0-0.4.2/Zend/zend_ini.h +--- php-4.4.0/Zend/zend_ini.h 2005-01-09 18:00:16.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_ini.h 2005-09-07 18:40:29.126942328 +0200 +@@ -174,6 +174,7 @@ + /* Standard message handlers */ + BEGIN_EXTERN_C() + ZEND_API ZEND_INI_MH(OnUpdateBool); ++#define OnUpdateLong OnUpdateInt + ZEND_API ZEND_INI_MH(OnUpdateInt); + ZEND_API ZEND_INI_MH(OnUpdateReal); + ZEND_API ZEND_INI_MH(OnUpdateString); +diff -Nura php-4.4.0/Zend/zend_language_scanner.l hardening-patch-4.4.0-0.4.2/Zend/zend_language_scanner.l +--- php-4.4.0/Zend/zend_language_scanner.l 2005-03-09 16:07:19.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_language_scanner.l 2005-09-07 18:40:29.131941568 +0200 +@@ -393,6 +393,13 @@ + compilation_successful=0; + } else { + init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array->created_by_eval = 1; ++ } else { ++ op_array->created_by_eval = 0; ++ } ++#endif + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + compiler_result = zendparse(TSRMLS_C); +diff -Nura php-4.4.0/Zend/zend_language_scanner.c hardening-patch-4.4.0-0.4.2/Zend/zend_language_scanner.c +--- php-4.4.0/Zend/zend_language_scanner.c 2005-07-11 12:07:41.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_language_scanner.c 2005-09-07 18:40:29.129941872 +0200 +@@ -3121,6 +3121,13 @@ + compilation_successful=0; + } else { + init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array->created_by_eval = 1; ++ } else { ++ op_array->created_by_eval = 0; ++ } ++#endif + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + compiler_result = zendparse(TSRMLS_C); +diff -Nura php-4.4.0/Zend/zend_llist.c hardening-patch-4.4.0-0.4.2/Zend/zend_llist.c +--- php-4.4.0/Zend/zend_llist.c 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_llist.c 2005-09-07 18:40:29.131941568 +0200 +@@ -21,9 +21,34 @@ + #include "zend.h" + #include "zend_llist.h" + #include "zend_qsort.h" ++#include "zend_globals.h" ++ ++#define CHECK_LIST_CANARY(list) \ ++ if (HG(canary_3) != (list)->canary_h || HG(canary_4) != (list)->canary_t) { \ ++ zend_security_log(S_MEMORY, "linked list canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++#define CHECK_LISTELEMENT_CANARY(elem) \ ++ if (HG(canary_3) != (elem)->canary) { \ ++ zend_security_log(S_MEMORY, "linked list element canary was overwritten"); \ ++ exit(1); \ ++ } ++ + + ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ ++ if (!HG(ll_canary_inited)) { ++ HG(canary_3) = zend_canary(); ++ HG(canary_4) = zend_canary(); ++ HG(ll_canary_inited) = 1; ++ } ++ l->canary_h = HG(canary_3); ++ l->canary_t = HG(canary_4); ++#endif + l->head = NULL; + l->tail = NULL; + l->count = 0; +@@ -37,6 +62,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->prev = l->tail; + tmp->next = NULL; + if (l->tail) { +@@ -55,6 +85,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->next = l->head; + tmp->prev = NULL; + if (l->head) { +@@ -91,10 +126,20 @@ + zend_llist_element *current=l->head; + zend_llist_element *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (compare(current->data, element)) { + DEL_LLIST_ELEMENT(current, l); ++#if HARDENING_PATCH_LL_PROTECT ++ current->canary = 0; ++#endif + break; + } + current = next; +@@ -106,7 +151,14 @@ + { + zend_llist_element *current=l->head, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (l->dtor) { + l->dtor(current->data); +@@ -131,7 +183,14 @@ + zend_llist_element *old_tail; + void *data; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if ((old_tail = l->tail)) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(old_tail) ++#endif + if (l->tail->prev) { + l->tail->prev->next = NULL; + } +@@ -157,9 +216,16 @@ + { + zend_llist_element *ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(src) ++#endif + zend_llist_init(dst, src->size, src->dtor, src->persistent); + ptr = src->head; + while (ptr) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(ptr) ++#endif + zend_llist_add_element(dst, ptr->data); + ptr = ptr->next; + } +@@ -170,11 +236,21 @@ + { + zend_llist_element *element, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + element=l->head; + while (element) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + next = element->next; + if (func(element->data)) { + DEL_LLIST_ELEMENT(element, l); ++#if HARDENING_PATCH_LL_PROTECT ++ element->canary = 0; ++#endif + } + element = next; + } +@@ -185,7 +261,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data TSRMLS_CC); + } + } +@@ -197,6 +279,9 @@ + zend_llist_element **elements; + zend_llist_element *element, **ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + if (l->count <= 0) { + return; + } +@@ -206,6 +291,9 @@ + ptr = &elements[0]; + + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + *ptr++ = element; + } + +@@ -228,7 +316,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, arg TSRMLS_CC); + } + } +@@ -239,8 +333,14 @@ + zend_llist_element *element; + va_list args; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + va_start(args, num_args); + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, num_args, args TSRMLS_CC); + } + va_end(args); +@@ -249,6 +349,10 @@ + + ZEND_API int zend_llist_count(zend_llist *l) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + return l->count; + } + +@@ -256,8 +360,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->head; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -269,8 +380,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->tail; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -282,9 +400,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->next; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +@@ -296,9 +424,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->prev; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +diff -Nura php-4.4.0/Zend/zend_llist.h hardening-patch-4.4.0-0.4.2/Zend/zend_llist.h +--- php-4.4.0/Zend/zend_llist.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_llist.h 2005-09-07 18:40:29.132941416 +0200 +@@ -24,6 +24,9 @@ + #include + + typedef struct _zend_llist_element { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary; ++#endif + struct _zend_llist_element *next; + struct _zend_llist_element *prev; + char data[1]; /* Needs to always be last in the struct */ +@@ -36,6 +39,9 @@ + typedef void (*llist_apply_func_t)(void * TSRMLS_DC); + + typedef struct _zend_llist { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_h; /* head */ ++#endif + zend_llist_element *head; + zend_llist_element *tail; + size_t size; +@@ -43,6 +49,9 @@ + llist_dtor_func_t dtor; + unsigned char persistent; + zend_llist_element *traverse_ptr; ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_t; /* tail */ ++#endif + } zend_llist; + + typedef zend_llist_element* zend_llist_position; +diff -Nura php-4.4.0/Zend/zend_modules.h hardening-patch-4.4.0-0.4.2/Zend/zend_modules.h +--- php-4.4.0/Zend/zend_modules.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_modules.h 2005-09-07 18:40:29.132941416 +0200 +@@ -34,6 +34,7 @@ + ZEND_API extern unsigned char second_arg_force_ref[]; + ZEND_API extern unsigned char third_arg_force_ref[]; + ++#define HARDENING_PATCH_ZEND_MODULE_API_NO 1001050805 + #define ZEND_MODULE_API_NO 20020429 + #ifdef ZTS + #define USING_ZTS 1 +@@ -41,9 +42,9 @@ + #define USING_ZTS 0 + #endif + +-#define STANDARD_MODULE_HEADER sizeof(zend_module_entry), ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS ++#define STANDARD_MODULE_HEADER sizeof(zend_module_entry), HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS + +-#define STANDARD_MODULE_PROPERTIES_EX 0, 0, 0, NULL, 0 ++#define STANDARD_MODULE_PROPERTIES_EX 0, 0, 0, NULL, 0, ZEND_MODULE_API_NO + + #define STANDARD_MODULE_PROPERTIES \ + NULL, NULL, STANDARD_MODULE_PROPERTIES_EX +@@ -75,6 +76,7 @@ + unsigned char type; + void *handle; + int module_number; ++ unsigned int real_zend_api; + }; + + +diff -Nura php-4.4.0/Zend/zend_opcode.c hardening-patch-4.4.0-0.4.2/Zend/zend_opcode.c +--- php-4.4.0/Zend/zend_opcode.c 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_opcode.c 2005-09-07 18:40:29.133941264 +0200 +@@ -88,6 +88,9 @@ + op_array->done_pass_two = 0; + + op_array->start_op = NULL; ++#if HARDENING_PATCH ++ op_array->created_by_eval = 0; ++#endif + + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC); + } +diff -Nura php-4.4.0/Zend/zend_operators.c hardening-patch-4.4.0-0.4.2/Zend/zend_operators.c +--- php-4.4.0/Zend/zend_operators.c 2005-03-31 10:18:39.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_operators.c 2005-09-07 18:40:29.134941112 +0200 +@@ -1604,6 +1604,20 @@ + return (op->value.lval ? 1 : 0); + } + ++ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length) ++{ ++ register unsigned char *str = (unsigned char*)source; ++ register unsigned char *result = (unsigned char*)dest; ++ register unsigned char *end = str + length; ++ ++ while (str < end) { ++ *result++ = tolower((int)*str++); ++ } ++ *result = *end; ++ ++ return dest; ++} ++ + ZEND_API void zend_str_tolower(char *str, unsigned int length) + { + register char *p=str, *end=p+length; +diff -Nura php-4.4.0/Zend/zend_operators.h hardening-patch-4.4.0-0.4.2/Zend/zend_operators.h +--- php-4.4.0/Zend/zend_operators.h 2005-03-31 10:18:40.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.2/Zend/zend_operators.h 2005-09-07 18:40:29.134941112 +0200 +@@ -174,6 +174,14 @@ + #endif + + ZEND_API void zend_str_tolower(char *str, unsigned int length); ++ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length); ++ ++static inline char * ++zend_str_tolower_dup(const char *source, unsigned int length) ++{ ++ return zend_str_tolower_copy((char *)emalloc(length+1), source, length); ++} ++ + ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2); + ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3); + ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2); diff --git a/0.4.2/hardening-patch-5.0.5-0.4.2.patch b/0.4.2/hardening-patch-5.0.5-0.4.2.patch new file mode 100644 index 0000000..f7f11b5 --- /dev/null +++ b/0.4.2/hardening-patch-5.0.5-0.4.2.patch @@ -0,0 +1,6671 @@ +diff -Nura php-5.0.5/acinclude.m4 hardening-patch-5.0.5-0.4.2/acinclude.m4 +--- php-5.0.5/acinclude.m4 2005-07-26 00:31:07.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/acinclude.m4 2005-09-07 13:49:17.000000000 +0200 +@@ -1182,6 +1182,36 @@ + fi + ]) + ++dnl ++dnl Check for broken realpath() ++dnl ++dnl realpath("/etc/hosts/../passwd",XXX) should not return ++dnl "/etc/passwd" ++dnl ++AC_DEFUN([PHP_AC_BROKEN_REALPATH],[ ++ AC_CACHE_CHECK(whether realpath is broken, ac_cv_broken_realpath,[ ++ AC_TRY_RUN([ ++main() { ++ char buf[4096+1]; ++ buf[0] = 0; ++ realpath("/etc/hosts/../passwd", buf); ++ exit(strcmp(buf, "/etc/passwd")==0); ++} ++ ],[ ++ ac_cv_broken_realpath=no ++ ],[ ++ ac_cv_broken_realpath=yes ++ ],[ ++ ac_cv_broken_realpath=no ++ ]) ++ ]) ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ AC_DEFINE(PHP_BROKEN_REALPATH, 1, [Whether realpath is broken]) ++ else ++ AC_DEFINE(PHP_BROKEN_REALPATH, 0, [Whether realpath is broken]) ++ fi ++]) ++ + dnl PHP_SHARED_MODULE(module-name, object-var, build-dir, cxx) + dnl + dnl Basically sets up the link-stage for building module-name +diff -Nura php-5.0.5/configure hardening-patch-5.0.5-0.4.2/configure +--- php-5.0.5/configure 2005-09-05 13:16:17.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/configure 2005-09-07 14:19:05.000000000 +0200 +@@ -404,6 +404,16 @@ + ac_default_prefix=/usr/local + # Any additions from configure.in: + ac_help="$ac_help ++ --disable-hardening-patch-mm-protect Disable the Memory Manager protection." ++ac_help="$ac_help ++ --disable-hardening-patch-ll-protect Disable the Linked List protection." ++ac_help="$ac_help ++ --disable-hardening-patch-inc-protect Disable include/require protection." ++ac_help="$ac_help ++ --disable-hardening-patch-fmt-protect Disable format string protection." ++ac_help="$ac_help ++ --disable-hardening-patch-hash-protect Disable Zend HashTable DTOR protection." ++ac_help="$ac_help + + SAPI modules: + " +@@ -860,6 +870,8 @@ + ac_help="$ac_help + --disable-tokenizer Disable tokenizer support" + ac_help="$ac_help ++ --disable-varfilter Disable Hardening-Patch's variable filter" ++ac_help="$ac_help + --enable-wddx Enable WDDX support." + ac_help="$ac_help + --disable-xml Disable XML support." +@@ -2834,6 +2846,157 @@ + + + ++# Check whether --enable-hardening-patch-mm-protect or --disable-hardening-patch-mm-protect was given. ++if test "${enable_hardening_patch_mm_protect+set}" = set; then ++ enableval="$enable_hardening_patch_mm_protect" ++ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-ll-protect or --disable-hardening-patch-ll-protect was given. ++if test "${enable_hardening_patch_ll_protect+set}" = set; then ++ enableval="$enable_hardening_patch_ll_protect" ++ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-inc-protect or --disable-hardening-patch-inc-protect was given. ++if test "${enable_hardening_patch_inc_protect+set}" = set; then ++ enableval="$enable_hardening_patch_inc_protect" ++ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-fmt-protect or --disable-hardening-patch-fmt-protect was given. ++if test "${enable_hardening_patch_fmt_protect+set}" = set; then ++ enableval="$enable_hardening_patch_fmt_protect" ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-hash-protect or --disable-hardening-patch-hash-protect was given. ++if test "${enable_hardening_patch_hash_protect+set}" = set; then ++ enableval="$enable_hardening_patch_hash_protect" ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++ ++fi ++ ++ ++echo $ac_n "checking whether to protect the Zend Memory Manager""... $ac_c" 1>&6 ++echo "configure:2725: checking whether to protect the Zend Memory Manager" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_MM_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend Linked Lists""... $ac_c" 1>&6 ++echo "configure:2729: checking whether to protect the Zend Linked Lists" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_LL_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect include/require statements""... $ac_c" 1>&6 ++echo "configure:2733: checking whether to protect include/require statements" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_INC_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect PHP Format String functions""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect PHP Format String functions" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_FMT_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend HashTable Destructors""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect the Zend HashTable Destructors" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_HASH_PROTECT" 1>&6 ++ ++ ++cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH 1 ++EOF ++ ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 0 ++EOF ++ ++fi + + + +@@ -17473,6 +17636,62 @@ + fi + + ++ echo $ac_n "checking whether realpath is broken""... $ac_c" 1>&6 ++echo "configure:14928: checking whether realpath is broken" >&5 ++if eval "test \"`echo '$''{'ac_cv_broken_realpath'+set}'`\" = set"; then ++ echo $ac_n "(cached) $ac_c" 1>&6 ++else ++ ++ if test "$cross_compiling" = yes; then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null ++then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ echo "configure: failed program was:" >&5 ++ cat conftest.$ac_ext >&5 ++ rm -fr conftest* ++ ++ ac_cv_broken_realpath=yes ++ ++fi ++rm -fr conftest* ++fi ++ ++ ++fi ++ ++echo "$ac_t""$ac_cv_broken_realpath" 1>&6 ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 1 ++EOF ++ ++ else ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 0 ++EOF ++ ++ fi ++ ++ + echo $ac_n "checking for declared timezone""... $ac_c" 1>&6 + echo "configure:17478: checking for declared timezone" >&5 + if eval "test \"`echo '$''{'ac_cv_declared_timezone'+set}'`\" = set"; then +@@ -88634,7 +88853,7 @@ + if test "$ac_cv_crypt_blowfish" = "yes"; then + ac_result=1 + else +- ac_result=0 ++ ac_result=1 + fi + cat >> confdefs.h <&6 ++echo "configure:82041: checking whether to enable Hardening-Patch's variable filter" >&5 ++# Check whether --enable-varfilter or --disable-varfilter was given. ++if test "${enable_varfilter+set}" = set; then ++ enableval="$enable_varfilter" ++ PHP_VARFILTER=$enableval ++else ++ ++ PHP_VARFILTER=yes ++ ++ if test "$PHP_ENABLE_ALL" && test "yes" = "yes"; then ++ PHP_VARFILTER=$PHP_ENABLE_ALL ++ fi ++ ++fi ++ ++ ++ ++ext_output="yes, shared" ++ext_shared=yes ++case $PHP_VARFILTER in ++shared,*) ++ PHP_VARFILTER=`echo "$PHP_VARFILTER"|sed 's/^shared,//'` ++ ;; ++shared) ++ PHP_VARFILTER=yes ++ ;; ++no) ++ ext_output=no ++ ext_shared=no ++ ;; ++*) ++ ext_output=yes ++ ext_shared=no ++ ;; ++esac ++ ++ ++ ++echo "$ac_t""$ext_output" 1>&6 ++ ++ ++ ++ ++if test "$PHP_VARFILTER" != "no"; then ++ cat >> confdefs.h <<\EOF ++#define HAVE_VARFILTER 1 ++EOF ++ ++ ++ ext_builddir=ext/varfilter ++ ext_srcdir=$abs_srcdir/ext/varfilter ++ ++ ac_extra= ++ ++ if test "$ext_shared" != "shared" && test "$ext_shared" != "yes" && test "" != "cli"; then ++ ++ ++ ++ case ext/varfilter in ++ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;; ++ /*) ac_srcdir=`echo "ext/varfilter"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;; ++ *) ac_srcdir="$abs_srcdir/ext/varfilter/"; ac_bdir="ext/varfilter/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;; ++ esac ++ ++ ++ ++ b_c_pre=$php_c_pre ++ b_cxx_pre=$php_cxx_pre ++ b_c_meta=$php_c_meta ++ b_cxx_meta=$php_cxx_meta ++ b_c_post=$php_c_post ++ b_cxx_post=$php_cxx_post ++ b_lo=$php_lo ++ ++ ++ old_IFS=$IFS ++ for ac_src in varfilter.c; do ++ ++ IFS=. ++ set $ac_src ++ ac_obj=$1 ++ IFS=$old_IFS ++ ++ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo" ++ ++ case $ac_src in ++ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;; ++ *.cpp) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;; ++ esac ++ ++ cat >>Makefile.objects<>Makefile.objects<>Makefile.objects<> confdefs.h <>Makefile.objects<>Makefile.objects<&6 +@@ -106554,7 +107032,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + network.c php_open_temporary_file.c php_logos.c \ +- output.c ; do ++ output.c hardening_patch.c ; do + + IFS=. + set $ac_src +@@ -106795,7 +107273,7 @@ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ + zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ +- zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c; do ++ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_canary.c; do + + IFS=. + set $ac_src +diff -Nura php-5.0.5/configure.in hardening-patch-5.0.5-0.4.2/configure.in +--- php-5.0.5/configure.in 2005-09-05 12:41:12.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/configure.in 2005-09-07 13:49:17.000000000 +0200 +@@ -247,7 +247,7 @@ + sinclude(Zend/acinclude.m4) + sinclude(Zend/Zend.m4) + sinclude(TSRM/tsrm.m4) +- ++sinclude(main/hardening_patch.m4) + + + divert(2) +@@ -631,6 +631,7 @@ + AC_FUNC_ALLOCA + dnl PHP_AC_BROKEN_SPRINTF + dnl PHP_AC_BROKEN_SNPRINTF ++PHP_AC_BROKEN_REALPATH + PHP_DECLARED_TIMEZONE + PHP_TIME_R_TYPE + PHP_READDIR_R_TYPE +@@ -1284,7 +1285,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + network.c php_open_temporary_file.c php_logos.c \ +- output.c ) ++ output.c hardening_patch.c ) + + PHP_ADD_SOURCES(main/streams, streams.c cast.c memory.c filter.c \ + plain_wrapper.c userspace.c transports.c xp_socket.c mmap.c) +@@ -1311,7 +1312,7 @@ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ + zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ +- zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c) ++ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_canary.c ) + + if test -r "$abs_srcdir/Zend/zend_objects.c"; then + PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_mm.c \ +diff -Nura php-5.0.5/ext/fbsql/php_fbsql.c hardening-patch-5.0.5-0.4.2/ext/fbsql/php_fbsql.c +--- php-5.0.5/ext/fbsql/php_fbsql.c 2005-02-09 20:32:45.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/ext/fbsql/php_fbsql.c 2005-09-07 13:49:17.000000000 +0200 +@@ -1852,8 +1852,24 @@ + } + else if (fbcmdErrorsFound(md)) + { ++#if HARDENING_PATCH ++ char* query_copy; ++ int i; ++#endif + FBCErrorMetaData* emd = fbcdcErrorMetaData(c, md); + char* emg = fbcemdAllErrorMessages(emd); ++#if HARDENING_PATCH ++ query_copy=estrdup(query_copy); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "fbsql error: %s - query: %s", emg, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ free(emg); ++ fbcemdRelease(emd); ++ result = 0; ++ zend_bailout(); ++ } ++#endif + if (FB_SQL_G(generateWarnings)) + { + if (emg) +diff -Nura php-5.0.5/ext/mysql/php_mysql.c hardening-patch-5.0.5-0.4.2/ext/mysql/php_mysql.c +--- php-5.0.5/ext/mysql/php_mysql.c 2005-04-08 00:23:28.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/ext/mysql/php_mysql.c 2005-09-07 13:49:17.000000000 +0200 +@@ -1224,6 +1224,8 @@ + { + php_mysql_conn *mysql; + MYSQL_RES *mysql_result; ++ char *copy_query; ++ int i; + + ZEND_FETCH_RESOURCE2(mysql, php_mysql_conn *, mysql_link, link_id, "MySQL-Link", le_link, le_plink); + +@@ -1274,6 +1276,13 @@ + php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #else +@@ -1284,6 +1293,13 @@ + php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #endif +diff -Nura php-5.0.5/ext/mysqli/mysqli_nonapi.c hardening-patch-5.0.5-0.4.2/ext/mysqli/mysqli_nonapi.c +--- php-5.0.5/ext/mysqli/mysqli_nonapi.c 2005-08-06 18:56:06.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/ext/mysqli/mysqli_nonapi.c 2005-09-07 13:49:17.000000000 +0200 +@@ -229,6 +229,17 @@ + if (mysql_real_query(mysql->mysql, query, query_len)) { + char s_error[MYSQL_ERRMSG_SIZE], s_sqlstate[SQLSTATE_LENGTH+1]; + unsigned int s_errno; ++#if HARDENING_PATCH ++ char *query_copy = estrdup(query); ++ int i; ++ ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "MySQLi error: %s - query: %s", mysql->mysql->net.last_errno, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } ++#endif + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); + + /* we have to save error information, cause +@@ -278,6 +289,17 @@ + MYSQLI_DISABLE_MQ; + + if (mysql_real_query(mysql->mysql, query, query_len)) { ++#if HARDENING_PATCH ++ char *query_copy = estrdup(query); ++ int i; ++ ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "MySQLi error: %s - query: %s", mysql->mysql->net.last_errno, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } ++#endif + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); + RETURN_FALSE; + } +diff -Nura php-5.0.5/ext/pgsql/pgsql.c hardening-patch-5.0.5-0.4.2/ext/pgsql/pgsql.c +--- php-5.0.5/ext/pgsql/pgsql.c 2005-07-05 14:47:06.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/ext/pgsql/pgsql.c 2005-09-07 13:49:17.000000000 +0200 +@@ -1080,10 +1080,28 @@ + case PGRES_EMPTY_QUERY: + case PGRES_BAD_RESPONSE: + case PGRES_NONFATAL_ERROR: +- case PGRES_FATAL_ERROR: +- PHP_PQ_ERROR("Query failed: %s", pgsql); +- PQclear(pgsql_result); +- RETURN_FALSE; ++ case PGRES_FATAL_ERROR: ++ { ++#if HARDENING_PATCH ++ int i; ++ char *query_copy; ++#endif ++ char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); ++ PQclear(pgsql_result); ++#if HARDENING_PATCH ++ query_copy = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "PgSQL error: %s - query: %s", msgbuf, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ efree(msgbuf); ++ zend_bailout(); ++ } ++#endif ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Query failed: %s", msgbuf); ++ efree(msgbuf); ++ RETURN_FALSE; ++ } + break; + case PGRES_COMMAND_OK: /* successful command that did not return rows */ + default: +diff -Nura php-5.0.5/ext/sqlite/sqlite.c hardening-patch-5.0.5-0.4.2/ext/sqlite/sqlite.c +--- php-5.0.5/ext/sqlite/sqlite.c 2005-06-07 17:38:37.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/ext/sqlite/sqlite.c 2005-09-07 13:49:17.000000000 +0200 +@@ -1481,6 +1481,19 @@ + db->last_err_code = ret; + + if (ret != SQLITE_OK) { ++#if HARDENING_PATCH ++ char *query_copy; ++ int i; ++ ++ query_copy = estrdup(sql); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "SQLite error: %s - query: %s", errtext, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ sqlite_freemem(errtext); ++ zend_bailout(); ++ } ++#endif + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext); + sqlite_freemem(errtext); + goto terminate; +diff -Nura php-5.0.5/ext/standard/array.c hardening-patch-5.0.5-0.4.2/ext/standard/array.c +--- php-5.0.5/ext/standard/array.c 2005-09-01 14:01:01.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/array.c 2005-09-07 13:49:17.000000000 +0200 +@@ -1283,6 +1283,32 @@ + } + } + } ++ ++ if (var_name[0] == 'H') { ++ if ((strcmp(var_name, "HTTP_GET_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_FILES")==0)|| ++ (strcmp(var_name, "HTTP_ENV_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(var_name, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(var_name, "HTTP_RAW_POST_DATA")==0)) { ++ return 0; ++ } ++ } else if (var_name[0] == '_') { ++ if ((strcmp(var_name, "_COOKIE")==0)|| ++ (strcmp(var_name, "_ENV")==0)|| ++ (strcmp(var_name, "_FILES")==0)|| ++ (strcmp(var_name, "_GET")==0)|| ++ (strcmp(var_name, "_POST")==0)|| ++ (strcmp(var_name, "_REQUEST")==0)|| ++ (strcmp(var_name, "_SESSION")==0)|| ++ (strcmp(var_name, "_SERVER")==0)) { ++ return 0; ++ } ++ } else if (strcmp(var_name, "GLOBALS")==0) { ++ return 0; ++ } + + return 1; + } +diff -Nura php-5.0.5/ext/standard/basic_functions.c hardening-patch-5.0.5-0.4.2/ext/standard/basic_functions.c +--- php-5.0.5/ext/standard/basic_functions.c 2005-08-21 20:36:33.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/basic_functions.c 2005-09-07 14:19:05.000000000 +0200 +@@ -142,12 +142,14 @@ + typedef struct _php_shutdown_function_entry { + zval **arguments; + int arg_count; ++ zend_bool created_by_eval; + } php_shutdown_function_entry; + + typedef struct _user_tick_function_entry { + zval **arguments; + int arg_count; + int calling; ++ zend_bool created_by_eval; + } user_tick_function_entry; + + /* some prototypes for local functions */ +@@ -189,6 +191,8 @@ + PHP_FE(get_html_translation_table, NULL) + PHP_FE(sha1, NULL) + PHP_FE(sha1_file, NULL) ++ PHP_FE(sha256, NULL) ++ PHP_FE(sha256_file, NULL) + PHP_NAMED_FE(md5,php_if_md5, NULL) + PHP_NAMED_FE(md5_file,php_if_md5_file, NULL) + PHP_NAMED_FE(crc32,php_if_crc32, NULL) +@@ -616,7 +620,7 @@ + PHP_FALIAS(socket_get_status, stream_get_meta_data, NULL) + + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +- PHP_FE(realpath, NULL) ++ PHP_STATIC_FE("realpath", zif_real_path, NULL) + #endif + + #ifdef HAVE_FNMATCH +@@ -2095,6 +2099,13 @@ + { + zval retval; + char *function_name = NULL; ++#if HARDENING_PATCH ++ zend_uint orig_code_type = EG(in_code_type); ++ ++ if (shutdown_function_entry->created_by_eval) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } ++#endif + + if (!zend_is_callable(shutdown_function_entry->arguments[0], 0, &function_name)) { + php_error(E_WARNING, "(Registered shutdown functions) Unable to call %s() - function does not exist", function_name); +@@ -2110,6 +2121,9 @@ + if (function_name) { + efree(function_name); + } ++#if HARDENING_PATCH ++ EG(in_code_type) = orig_code_type; ++#endif + return 0; + } + +@@ -2117,6 +2131,13 @@ + { + zval retval; + zval *function = tick_fe->arguments[0]; ++#if HARDENING_PATCH ++ zend_uint orig_code_type = EG(in_code_type); ++ ++ if (tick_fe->created_by_eval) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } ++#endif + + /* Prevent reentrant calls to the same user ticks function */ + if (! tick_fe->calling) { +@@ -2148,6 +2169,9 @@ + + tick_fe->calling = 0; + } ++#if HARDENING_PATCH ++ EG(in_code_type) = orig_code_type; ++#endif + } + + static void run_user_tick_functions(int tick_count) +@@ -2211,6 +2235,13 @@ + } + + shutdown_function_entry.arguments = (zval **) safe_emalloc(sizeof(zval *), shutdown_function_entry.arg_count, 0); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ shutdown_function_entry.created_by_eval = 1; ++ } else { ++ shutdown_function_entry.created_by_eval = 0; ++ } ++#endif + + if (zend_get_parameters_array(ht, shutdown_function_entry.arg_count, shutdown_function_entry.arguments) == FAILURE) { + RETURN_FALSE; +@@ -2794,6 +2825,13 @@ + } + + tick_fe.arguments = (zval **) safe_emalloc(sizeof(zval *), tick_fe.arg_count, 0); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ tick_fe.created_by_eval = 1; ++ } else { ++ tick_fe.created_by_eval = 0; ++ } ++#endif + + if (zend_get_parameters_array(ht, tick_fe.arg_count, tick_fe.arguments) == FAILURE) { + RETURN_FALSE; +@@ -3082,6 +3120,35 @@ + memcpy(new_key, prefix, prefix_len); + memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + ++ if (new_key[0] == 'H') { ++ if ((strcmp(new_key, "HTTP_GET_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_FILES")==0)|| ++ (strcmp(new_key, "HTTP_ENV_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(new_key, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(new_key, "HTTP_RAW_POST_DATA")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (new_key[0] == '_') { ++ if ((strcmp(new_key, "_COOKIE")==0)|| ++ (strcmp(new_key, "_ENV")==0)|| ++ (strcmp(new_key, "_FILES")==0)|| ++ (strcmp(new_key, "_GET")==0)|| ++ (strcmp(new_key, "_POST")==0)|| ++ (strcmp(new_key, "_REQUEST")==0)|| ++ (strcmp(new_key, "_SESSION")==0)|| ++ (strcmp(new_key, "_SERVER")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (strcmp(new_key, "GLOBALS")==0) { ++ efree(new_key); ++ return 0; ++ } ++ + zend_hash_del(&EG(symbol_table), new_key, new_key_len); + ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, (*var)->refcount+1, 0); + +diff -Nura php-5.0.5/ext/standard/config.m4 hardening-patch-5.0.5-0.4.2/ext/standard/config.m4 +--- php-5.0.5/ext/standard/config.m4 2004-12-30 08:04:11.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/config.m4 2005-09-07 14:19:05.000000000 +0200 +@@ -187,7 +187,7 @@ + if test "$ac_cv_crypt_blowfish" = "yes"; then + ac_result=1 + else +- ac_result=0 ++ ac_result=1 + fi + AC_DEFINE_UNQUOTED(PHP_BLOWFISH_CRYPT, $ac_result, [Whether the system supports BlowFish salt]) + ]) +@@ -469,6 +469,6 @@ + incomplete_class.c url_scanner_ex.c ftp_fopen_wrapper.c \ + http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \ + var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c \ +- filters.c proc_open.c sunfuncs.c streamsfuncs.c http.c) ++ filters.c proc_open.c sunfuncs.c streamsfuncs.c http.c sha256.c crypt_blowfish.c ) + + PHP_ADD_MAKEFILE_FRAGMENT +diff -Nura php-5.0.5/ext/standard/config.w32 hardening-patch-5.0.5-0.4.2/ext/standard/config.w32 +--- php-5.0.5/ext/standard/config.w32 2003-12-06 17:04:33.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/config.w32 2005-09-07 14:19:05.000000000 +0200 +@@ -14,5 +14,5 @@ + url_scanner_ex.c ftp_fopen_wrapper.c http_fopen_wrapper.c \ + php_fopen_wrapper.c credits.c css.c var_unserializer.c ftok.c sha1.c \ + user_filters.c uuencode.c filters.c proc_open.c sunfuncs.c \ +- streamsfuncs.c http.c", false /* never shared */); ++ streamsfuncs.c http.c sha256.c crypt_blowfish.c", false /* never shared */); + +diff -Nura php-5.0.5/ext/standard/crypt_blowfish.c hardening-patch-5.0.5-0.4.2/ext/standard/crypt_blowfish.c +--- php-5.0.5/ext/standard/crypt_blowfish.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/crypt_blowfish.c 2005-09-07 14:19:05.000000000 +0200 +@@ -0,0 +1,748 @@ ++/* ++ * This code comes from John the Ripper password cracker, with reentrant ++ * and crypt(3) interfaces added, but optimizations specific to password ++ * cracking removed. ++ * ++ * Written by Solar Designer in 1998-2002 and ++ * placed in the public domain. ++ * ++ * There's absolutely no warranty. ++ * ++ * It is my intent that you should be able to use this on your system, ++ * as a part of a software package, or anywhere else to improve security, ++ * ensure compatibility, or for any other purpose. I would appreciate ++ * it if you give credit where it is due and keep your modifications in ++ * the public domain as well, but I don't require that in order to let ++ * you place this code and any modifications you make under a license ++ * of your choice. ++ * ++ * This implementation is compatible with OpenBSD bcrypt.c (version 2a) ++ * by Niels Provos , and uses some of his ++ * ideas. The password hashing algorithm was designed by David Mazieres ++ * . ++ * ++ * There's a paper on the algorithm that explains its design decisions: ++ * ++ * http://www.usenix.org/events/usenix99/provos.html ++ * ++ * Some of the tricks in BF_ROUND might be inspired by Eric Young's ++ * Blowfish library (I can't be sure if I would think of something if I ++ * hadn't seen his code). ++ */ ++ ++#include ++ ++#include ++#ifndef __set_errno ++#define __set_errno(val) errno = (val) ++#endif ++ ++#undef __CONST ++#ifdef __GNUC__ ++#define __CONST __const ++#else ++#define __CONST ++#endif ++ ++#ifdef __i386__ ++#define BF_ASM 0 ++#define BF_SCALE 1 ++#elif defined(__alpha__) || defined(__hppa__) ++#define BF_ASM 0 ++#define BF_SCALE 1 ++#else ++#define BF_ASM 0 ++#define BF_SCALE 0 ++#endif ++ ++typedef unsigned int BF_word; ++ ++/* Number of Blowfish rounds, this is also hardcoded into a few places */ ++#define BF_N 16 ++ ++typedef BF_word BF_key[BF_N + 2]; ++ ++typedef struct { ++ BF_word S[4][0x100]; ++ BF_key P; ++} BF_ctx; ++ ++/* ++ * Magic IV for 64 Blowfish encryptions that we do at the end. ++ * The string is "OrpheanBeholderScryDoubt" on big-endian. ++ */ ++static BF_word BF_magic_w[6] = { ++ 0x4F727068, 0x65616E42, 0x65686F6C, ++ 0x64657253, 0x63727944, 0x6F756274 ++}; ++ ++/* ++ * P-box and S-box tables initialized with digits of Pi. ++ */ ++static BF_ctx BF_init_state = { ++ { ++ { ++ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, ++ 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, ++ 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, ++ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, ++ 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, ++ 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, ++ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, ++ 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, ++ 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, ++ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, ++ 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, ++ 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, ++ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, ++ 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, ++ 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, ++ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, ++ 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, ++ 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, ++ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, ++ 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, ++ 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, ++ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, ++ 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, ++ 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, ++ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, ++ 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, ++ 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, ++ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, ++ 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, ++ 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, ++ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, ++ 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, ++ 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, ++ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, ++ 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, ++ 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, ++ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, ++ 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, ++ 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, ++ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, ++ 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, ++ 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, ++ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, ++ 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, ++ 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, ++ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, ++ 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, ++ 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, ++ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, ++ 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, ++ 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, ++ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, ++ 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, ++ 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, ++ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, ++ 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, ++ 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, ++ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, ++ 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, ++ 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, ++ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, ++ 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, ++ 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, ++ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a ++ }, { ++ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, ++ 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, ++ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, ++ 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, ++ 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, ++ 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, ++ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, ++ 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, ++ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, ++ 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, ++ 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, ++ 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, ++ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, ++ 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, ++ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, ++ 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, ++ 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, ++ 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, ++ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, ++ 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, ++ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, ++ 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, ++ 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, ++ 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, ++ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, ++ 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, ++ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, ++ 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, ++ 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, ++ 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, ++ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, ++ 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, ++ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, ++ 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, ++ 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, ++ 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, ++ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, ++ 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, ++ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, ++ 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, ++ 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, ++ 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, ++ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, ++ 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, ++ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, ++ 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, ++ 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, ++ 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, ++ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, ++ 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, ++ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, ++ 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, ++ 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, ++ 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, ++ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, ++ 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, ++ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, ++ 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, ++ 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, ++ 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, ++ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, ++ 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, ++ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, ++ 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 ++ }, { ++ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, ++ 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, ++ 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, ++ 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, ++ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, ++ 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, ++ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, ++ 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, ++ 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, ++ 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, ++ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, ++ 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, ++ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, ++ 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, ++ 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, ++ 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, ++ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, ++ 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, ++ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, ++ 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, ++ 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, ++ 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, ++ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, ++ 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, ++ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, ++ 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, ++ 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, ++ 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, ++ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, ++ 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, ++ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, ++ 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, ++ 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, ++ 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, ++ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, ++ 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, ++ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, ++ 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, ++ 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, ++ 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, ++ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, ++ 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, ++ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, ++ 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, ++ 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, ++ 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, ++ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, ++ 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, ++ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, ++ 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, ++ 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, ++ 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, ++ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, ++ 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, ++ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, ++ 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, ++ 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, ++ 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, ++ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, ++ 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, ++ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, ++ 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, ++ 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, ++ 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 ++ }, { ++ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, ++ 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, ++ 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, ++ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, ++ 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, ++ 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, ++ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, ++ 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, ++ 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, ++ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, ++ 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, ++ 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, ++ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, ++ 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, ++ 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, ++ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, ++ 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, ++ 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, ++ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, ++ 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, ++ 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, ++ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, ++ 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, ++ 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, ++ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, ++ 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, ++ 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, ++ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, ++ 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, ++ 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, ++ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, ++ 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, ++ 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, ++ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, ++ 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, ++ 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, ++ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, ++ 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, ++ 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, ++ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, ++ 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, ++ 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, ++ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, ++ 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, ++ 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, ++ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, ++ 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, ++ 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, ++ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, ++ 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, ++ 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, ++ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, ++ 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, ++ 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, ++ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, ++ 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, ++ 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, ++ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, ++ 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, ++ 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, ++ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, ++ 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, ++ 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, ++ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 ++ } ++ }, { ++ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, ++ 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, ++ 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, ++ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, ++ 0x9216d5d9, 0x8979fb1b ++ } ++}; ++ ++static unsigned char BF_itoa64[64 + 1] = ++ "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; ++ ++static unsigned char BF_atoi64[0x60] = { ++ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, ++ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64, ++ 64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ++ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64, ++ 64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, ++ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 ++}; ++ ++/* ++ * This may be optimized out if built with function inlining and no BF_ASM. ++ */ ++static void clean(void *data, int size) ++{ ++#if BF_ASM ++ extern void _BF_clean(void *data); ++#endif ++ memset(data, 0, size); ++#if BF_ASM ++ _BF_clean(data); ++#endif ++} ++ ++#define BF_safe_atoi64(dst, src) \ ++{ \ ++ tmp = (unsigned char)(src); \ ++ if (tmp == '$') break; \ ++ if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ ++ tmp = BF_atoi64[tmp]; \ ++ if (tmp > 63) return -1; \ ++ (dst) = tmp; \ ++} ++ ++static int BF_decode(BF_word *dst, __CONST char *src, int size) ++{ ++ unsigned char *dptr = (unsigned char *)dst; ++ unsigned char *end = dptr + size; ++ unsigned char *sptr = (unsigned char *)src; ++ unsigned int tmp, c1, c2, c3, c4; ++ ++ do { ++ BF_safe_atoi64(c1, *sptr++); ++ BF_safe_atoi64(c2, *sptr++); ++ *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4); ++ if (dptr >= end) break; ++ ++ BF_safe_atoi64(c3, *sptr++); ++ *dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2); ++ if (dptr >= end) break; ++ ++ BF_safe_atoi64(c4, *sptr++); ++ *dptr++ = ((c3 & 0x03) << 6) | c4; ++ } while (dptr < end); ++ ++ while (dptr < end) ++ *dptr++ = 0; ++ ++ return 0; ++} ++ ++static void BF_encode(char *dst, __CONST BF_word *src, int size) ++{ ++ unsigned char *sptr = (unsigned char *)src; ++ unsigned char *end = sptr + size; ++ unsigned char *dptr = (unsigned char *)dst; ++ unsigned int c1, c2; ++ ++ do { ++ c1 = *sptr++; ++ *dptr++ = BF_itoa64[c1 >> 2]; ++ c1 = (c1 & 0x03) << 4; ++ if (sptr >= end) { ++ *dptr++ = BF_itoa64[c1]; ++ break; ++ } ++ ++ c2 = *sptr++; ++ c1 |= c2 >> 4; ++ *dptr++ = BF_itoa64[c1]; ++ c1 = (c2 & 0x0f) << 2; ++ if (sptr >= end) { ++ *dptr++ = BF_itoa64[c1]; ++ break; ++ } ++ ++ c2 = *sptr++; ++ c1 |= c2 >> 6; ++ *dptr++ = BF_itoa64[c1]; ++ *dptr++ = BF_itoa64[c2 & 0x3f]; ++ } while (sptr < end); ++} ++ ++static void BF_swap(BF_word *x, int count) ++{ ++ static int endianness_check = 1; ++ char *is_little_endian = (char *)&endianness_check; ++ BF_word tmp; ++ ++ if (*is_little_endian) ++ do { ++ tmp = *x; ++ tmp = (tmp << 16) | (tmp >> 16); ++ *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF); ++ } while (--count); ++} ++ ++#if BF_SCALE ++/* Architectures which can shift addresses left by 2 bits with no extra cost */ ++#define BF_ROUND(L, R, N) \ ++ tmp1 = L & 0xFF; \ ++ tmp2 = L >> 8; \ ++ tmp2 &= 0xFF; \ ++ tmp3 = L >> 16; \ ++ tmp3 &= 0xFF; \ ++ tmp4 = L >> 24; \ ++ tmp1 = data.ctx.S[3][tmp1]; \ ++ tmp2 = data.ctx.S[2][tmp2]; \ ++ tmp3 = data.ctx.S[1][tmp3]; \ ++ tmp3 += data.ctx.S[0][tmp4]; \ ++ tmp3 ^= tmp2; \ ++ R ^= data.ctx.P[N + 1]; \ ++ tmp3 += tmp1; \ ++ R ^= tmp3; ++#else ++/* Architectures with no complicated addressing modes supported */ ++#define BF_INDEX(S, i) \ ++ (*((BF_word *)(((unsigned char *)S) + (i)))) ++#define BF_ROUND(L, R, N) \ ++ tmp1 = L & 0xFF; \ ++ tmp1 <<= 2; \ ++ tmp2 = L >> 6; \ ++ tmp2 &= 0x3FC; \ ++ tmp3 = L >> 14; \ ++ tmp3 &= 0x3FC; \ ++ tmp4 = L >> 22; \ ++ tmp4 &= 0x3FC; \ ++ tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \ ++ tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \ ++ tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \ ++ tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \ ++ tmp3 ^= tmp2; \ ++ R ^= data.ctx.P[N + 1]; \ ++ tmp3 += tmp1; \ ++ R ^= tmp3; ++#endif ++ ++/* ++ * Encrypt one block, BF_N is hardcoded here. ++ */ ++#define BF_ENCRYPT \ ++ L ^= data.ctx.P[0]; \ ++ BF_ROUND(L, R, 0); \ ++ BF_ROUND(R, L, 1); \ ++ BF_ROUND(L, R, 2); \ ++ BF_ROUND(R, L, 3); \ ++ BF_ROUND(L, R, 4); \ ++ BF_ROUND(R, L, 5); \ ++ BF_ROUND(L, R, 6); \ ++ BF_ROUND(R, L, 7); \ ++ BF_ROUND(L, R, 8); \ ++ BF_ROUND(R, L, 9); \ ++ BF_ROUND(L, R, 10); \ ++ BF_ROUND(R, L, 11); \ ++ BF_ROUND(L, R, 12); \ ++ BF_ROUND(R, L, 13); \ ++ BF_ROUND(L, R, 14); \ ++ BF_ROUND(R, L, 15); \ ++ tmp4 = R; \ ++ R = L; \ ++ L = tmp4 ^ data.ctx.P[BF_N + 1]; ++ ++#if BF_ASM ++#define BF_body() \ ++ _BF_body_r(&data.ctx); ++#else ++#define BF_body() \ ++ L = R = 0; \ ++ ptr = data.ctx.P; \ ++ do { \ ++ ptr += 2; \ ++ BF_ENCRYPT; \ ++ *(ptr - 2) = L; \ ++ *(ptr - 1) = R; \ ++ } while (ptr < &data.ctx.P[BF_N + 2]); \ ++\ ++ ptr = data.ctx.S[0]; \ ++ do { \ ++ ptr += 2; \ ++ BF_ENCRYPT; \ ++ *(ptr - 2) = L; \ ++ *(ptr - 1) = R; \ ++ } while (ptr < &data.ctx.S[3][0xFF]); ++#endif ++ ++static void BF_set_key(__CONST char *key, BF_key expanded, BF_key initial) ++{ ++ __CONST char *ptr = key; ++ int i, j; ++ BF_word tmp; ++ ++ for (i = 0; i < BF_N + 2; i++) { ++ tmp = 0; ++ for (j = 0; j < 4; j++) { ++ tmp <<= 8; ++ tmp |= *ptr; ++ ++ if (!*ptr) ptr = key; else ptr++; ++ } ++ ++ expanded[i] = tmp; ++ initial[i] = BF_init_state.P[i] ^ tmp; ++ } ++} ++ ++char *_crypt_blowfish_rn(__CONST char *key, __CONST char *setting, ++ char *output, int size) ++{ ++#if BF_ASM ++ extern void _BF_body_r(BF_ctx *ctx); ++#endif ++ struct { ++ BF_ctx ctx; ++ BF_key expanded_key; ++ union { ++ BF_word salt[4]; ++ BF_word output[6]; ++ } binary; ++ } data; ++ BF_word L, R; ++ BF_word tmp1, tmp2, tmp3, tmp4; ++ BF_word *ptr; ++ BF_word count; ++ int i; ++ ++ if (size < 7 + 22 + 31 + 1) { ++ __set_errno(ERANGE); ++ return NULL; ++ } ++ ++ if (setting[0] != '$' || ++ setting[1] != '2' || ++ setting[2] != 'a' || ++ setting[3] != '$' || ++ setting[4] < '0' || setting[4] > '3' || ++ setting[5] < '0' || setting[5] > '9' || ++ setting[6] != '$') { ++ __set_errno(EINVAL); ++ return NULL; ++ } ++ ++ count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); ++ if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16)) { ++ clean(data.binary.salt, sizeof(data.binary.salt)); ++ __set_errno(EINVAL); ++ return NULL; ++ } ++ ++ BF_swap(data.binary.salt, 4); ++ ++ BF_set_key(key, data.expanded_key, data.ctx.P); ++ ++ memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); ++ ++ L = R = 0; ++ for (i = 0; i < BF_N + 2; i += 2) { ++ L ^= data.binary.salt[i & 2]; ++ R ^= data.binary.salt[(i & 2) + 1]; ++ BF_ENCRYPT; ++ data.ctx.P[i] = L; ++ data.ctx.P[i + 1] = R; ++ } ++ ++ ptr = data.ctx.S[0]; ++ do { ++ ptr += 4; ++ L ^= data.binary.salt[(BF_N + 2) & 3]; ++ R ^= data.binary.salt[(BF_N + 3) & 3]; ++ BF_ENCRYPT; ++ *(ptr - 4) = L; ++ *(ptr - 3) = R; ++ ++ L ^= data.binary.salt[(BF_N + 4) & 3]; ++ R ^= data.binary.salt[(BF_N + 5) & 3]; ++ BF_ENCRYPT; ++ *(ptr - 2) = L; ++ *(ptr - 1) = R; ++ } while (ptr < &data.ctx.S[3][0xFF]); ++ ++ do { ++ data.ctx.P[0] ^= data.expanded_key[0]; ++ data.ctx.P[1] ^= data.expanded_key[1]; ++ data.ctx.P[2] ^= data.expanded_key[2]; ++ data.ctx.P[3] ^= data.expanded_key[3]; ++ data.ctx.P[4] ^= data.expanded_key[4]; ++ data.ctx.P[5] ^= data.expanded_key[5]; ++ data.ctx.P[6] ^= data.expanded_key[6]; ++ data.ctx.P[7] ^= data.expanded_key[7]; ++ data.ctx.P[8] ^= data.expanded_key[8]; ++ data.ctx.P[9] ^= data.expanded_key[9]; ++ data.ctx.P[10] ^= data.expanded_key[10]; ++ data.ctx.P[11] ^= data.expanded_key[11]; ++ data.ctx.P[12] ^= data.expanded_key[12]; ++ data.ctx.P[13] ^= data.expanded_key[13]; ++ data.ctx.P[14] ^= data.expanded_key[14]; ++ data.ctx.P[15] ^= data.expanded_key[15]; ++ data.ctx.P[16] ^= data.expanded_key[16]; ++ data.ctx.P[17] ^= data.expanded_key[17]; ++ ++ BF_body(); ++ ++ tmp1 = data.binary.salt[0]; ++ tmp2 = data.binary.salt[1]; ++ tmp3 = data.binary.salt[2]; ++ tmp4 = data.binary.salt[3]; ++ data.ctx.P[0] ^= tmp1; ++ data.ctx.P[1] ^= tmp2; ++ data.ctx.P[2] ^= tmp3; ++ data.ctx.P[3] ^= tmp4; ++ data.ctx.P[4] ^= tmp1; ++ data.ctx.P[5] ^= tmp2; ++ data.ctx.P[6] ^= tmp3; ++ data.ctx.P[7] ^= tmp4; ++ data.ctx.P[8] ^= tmp1; ++ data.ctx.P[9] ^= tmp2; ++ data.ctx.P[10] ^= tmp3; ++ data.ctx.P[11] ^= tmp4; ++ data.ctx.P[12] ^= tmp1; ++ data.ctx.P[13] ^= tmp2; ++ data.ctx.P[14] ^= tmp3; ++ data.ctx.P[15] ^= tmp4; ++ data.ctx.P[16] ^= tmp1; ++ data.ctx.P[17] ^= tmp2; ++ ++ BF_body(); ++ } while (--count); ++ ++ for (i = 0; i < 6; i += 2) { ++ L = BF_magic_w[i]; ++ R = BF_magic_w[i + 1]; ++ ++ count = 64; ++ do { ++ BF_ENCRYPT; ++ } while (--count); ++ ++ data.binary.output[i] = L; ++ data.binary.output[i + 1] = R; ++ } ++ ++ memcpy(output, setting, 7 + 22 - 1); ++ output[7 + 22 - 1] = BF_itoa64[(int) ++ BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30]; ++ ++/* This has to be bug-compatible with the original implementation, so ++ * only encode 23 of the 24 bytes. :-) */ ++ BF_swap(data.binary.output, 6); ++ BF_encode(&output[7 + 22], data.binary.output, 23); ++ output[7 + 22 + 31] = '\0'; ++ ++/* Overwrite the most obvious sensitive data we have on the stack. Note ++ * that this does not guarantee there's no sensitive data left on the ++ * stack and/or in registers; I'm not aware of portable code that does. */ ++ clean(&data, sizeof(data)); ++ ++ return output; ++} ++ ++char *_crypt_gensalt_blowfish_rn(unsigned long count, ++ __CONST char *input, int size, char *output, int output_size) ++{ ++ if (size < 16 || output_size < 7 + 22 + 1 || ++ (count && (count < 4 || count > 31))) { ++ if (output_size > 0) output[0] = '\0'; ++ __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); ++ return NULL; ++ } ++ ++ if (!count) count = 5; ++ ++ output[0] = '$'; ++ output[1] = '2'; ++ output[2] = 'a'; ++ output[3] = '$'; ++ output[4] = '0' + count / 10; ++ output[5] = '0' + count % 10; ++ output[6] = '$'; ++ ++ BF_encode(&output[7], (BF_word *)input, 16); ++ output[7 + 22] = '\0'; ++ ++ return output; ++} +diff -Nura php-5.0.5/ext/standard/crypt.c hardening-patch-5.0.5-0.4.2/ext/standard/crypt.c +--- php-5.0.5/ext/standard/crypt.c 2004-02-12 20:05:41.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/crypt.c 2005-09-07 15:22:30.000000000 +0200 +@@ -100,6 +100,8 @@ + return SUCCESS; + } + ++char *_crypt_blowfish_rn(char *key, char *setting, char *output, int size); ++char *_crypt_gensalt_blowfish_rn(unsigned long count, char *input, int size, char *output, int output_size); + + static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +@@ -135,7 +137,14 @@ + + /* The automatic salt generation only covers standard DES and md5-crypt */ + if(!*salt) { +-#if PHP_MD5_CRYPT ++#if PHP_BLOWFISH_CRYPT ++ char randat[16]; ++ int i; ++ ++ for (i=0; i<16; i++) randat[i] = PHP_CRYPT_RAND; ++ ++ _crypt_gensalt_blowfish_rn(5, randat, sizeof(randat), salt, sizeof(salt)); ++#elif PHP_MD5_CRYPT + strcpy(salt, "$1$"); + php_to64(&salt[3], PHP_CRYPT_RAND, 4); + php_to64(&salt[7], PHP_CRYPT_RAND, 4); +@@ -145,8 +154,24 @@ + salt[2] = '\0'; + #endif + } +- +- RETVAL_STRING(crypt(str, salt), 1); ++ ++ if (salt[0] == '$' && ++ salt[1] == '2' && ++ salt[2] == 'a' && ++ salt[3] == '$' && ++ salt[4] >= '0' && salt[4] <= '3' && ++ salt[5] >= '0' && salt[5] <= '9' && ++ salt[6] == '$') { ++ ++ char output[PHP_MAX_SALT_LEN+1]; ++ ++ output[0] = 0; ++ _crypt_blowfish_rn(str, salt, output, sizeof(output)); ++ RETVAL_STRING(output, 1); ++ ++ } else { ++ RETVAL_STRING(crypt(str, salt), 1); ++ } + } + /* }}} */ + #endif +diff -Nura php-5.0.5/ext/standard/dl.c hardening-patch-5.0.5-0.4.2/ext/standard/dl.c +--- php-5.0.5/ext/standard/dl.c 2005-05-04 15:48:01.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/dl.c 2005-09-07 13:49:17.000000000 +0200 +@@ -159,8 +159,35 @@ + RETURN_FALSE; + } + module_entry = get_module(); ++ ++ /* check if Hardening-Patch is installed */ ++ if (module_entry->zend_api < 1000000000) { ++ php_error_docref(NULL TSRMLS_CC, error_type, ++ "%s: Unable to initialize module\n" ++ "Module compiled without Hardening-Patch, module API=%d, debug=%d, thread-safety=%d\n" ++ "PHP compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "These options need to match\n", ++ module_entry->name, module_entry->zend_api, module_entry->zend_debug, module_entry->zts, ++ HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS); ++ DL_UNLOAD(handle); ++ RETURN_FALSE; ++ } ++ ++ /* check if correct Hardening-Patch is installed */ ++ if (module_entry->zend_api != HARDENING_PATCH_ZEND_MODULE_API_NO) { ++ php_error_docref(NULL TSRMLS_CC, error_type, ++ "%s: Unable to initialize module\n" ++ "Module compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "PHP compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "These options need to match\n", ++ module_entry->name, module_entry->zend_api, module_entry->real_zend_api, module_entry->zend_debug, module_entry->zts, ++ HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS); ++ DL_UNLOAD(handle); ++ RETURN_FALSE; ++ } ++ + if ((module_entry->zend_debug != ZEND_DEBUG) || (module_entry->zts != USING_ZTS) +- || (module_entry->zend_api != ZEND_MODULE_API_NO)) { ++ || (module_entry->real_zend_api != ZEND_MODULE_API_NO)) { + /* Check for pre-4.1.0 module which has a slightly different module_entry structure :( */ + struct pre_4_1_0_module_entry { + char *name; +@@ -194,7 +221,7 @@ + zts = ((struct pre_4_1_0_module_entry *)module_entry)->zts; + } else { + name = module_entry->name; +- zend_api = module_entry->zend_api; ++ zend_api = module_entry->real_zend_api; + zend_debug = module_entry->zend_debug; + zts = module_entry->zts; + } +diff -Nura php-5.0.5/ext/standard/file.c hardening-patch-5.0.5-0.4.2/ext/standard/file.c +--- php-5.0.5/ext/standard/file.c 2005-04-06 15:59:48.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/file.c 2005-09-07 13:49:17.000000000 +0200 +@@ -2044,7 +2044,7 @@ + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) + /* {{{ proto string realpath(string path) + Return the resolved path */ +-PHP_FUNCTION(realpath) ++PHP_FUNCTION(real_path) + { + zval **path; + char resolved_path_buff[MAXPATHLEN]; +diff -Nura php-5.0.5/ext/standard/file.h hardening-patch-5.0.5-0.4.2/ext/standard/file.h +--- php-5.0.5/ext/standard/file.h 2005-07-15 11:29:18.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/file.h 2005-09-07 13:54:52.000000000 +0200 +@@ -60,7 +60,7 @@ + PHP_FUNCTION(fd_set); + PHP_FUNCTION(fd_isset); + #if (!defined(__BEOS__) && HAVE_REALPATH) || defined(ZTS) +-PHP_FUNCTION(realpath); ++PHP_FUNCTION(real_path); + PHP_FUNCTION(fnmatch); + #endif + PHP_NAMED_FUNCTION(php_if_ftruncate); +diff -Nura php-5.0.5/ext/standard/head.c hardening-patch-5.0.5-0.4.2/ext/standard/head.c +--- php-5.0.5/ext/standard/head.c 2005-06-28 16:49:14.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/head.c 2005-09-07 13:49:17.000000000 +0200 +@@ -40,10 +40,31 @@ + { + zend_bool rep = 1; + sapi_header_line ctr = {0}; ++#if HARDENING_PATCH ++ int i; ++#endif + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &ctr.line, + &ctr.line_len, &rep, &ctr.response_code) == FAILURE) + return; ++ ++#if HARDENING_PATCH ++ if (!HG(hphp_multiheader)) { ++ for (i=0; i0 && (i"); + } + ++#if HARDENING_PATCH ++ if (!sapi_module.phpinfo_as_text) { ++ php_printf("

PHP Version %s with Hardening-Patch %s

\n", PHP_VERSION, HARDENING_PATCH_VERSION); ++ } else { ++ char temp_ver[40]; ++ ++ snprintf(temp_ver, sizeof(temp_ver), "%s/%s", PHP_VERSION, HARDENING_PATCH_VERSION); ++ php_info_print_table_row(2, "PHP/Hardening-Patch Version", temp_ver); ++ } ++#else + if (!sapi_module.phpinfo_as_text) { + php_printf("

PHP Version %s

\n", PHP_VERSION); + } else { + php_info_print_table_row(2, "PHP Version", PHP_VERSION); +- } ++ } ++#endif + php_info_print_box_end(); + php_info_print_table_start(); + php_info_print_table_row(2, "System", php_uname ); +diff -Nura php-5.0.5/ext/standard/php_standard.h hardening-patch-5.0.5-0.4.2/ext/standard/php_standard.h +--- php-5.0.5/ext/standard/php_standard.h 2004-01-08 18:32:51.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/php_standard.h 2005-09-07 14:19:05.000000000 +0200 +@@ -28,6 +28,7 @@ + #include "php_mail.h" + #include "md5.h" + #include "sha1.h" ++#include "sha256.h" + #include "html.h" + #include "exec.h" + #include "file.h" +diff -Nura php-5.0.5/ext/standard/sha256.c hardening-patch-5.0.5-0.4.2/ext/standard/sha256.c +--- php-5.0.5/ext/standard/sha256.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/sha256.c 2005-09-07 14:19:05.000000000 +0200 +@@ -0,0 +1,398 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 5 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2004 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 3.0 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available through the world-wide-web at the following url: | ++ | http://www.php.net/license/3_0.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++*/ ++ ++/* $Id: sha256.c,v 1.9 2004/01/08 08:17:34 andi Exp $ */ ++ ++#include ++#include "php.h" ++ ++/* This code is heavily based on the PHP md5/sha1 implementations */ ++ ++#include "sha256.h" ++ ++PHPAPI void make_sha256_digest(char *sha256str, unsigned char *digest) ++{ ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ sprintf(sha256str, "%02x", digest[i]); ++ sha256str += 2; ++ } ++ ++ *sha256str = '\0'; ++} ++ ++/* {{{ proto string sha256(string str [, bool raw_output]) ++ Calculate the sha256 hash of a string */ ++PHP_FUNCTION(sha256) ++{ ++ char *arg; ++ int arg_len; ++ zend_bool raw_output = 0; ++ char sha256str[65]; ++ PHP_SHA256_CTX context; ++ unsigned char digest[32]; ++ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &arg, &arg_len, &raw_output) == FAILURE) { ++ return; ++ } ++ ++ sha256str[0] = '\0'; ++ PHP_SHA256Init(&context); ++ PHP_SHA256Update(&context, arg, arg_len); ++ PHP_SHA256Final(digest, &context); ++ if (raw_output) { ++ RETURN_STRINGL(digest, 32, 1); ++ } else { ++ make_sha256_digest(sha256str, digest); ++ RETVAL_STRING(sha256str, 1); ++ } ++ ++} ++ ++/* }}} */ ++ ++/* {{{ proto string sha256_file(string filename [, bool raw_output]) ++ Calculate the sha256 hash of given filename */ ++PHP_FUNCTION(sha256_file) ++{ ++ char *arg; ++ int arg_len; ++ zend_bool raw_output = 0; ++ char sha256str[65]; ++ unsigned char buf[1024]; ++ unsigned char digest[32]; ++ PHP_SHA256_CTX context; ++ int n; ++ FILE *fp; ++ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &arg, &arg_len, &raw_output) == FAILURE) { ++ return; ++ } ++ ++ if (PG(safe_mode) && (!php_checkuid(arg, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { ++ RETURN_FALSE; ++ } ++ ++ if (php_check_open_basedir(arg TSRMLS_CC)) { ++ RETURN_FALSE; ++ } ++ ++ if ((fp = VCWD_FOPEN(arg, "rb")) == NULL) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open file"); ++ RETURN_FALSE; ++ } ++ ++ PHP_SHA256Init(&context); ++ ++ while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { ++ PHP_SHA256Update(&context, buf, n); ++ } ++ ++ PHP_SHA256Final(digest, &context); ++ ++ if (ferror(fp)) { ++ fclose(fp); ++ RETURN_FALSE; ++ } ++ ++ fclose(fp); ++ ++ if (raw_output) { ++ RETURN_STRINGL(digest, 32, 1); ++ } else { ++ make_sha256_digest(sha256str, digest); ++ RETVAL_STRING(sha256str, 1); ++ } ++} ++/* }}} */ ++ ++ ++static void SHA256Transform(php_uint32[8], const unsigned char[64]); ++static void SHA256Encode(unsigned char *, php_uint32 *, unsigned int); ++static void SHA256Decode(php_uint32 *, const unsigned char *, unsigned int); ++ ++static unsigned char PADDING[64] = ++{ ++ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ++}; ++ ++/* F, G, H and I are basic SHA256 functions. ++ */ ++#define F(x) (ROTATE_RIGHT(x,2) ^ ROTATE_RIGHT(x,13) ^ ROTATE_RIGHT(x,22)) ++#define G(x, y, z) (((x) & (y)) | ((z) & ((y) | (x)))) ++#define H(x) (ROTATE_RIGHT(x,6) ^ ROTATE_RIGHT(x,11) ^ ROTATE_RIGHT(x,25)) ++#define I(x, y, z) (((x) & (y)) | ((~x) & z)) ++ ++/* ROTATE_RIGHT rotates x right n bits. ++ */ ++#define ROTATE_RIGHT(x, n) (((x) >> (n)) | ((x) << (32-(n)))) ++ ++/* W[i] ++ */ ++#define W(i) ( tmp1=ROTATE_RIGHT(x[(i-15)&15],7)^ROTATE_RIGHT(x[(i-15)&15],18)^(x[(i-15)&15] >> 3), \ ++ tmp2=ROTATE_RIGHT(x[(i-2)&15],17)^ROTATE_RIGHT(x[(i-2)&15],19)^(x[(i-2)&15] >> 10), \ ++ (x[i&15]=x[i&15] + tmp1 + x[(i-7)&15] + tmp2) ) ++ ++/* ROUND function of sha256 ++ */ ++ ++#define ROUND(a,b,c,d,e,f,g,h,w,k) { \ ++ t1 = (h) + H((e)) + I((e), (f), (g)) + (k) + (php_uint32)(w); \ ++ (h) = F((a)) + G((a), (b), (c)) + t1; \ ++ (d) += t1; \ ++ } ++ ++ ++/* {{{ PHP_SHA256Init ++ * SHA256 initialization. Begins an SHA256 operation, writing a new context. ++ */ ++PHPAPI void PHP_SHA256Init(PHP_SHA256_CTX * context) ++{ ++ context->count[0] = context->count[1] = 0; ++ /* Load magic initialization constants. ++ */ ++ context->state[0] = 0x6a09e667; ++ context->state[1] = 0xbb67ae85; ++ context->state[2] = 0x3c6ef372; ++ context->state[3] = 0xa54ff53a; ++ context->state[4] = 0x510e527f; ++ context->state[5] = 0x9b05688c; ++ context->state[6] = 0x1f83d9ab; ++ context->state[7] = 0x5be0cd19; ++} ++/* }}} */ ++ ++/* {{{ PHP_SHA256Update ++ SHA256 block update operation. Continues an SHA256 message-digest ++ operation, processing another message block, and updating the ++ context. ++ */ ++PHPAPI void PHP_SHA256Update(PHP_SHA256_CTX * context, const unsigned char *input, ++ unsigned int inputLen) ++{ ++ unsigned int i, index, partLen; ++ ++ /* Compute number of bytes mod 64 */ ++ index = (unsigned int) ((context->count[0] >> 3) & 0x3F); ++ ++ /* Update number of bits */ ++ if ((context->count[0] += ((php_uint32) inputLen << 3)) ++ < ((php_uint32) inputLen << 3)) ++ context->count[1]++; ++ context->count[1] += ((php_uint32) inputLen >> 29); ++ ++ partLen = 64 - index; ++ ++ /* Transform as many times as possible. ++ */ ++ if (inputLen >= partLen) { ++ memcpy ++ ((unsigned char*) & context->buffer[index], (unsigned char*) input, partLen); ++ SHA256Transform(context->state, context->buffer); ++ ++ for (i = partLen; i + 63 < inputLen; i += 64) ++ SHA256Transform(context->state, &input[i]); ++ ++ index = 0; ++ } else ++ i = 0; ++ ++ /* Buffer remaining input */ ++ memcpy ++ ((unsigned char*) & context->buffer[index], (unsigned char*) & input[i], ++ inputLen - i); ++} ++/* }}} */ ++ ++/* {{{ PHP_SHA256Final ++ SHA256 finalization. Ends an SHA256 message-digest operation, writing the ++ the message digest and zeroizing the context. ++ */ ++PHPAPI void PHP_SHA256Final(unsigned char digest[32], PHP_SHA256_CTX * context) ++{ ++ unsigned char bits[8]; ++ unsigned int index, padLen; ++ ++ /* Save number of bits */ ++ bits[7] = context->count[0] & 0xFF; ++ bits[6] = (context->count[0] >> 8) & 0xFF; ++ bits[5] = (context->count[0] >> 16) & 0xFF; ++ bits[4] = (context->count[0] >> 24) & 0xFF; ++ bits[3] = context->count[1] & 0xFF; ++ bits[2] = (context->count[1] >> 8) & 0xFF; ++ bits[1] = (context->count[1] >> 16) & 0xFF; ++ bits[0] = (context->count[1] >> 24) & 0xFF; ++ ++ /* Pad out to 56 mod 64. ++ */ ++ index = (unsigned int) ((context->count[0] >> 3) & 0x3f); ++ padLen = (index < 56) ? (56 - index) : (120 - index); ++ PHP_SHA256Update(context, PADDING, padLen); ++ ++ /* Append length (before padding) */ ++ PHP_SHA256Update(context, bits, 8); ++ ++ /* Store state in digest */ ++ SHA256Encode(digest, context->state, 32); ++ ++ /* Zeroize sensitive information. ++ */ ++ memset((unsigned char*) context, 0, sizeof(*context)); ++} ++/* }}} */ ++ ++/* {{{ SHA256Transform ++ * SHA256 basic transformation. Transforms state based on block. ++ */ ++static void SHA256Transform(state, block) ++php_uint32 state[8]; ++const unsigned char block[64]; ++{ ++ php_uint32 a = state[0], b = state[1], c = state[2]; ++ php_uint32 d = state[3], e = state[4], f = state[5]; ++ php_uint32 g = state[6], h = state[7], x[16], tmp1, tmp2, t1; ++ ++ SHA256Decode(x, block, 64); ++ ++ ROUND(a, b, c, d, e, f, g, h, x[0], 0x428a2f98) ++ ROUND(h, a, b, c, d, e, f, g, x[1], 0x71374491) ++ ROUND(g, h, a, b, c, d, e, f, x[2], 0xb5c0fbcf) ++ ROUND(f, g, h, a, b, c, d, e, x[3], 0xe9b5dba5) ++ ROUND(e, f, g, h, a, b, c, d, x[4], 0x3956c25b) ++ ROUND(d, e, f, g, h, a, b, c, x[5], 0x59f111f1) ++ ROUND(c, d, e, f, g, h, a, b, x[6], 0x923f82a4) ++ ROUND(b, c, d, e, f, g, h, a, x[7], 0xab1c5ed5) ++ ROUND(a, b, c, d, e, f, g, h, x[8], 0xd807aa98) ++ ROUND(h, a, b, c, d, e, f, g, x[9], 0x12835b01) ++ ROUND(g, h, a, b, c, d, e, f, x[10], 0x243185be) ++ ROUND(f, g, h, a, b, c, d, e, x[11], 0x550c7dc3) ++ ROUND(e, f, g, h, a, b, c, d, x[12], 0x72be5d74) ++ ROUND(d, e, f, g, h, a, b, c, x[13], 0x80deb1fe) ++ ROUND(c, d, e, f, g, h, a, b, x[14], 0x9bdc06a7) ++ ROUND(b, c, d, e, f, g, h, a, x[15], 0xc19bf174) ++ ROUND(a, b, c, d, e, f, g, h, W(16), 0xe49b69c1) ++ ROUND(h, a, b, c, d, e, f, g, W(17), 0xefbe4786) ++ ROUND(g, h, a, b, c, d, e, f, W(18), 0x0fc19dc6) ++ ROUND(f, g, h, a, b, c, d, e, W(19), 0x240ca1cc) ++ ROUND(e, f, g, h, a, b, c, d, W(20), 0x2de92c6f) ++ ROUND(d, e, f, g, h, a, b, c, W(21), 0x4a7484aa) ++ ROUND(c, d, e, f, g, h, a, b, W(22), 0x5cb0a9dc) ++ ROUND(b, c, d, e, f, g, h, a, W(23), 0x76f988da) ++ ROUND(a, b, c, d, e, f, g, h, W(24), 0x983e5152) ++ ROUND(h, a, b, c, d, e, f, g, W(25), 0xa831c66d) ++ ROUND(g, h, a, b, c, d, e, f, W(26), 0xb00327c8) ++ ROUND(f, g, h, a, b, c, d, e, W(27), 0xbf597fc7) ++ ROUND(e, f, g, h, a, b, c, d, W(28), 0xc6e00bf3) ++ ROUND(d, e, f, g, h, a, b, c, W(29), 0xd5a79147) ++ ROUND(c, d, e, f, g, h, a, b, W(30), 0x06ca6351) ++ ROUND(b, c, d, e, f, g, h, a, W(31), 0x14292967) ++ ROUND(a, b, c, d, e, f, g, h, W(32), 0x27b70a85) ++ ROUND(h, a, b, c, d, e, f, g, W(33), 0x2e1b2138) ++ ROUND(g, h, a, b, c, d, e, f, W(34), 0x4d2c6dfc) ++ ROUND(f, g, h, a, b, c, d, e, W(35), 0x53380d13) ++ ROUND(e, f, g, h, a, b, c, d, W(36), 0x650a7354) ++ ROUND(d, e, f, g, h, a, b, c, W(37), 0x766a0abb) ++ ROUND(c, d, e, f, g, h, a, b, W(38), 0x81c2c92e) ++ ROUND(b, c, d, e, f, g, h, a, W(39), 0x92722c85) ++ ROUND(a, b, c, d, e, f, g, h, W(40), 0xa2bfe8a1) ++ ROUND(h, a, b, c, d, e, f, g, W(41), 0xa81a664b) ++ ROUND(g, h, a, b, c, d, e, f, W(42), 0xc24b8b70) ++ ROUND(f, g, h, a, b, c, d, e, W(43), 0xc76c51a3) ++ ROUND(e, f, g, h, a, b, c, d, W(44), 0xd192e819) ++ ROUND(d, e, f, g, h, a, b, c, W(45), 0xd6990624) ++ ROUND(c, d, e, f, g, h, a, b, W(46), 0xf40e3585) ++ ROUND(b, c, d, e, f, g, h, a, W(47), 0x106aa070) ++ ROUND(a, b, c, d, e, f, g, h, W(48), 0x19a4c116) ++ ROUND(h, a, b, c, d, e, f, g, W(49), 0x1e376c08) ++ ROUND(g, h, a, b, c, d, e, f, W(50), 0x2748774c) ++ ROUND(f, g, h, a, b, c, d, e, W(51), 0x34b0bcb5) ++ ROUND(e, f, g, h, a, b, c, d, W(52), 0x391c0cb3) ++ ROUND(d, e, f, g, h, a, b, c, W(53), 0x4ed8aa4a) ++ ROUND(c, d, e, f, g, h, a, b, W(54), 0x5b9cca4f) ++ ROUND(b, c, d, e, f, g, h, a, W(55), 0x682e6ff3) ++ ROUND(a, b, c, d, e, f, g, h, W(56), 0x748f82ee) ++ ROUND(h, a, b, c, d, e, f, g, W(57), 0x78a5636f) ++ ROUND(g, h, a, b, c, d, e, f, W(58), 0x84c87814) ++ ROUND(f, g, h, a, b, c, d, e, W(59), 0x8cc70208) ++ ROUND(e, f, g, h, a, b, c, d, W(60), 0x90befffa) ++ ROUND(d, e, f, g, h, a, b, c, W(61), 0xa4506ceb) ++ ROUND(c, d, e, f, g, h, a, b, W(62), 0xbef9a3f7) ++ ROUND(b, c, d, e, f, g, h, a, W(63), 0xc67178f2) ++ ++ state[0] += a; ++ state[1] += b; ++ state[2] += c; ++ state[3] += d; ++ state[4] += e; ++ state[5] += f; ++ state[6] += g; ++ state[7] += h; ++ ++ /* Zeroize sensitive information. */ ++ memset((unsigned char*) x, 0, sizeof(x)); ++} ++/* }}} */ ++ ++/* {{{ SHA256Encode ++ Encodes input (php_uint32) into output (unsigned char). Assumes len is ++ a multiple of 4. ++ */ ++static void SHA256Encode(output, input, len) ++unsigned char *output; ++php_uint32 *input; ++unsigned int len; ++{ ++ unsigned int i, j; ++ ++ for (i = 0, j = 0; j < len; i++, j += 4) { ++ output[j] = (unsigned char) ((input[i] >> 24) & 0xff); ++ output[j + 1] = (unsigned char) ((input[i] >> 16) & 0xff); ++ output[j + 2] = (unsigned char) ((input[i] >> 8) & 0xff); ++ output[j + 3] = (unsigned char) (input[i] & 0xff); ++ } ++} ++/* }}} */ ++ ++/* {{{ SHA256Decode ++ Decodes input (unsigned char) into output (php_uint32). Assumes len is ++ a multiple of 4. ++ */ ++static void SHA256Decode(output, input, len) ++php_uint32 *output; ++const unsigned char *input; ++unsigned int len; ++{ ++ unsigned int i, j; ++ ++ for (i = 0, j = 0; j < len; i++, j += 4) ++ output[i] = ((php_uint32) input[j + 3]) | (((php_uint32) input[j + 2]) << 8) | ++ (((php_uint32) input[j + 1]) << 16) | (((php_uint32) input[j]) << 24); ++} ++/* }}} */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-5.0.5/ext/standard/sha256.h hardening-patch-5.0.5-0.4.2/ext/standard/sha256.h +--- php-5.0.5/ext/standard/sha256.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/sha256.h 2005-09-07 14:19:05.000000000 +0200 +@@ -0,0 +1,40 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 5 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2004 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 3.0 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available through the world-wide-web at the following url: | ++ | http://www.php.net/license/3_0.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++*/ ++ ++/* $Id: sha256.h,v 1.4 2004/01/08 17:32:52 sniper Exp $ */ ++ ++#ifndef SHA256_H ++#define SHA256_H ++ ++#include "ext/standard/basic_functions.h" ++ ++/* SHA1 context. */ ++typedef struct { ++ php_uint32 state[8]; /* state (ABCD) */ ++ php_uint32 count[2]; /* number of bits, modulo 2^64 (lsb first) */ ++ unsigned char buffer[64]; /* input buffer */ ++} PHP_SHA256_CTX; ++ ++PHPAPI void PHP_SHA256Init(PHP_SHA256_CTX *); ++PHPAPI void PHP_SHA256Update(PHP_SHA256_CTX *, const unsigned char *, unsigned int); ++PHPAPI void PHP_SHA256Final(unsigned char[32], PHP_SHA256_CTX *); ++ ++PHP_FUNCTION(sha256); ++PHP_FUNCTION(sha256_file); ++ ++#endif +diff -Nura php-5.0.5/ext/standard/syslog.c hardening-patch-5.0.5-0.4.2/ext/standard/syslog.c +--- php-5.0.5/ext/standard/syslog.c 2005-07-15 11:29:19.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/ext/standard/syslog.c 2005-09-07 13:49:17.000000000 +0200 +@@ -42,6 +42,7 @@ + */ + PHP_MINIT_FUNCTION(syslog) + { ++#if !HARDENING_PATCH + /* error levels */ + REGISTER_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ + REGISTER_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ +@@ -97,7 +98,7 @@ + /* AIX doesn't have LOG_PERROR */ + REGISTER_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ + #endif +- ++#endif + return SUCCESS; + } + /* }}} */ +diff -Nura php-5.0.5/ext/varfilter/config.m4 hardening-patch-5.0.5-0.4.2/ext/varfilter/config.m4 +--- php-5.0.5/ext/varfilter/config.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/ext/varfilter/config.m4 2005-09-07 13:49:17.000000000 +0200 +@@ -0,0 +1,11 @@ ++dnl ++dnl $Id: config.m4,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++dnl ++ ++PHP_ARG_ENABLE(varfilter, whether to enable Hardening-Patch's variable filter, ++[ --disable-varfilter Disable Hardening-Patch's variable filter], yes) ++ ++if test "$PHP_VARFILTER" != "no"; then ++ AC_DEFINE(HAVE_VARFILTER, 1, [ ]) ++ PHP_NEW_EXTENSION(varfilter, varfilter.c, $ext_shared) ++fi +diff -Nura php-5.0.5/ext/varfilter/CREDITS hardening-patch-5.0.5-0.4.2/ext/varfilter/CREDITS +--- php-5.0.5/ext/varfilter/CREDITS 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/ext/varfilter/CREDITS 2005-09-07 13:49:17.000000000 +0200 +@@ -0,0 +1,2 @@ ++varfilter ++Stefan Esser +\ Kein Zeilenumbruch am Dateiende. +diff -Nura php-5.0.5/ext/varfilter/php_varfilter.h hardening-patch-5.0.5-0.4.2/ext/varfilter/php_varfilter.h +--- php-5.0.5/ext/varfilter/php_varfilter.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/ext/varfilter/php_varfilter.h 2005-09-07 13:49:17.000000000 +0200 +@@ -0,0 +1,111 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: php_varfilter.h,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifndef PHP_VARFILTER_H ++#define PHP_VARFILTER_H ++ ++extern zend_module_entry varfilter_module_entry; ++#define phpext_varfilter_ptr &varfilter_module_entry ++ ++#ifdef PHP_WIN32 ++#define PHP_VARFILTER_API __declspec(dllexport) ++#else ++#define PHP_VARFILTER_API ++#endif ++ ++#ifdef ZTS ++#include "TSRM.h" ++#endif ++ ++#include "SAPI.h" ++ ++#include "php_variables.h" ++ ++ ++PHP_MINIT_FUNCTION(varfilter); ++PHP_MSHUTDOWN_FUNCTION(varfilter); ++PHP_RINIT_FUNCTION(varfilter); ++PHP_RSHUTDOWN_FUNCTION(varfilter); ++PHP_MINFO_FUNCTION(varfilter); ++ ++ ++ZEND_BEGIN_MODULE_GLOBALS(varfilter) ++/* request variables */ ++ long max_request_variables; ++ long cur_request_variables; ++ long max_varname_length; ++ long max_totalname_length; ++ long max_value_length; ++ long max_array_depth; ++ long max_array_index_length; ++/* cookie variables */ ++ long max_cookie_vars; ++ long cur_cookie_vars; ++ long max_cookie_name_length; ++ long max_cookie_totalname_length; ++ long max_cookie_value_length; ++ long max_cookie_array_depth; ++ long max_cookie_array_index_length; ++/* get variables */ ++ long max_get_vars; ++ long cur_get_vars; ++ long max_get_name_length; ++ long max_get_totalname_length; ++ long max_get_value_length; ++ long max_get_array_depth; ++ long max_get_array_index_length; ++/* post variables */ ++ long max_post_vars; ++ long cur_post_vars; ++ long max_post_name_length; ++ long max_post_totalname_length; ++ long max_post_value_length; ++ long max_post_array_depth; ++ long max_post_array_index_length; ++/* fileupload */ ++ long max_uploads; ++ long cur_uploads; ++ zend_bool disallow_elf_files; ++ char *verification_script; ++ ++ZEND_END_MODULE_GLOBALS(varfilter) ++ ++ ++#ifdef ZTS ++#define VARFILTER_G(v) TSRMG(varfilter_globals_id, zend_varfilter_globals *, v) ++#else ++#define VARFILTER_G(v) (varfilter_globals.v) ++#endif ++ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter); ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter); ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter); ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter); ++ ++#endif /* PHP_VARFILTER_H */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * indent-tabs-mode: t ++ * End: ++ */ +diff -Nura php-5.0.5/ext/varfilter/varfilter.c hardening-patch-5.0.5-0.4.2/ext/varfilter/varfilter.c +--- php-5.0.5/ext/varfilter/varfilter.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/ext/varfilter/varfilter.c 2005-09-07 14:19:05.000000000 +0200 +@@ -0,0 +1,602 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: varfilter.c,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "php.h" ++#include "php_ini.h" ++#include "ext/standard/info.h" ++#include "php_varfilter.h" ++#include "hardening_patch.h" ++ ++ZEND_DECLARE_MODULE_GLOBALS(varfilter) ++ ++/* True global resources - no need for thread safety here */ ++static int le_varfilter; ++ ++/* {{{ varfilter_module_entry ++ */ ++zend_module_entry varfilter_module_entry = { ++#if ZEND_MODULE_API_NO >= 20010901 ++ STANDARD_MODULE_HEADER, ++#endif ++ "varfilter", ++ NULL, ++ PHP_MINIT(varfilter), ++ PHP_MSHUTDOWN(varfilter), ++ PHP_RINIT(varfilter), /* Replace with NULL if there's nothing to do at request start */ ++ PHP_RSHUTDOWN(varfilter), /* Replace with NULL if there's nothing to do at request end */ ++ PHP_MINFO(varfilter), ++#if ZEND_MODULE_API_NO >= 20010901 ++ "0.3.2", /* Replace with version number for your extension */ ++#endif ++ STANDARD_MODULE_PROPERTIES ++}; ++/* }}} */ ++ ++#ifdef COMPILE_DL_VARFILTER ++ZEND_GET_MODULE(varfilter) ++#endif ++ ++/* {{{ PHP_INI ++ */ ++PHP_INI_BEGIN() ++ /* for backward compatibility */ ++ STD_PHP_INI_ENTRY("varfilter.max_request_variables", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.request.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.cookie.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_cookie_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_value_length", "10000", PHP_INI_PERDIR, OnUpdateLong, max_cookie_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.get.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_get_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_get_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_value_length", "512", PHP_INI_PERDIR, OnUpdateLong, max_get_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_depth", "50", PHP_INI_PERDIR, OnUpdateLong, max_get_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.post.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_post_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_post_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_post_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_post_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.upload.max_uploads", "25", PHP_INI_PERDIR, OnUpdateLong, max_uploads, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.disallow_elf_files", "1", PHP_INI_SYSTEM, OnUpdateBool, disallow_elf_files, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.verification_script", NULL, PHP_INI_SYSTEM, OnUpdateString, verification_script, zend_varfilter_globals, varfilter_globals) ++ ++ ++PHP_INI_END() ++/* }}} */ ++ ++/* {{{ php_varfilter_init_globals ++ */ ++static void php_varfilter_init_globals(zend_varfilter_globals *varfilter_globals) ++{ ++ varfilter_globals->max_request_variables = 200; ++ varfilter_globals->max_varname_length = 64; ++ varfilter_globals->max_value_length = 10000; ++ varfilter_globals->max_array_depth = 100; ++ varfilter_globals->max_totalname_length = 256; ++ varfilter_globals->max_array_index_length = 64; ++ ++ varfilter_globals->max_cookie_vars = 100; ++ varfilter_globals->max_cookie_name_length = 64; ++ varfilter_globals->max_cookie_totalname_length = 256; ++ varfilter_globals->max_cookie_value_length = 10000; ++ varfilter_globals->max_cookie_array_depth = 100; ++ varfilter_globals->max_cookie_array_index_length = 64; ++ ++ varfilter_globals->max_get_vars = 100; ++ varfilter_globals->max_get_name_length = 64; ++ varfilter_globals->max_get_totalname_length = 256; ++ varfilter_globals->max_get_value_length = 512; ++ varfilter_globals->max_get_array_depth = 50; ++ varfilter_globals->max_get_array_index_length = 64; ++ ++ varfilter_globals->max_post_vars = 200; ++ varfilter_globals->max_post_name_length = 64; ++ varfilter_globals->max_post_totalname_length = 256; ++ varfilter_globals->max_post_value_length = 65000; ++ varfilter_globals->max_post_array_depth = 100; ++ varfilter_globals->max_post_array_index_length = 64; ++ ++ varfilter_globals->max_uploads = 25; ++ varfilter_globals->disallow_elf_files = 1; ++ varfilter_globals->verification_script = NULL; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINIT_FUNCTION ++ */ ++PHP_MINIT_FUNCTION(varfilter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(varfilter, php_varfilter_init_globals, NULL); ++ REGISTER_INI_ENTRIES(); ++ ++ sapi_register_input_filter(varfilter_input_filter); ++ sapi_register_pre_upload_filter(varfilter_pre_upload_filter); ++ sapi_register_upload_content_filter(varfilter_upload_content_filter); ++ sapi_register_post_upload_filter(varfilter_post_upload_filter); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MSHUTDOWN_FUNCTION ++ */ ++PHP_MSHUTDOWN_FUNCTION(varfilter) ++{ ++ UNREGISTER_INI_ENTRIES(); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request start */ ++/* {{{ PHP_RINIT_FUNCTION ++ */ ++PHP_RINIT_FUNCTION(varfilter) ++{ ++ VARFILTER_G(cur_request_variables) = 0; ++ VARFILTER_G(cur_get_vars) = 0; ++ VARFILTER_G(cur_post_vars) = 0; ++ VARFILTER_G(cur_cookie_vars) = 0; ++ ++ VARFILTER_G(cur_uploads) = 0; ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request end */ ++/* {{{ PHP_RSHUTDOWN_FUNCTION ++ */ ++PHP_RSHUTDOWN_FUNCTION(varfilter) ++{ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINFO_FUNCTION ++ */ ++PHP_MINFO_FUNCTION(varfilter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_header(2, "Hardening-Patch's variable filter support", "enabled"); ++ php_info_print_table_end(); ++ ++ DISPLAY_INI_ENTRIES(); ++} ++/* }}} */ ++ ++/* {{{ normalize_varname ++ */ ++static void normalize_varname(char *varname) ++{ ++ char *s=varname, *index=NULL, *indexend=NULL, *p; ++ ++ /* overjump leading space */ ++ while (*s == ' ') { ++ s++; ++ } ++ ++ /* and remove it */ ++ if (s != varname) { ++ memmove(varname, s, strlen(s)+1); ++ } ++ ++ for (p=varname; *p && *p != '['; p++) { ++ switch(*p) { ++ case ' ': ++ case '.': ++ *p='_'; ++ break; ++ } ++ } ++ ++ /* find index */ ++ index = strchr(varname, '['); ++ if (index) { ++ index++; ++ s=index; ++ } else { ++ return; ++ } ++ ++ /* done? */ ++ while (index) { ++ ++ while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') { ++ index++; ++ } ++ indexend = strchr(index, ']'); ++ indexend = indexend ? indexend + 1 : index + strlen(index); ++ ++ if (s != index) { ++ memmove(s, index, strlen(index)+1); ++ s += indexend-index; ++ } else { ++ s = indexend; ++ } ++ ++ if (*s == '[') { ++ s++; ++ index = s; ++ } else { ++ index = NULL; ++ } ++ } ++ *s++='\0'; ++} ++/* }}} */ ++ ++/* {{{ SAPI_PRE_UPLOAD_FILTER_FUNC ++ */ ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter) ++{ ++ /* Drop this fileupload if the limit is reached */ ++ if (VARFILTER_G(max_uploads) && VARFILTER_G(max_uploads) <= VARFILTER_G(cur_uploads)) { ++ php_security_log(S_FILES, "configured fileupload limit exceeded - file dropped"); ++ return FAILURE; ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_UPLOAD_CONTENT_FILTER_FUNC ++ */ ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter) ++{ ++ ++ if (VARFILTER_G(disallow_elf_files)) { ++ ++ if (offset == 0 && buffer_len > 10) { ++ ++ if (buffer[0] == 0x7F && buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F') { ++ php_security_log(S_FILES, "uploaded file is an ELF executable - file dropped"); ++ return FAILURE; ++ } ++ } ++ ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_POST_UPLOAD_FILTER_FUNC ++ */ ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter) ++{ ++ int retval = SUCCESS; ++ ++ if (VARFILTER_G(verification_script)) { ++ char cmd[8192]; ++ FILE *in; ++ int first=1; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s", VARFILTER_G(verification_script), tmpfilename); ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_FILES, "unable to execute fileupload verification script %s - file dropped", VARFILTER_G(verification_script)); ++ return FAILURE; ++ } ++ ++ retval = FAILURE; ++ ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ if (first) { ++ retval = atoi(cmd) == 1 ? SUCCESS : FAILURE; ++ first = 0; ++ } ++ } ++ pclose(in); ++ } ++ ++ if (retval != SUCCESS) { ++ php_security_log(S_FILES, "fileupload verification script disallows file - file dropped"); ++ return FAILURE; ++ } ++ ++ VARFILTER_G(cur_uploads)++; ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_INPUT_FILTER_FUNC ++ */ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter) ++{ ++ char *index, *prev_index = NULL, *copy_var; ++ unsigned int var_len, total_len, depth = 0, rv; ++ ++ /* Drop this variable if the limit is reached */ ++ if (VARFILTER_G(max_request_variables) && VARFILTER_G(max_request_variables) <= VARFILTER_G(cur_request_variables)) { ++ php_security_log(S_VARS, "configured request variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_vars) && VARFILTER_G(max_get_vars) <= VARFILTER_G(cur_get_vars)) { ++ php_security_log(S_VARS, "configured GET variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_vars) && VARFILTER_G(max_cookie_vars) <= VARFILTER_G(cur_cookie_vars)) { ++ php_security_log(S_VARS, "configured COOKIE variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_vars) && VARFILTER_G(max_post_vars) <= VARFILTER_G(cur_post_vars)) { ++ php_security_log(S_VARS, "configured POST variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ ++ /* Drop this variable if it exceeds the value length limit */ ++ if (VARFILTER_G(max_value_length) && VARFILTER_G(max_value_length) < val_len) { ++ php_security_log(S_VARS, "configured request variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_value_length) && VARFILTER_G(max_get_value_length) < val_len) { ++ php_security_log(S_VARS, "configured GET variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_value_length) && VARFILTER_G(max_cookie_value_length) < val_len) { ++ php_security_log(S_VARS, "configured COOKIE variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_value_length) && VARFILTER_G(max_post_value_length) < val_len) { ++ php_security_log(S_VARS, "configured POST variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Normalize the variable name */ ++ normalize_varname(var); ++ ++ /* Find length of variable name */ ++ index = strchr(var, '['); ++ total_len = strlen(var); ++ var_len = index ? index-var : total_len; ++ ++ /* Drop this variable if it exceeds the varname/total length limit */ ++ if (VARFILTER_G(max_varname_length) && VARFILTER_G(max_varname_length) < var_len) { ++ php_security_log(S_VARS, "configured request variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_totalname_length) && VARFILTER_G(max_totalname_length) < total_len) { ++ php_security_log(S_VARS, "configured request variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_name_length) && VARFILTER_G(max_get_name_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_get_totalname_length) && VARFILTER_G(max_get_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_name_length) && VARFILTER_G(max_cookie_name_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_cookie_totalname_length) && VARFILTER_G(max_cookie_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_name_length) && VARFILTER_G(max_post_name_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_post_totalname_length) && VARFILTER_G(max_post_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Find out array depth */ ++ while (index) { ++ unsigned int index_length; ++ ++ depth++; ++ index = strchr(index+1, '['); ++ ++ if (prev_index) { ++ index_length = index ? index - 1 - prev_index - 1: strlen(prev_index); ++ ++ if (VARFILTER_G(max_array_index_length) && VARFILTER_G(max_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured request variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_index_length) && VARFILTER_G(max_get_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured GET variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_index_length) && VARFILTER_G(max_cookie_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured COOKIE variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_index_length) && VARFILTER_G(max_post_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured POST variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ prev_index = index; ++ } ++ ++ } ++ ++ /* Drop this variable if it exceeds the array depth limit */ ++ if (VARFILTER_G(max_array_depth) && VARFILTER_G(max_array_depth) < depth) { ++ php_security_log(S_VARS, "configured request variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_depth) && VARFILTER_G(max_get_array_depth) < depth) { ++ php_security_log(S_VARS, "configured GET variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_depth) && VARFILTER_G(max_cookie_array_depth) < depth) { ++ php_security_log(S_VARS, "configured COOKIE variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_depth) && VARFILTER_G(max_post_array_depth) < depth) { ++ php_security_log(S_VARS, "configured POST variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Drop this variable if it is one of GLOBALS, _GET, _POST, ... */ ++ /* This is to protect several silly scripts that do globalizing themself */ ++ ++ switch (var_len) { ++ case 18: ++ if (memcmp(var, "HTTP_RAW_POST_DATA", 18)==0) goto protected_varname; ++ break; ++ case 17: ++ if (memcmp(var, "HTTP_SESSION_VARS", 17)==0) goto protected_varname; ++ break; ++ case 16: ++ if (memcmp(var, "HTTP_SERVER_VARS", 16)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_COOKIE_VARS", 16)==0) goto protected_varname; ++ break; ++ case 15: ++ if (memcmp(var, "HTTP_POST_FILES", 15)==0) goto protected_varname; ++ break; ++ case 14: ++ if (memcmp(var, "HTTP_POST_VARS", 14)==0) goto protected_varname; ++ break; ++ case 13: ++ if (memcmp(var, "HTTP_GET_VARS", 13)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_ENV_VARS", 13)==0) goto protected_varname; ++ break; ++ case 8: ++ if (memcmp(var, "_SESSION", 8)==0) goto protected_varname; ++ if (memcmp(var, "_REQUEST", 8)==0) goto protected_varname; ++ break; ++ case 7: ++ if (memcmp(var, "GLOBALS", 7)==0) goto protected_varname; ++ if (memcmp(var, "_COOKIE", 7)==0) goto protected_varname; ++ if (memcmp(var, "_SERVER", 7)==0) goto protected_varname; ++ break; ++ case 6: ++ if (memcmp(var, "_FILES", 6)==0) goto protected_varname; ++ break; ++ case 5: ++ if (memcmp(var, "_POST", 5)==0) goto protected_varname; ++ break; ++ case 4: ++ if (memcmp(var, "_ENV", 4)==0) goto protected_varname; ++ if (memcmp(var, "_GET", 4)==0) goto protected_varname; ++ break; ++ } ++ ++ /* Okay let PHP register this variable */ ++ VARFILTER_G(cur_request_variables)++; ++ switch (arg) { ++ case PARSE_GET: ++ VARFILTER_G(cur_get_vars)++; ++ break; ++ case PARSE_COOKIE: ++ VARFILTER_G(cur_cookie_vars)++; ++ break; ++ case PARSE_POST: ++ VARFILTER_G(cur_post_vars)++; ++ break; ++ } ++ ++ if (new_val_len) { ++ *new_val_len = val_len; ++ } ++ ++ return 1; ++protected_varname: ++ php_security_log(S_VARS, "tried to register forbidden variable '%s' through %s variables", var, arg == PARSE_GET ? "GET" : arg == PARSE_POST ? "POST" : "COOKIE"); ++ return 0; ++} ++/* }}} */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: noet sw=4 ts=4 fdm=marker ++ * vim<600: noet sw=4 ts=4 ++ */ ++ ++ +diff -Nura php-5.0.5/main/fopen_wrappers.c hardening-patch-5.0.5-0.4.2/main/fopen_wrappers.c +--- php-5.0.5/main/fopen_wrappers.c 2005-07-16 14:14:44.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/main/fopen_wrappers.c 2005-09-07 13:49:17.000000000 +0200 +@@ -155,6 +155,21 @@ + char *pathbuf; + char *ptr; + char *end; ++ char path_copy[MAXPATHLEN]; ++ int path_len; ++ ++ /* Special case path ends with a trailing slash */ ++ path_len = strlen(path); ++ if (path_len >= MAXPATHLEN) { ++ errno = EPERM; /* we deny permission to open it */ ++ return -1; ++ } ++ if (path_len > 0 && path[path_len-1] == PHP_DIR_SEPARATOR) { ++ memcpy(path_copy, path, path_len+1); ++ while (path_len > 0 && path_copy[path_len-1] == PHP_DIR_SEPARATOR) path_len--; ++ path_copy[path_len] = '\0'; ++ path = (const char *)&path_copy; ++ } + + pathbuf = estrdup(PG(open_basedir)); + +diff -Nura php-5.0.5/main/hardened_globals.h hardening-patch-5.0.5-0.4.2/main/hardened_globals.h +--- php-5.0.5/main/hardened_globals.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/main/hardened_globals.h 2005-09-07 13:49:17.000000000 +0200 +@@ -0,0 +1,60 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_GLOBALS_H ++#define HARDENED_GLOBALS_H ++ ++typedef struct _hardened_globals hardened_globals_struct; ++ ++#ifdef ZTS ++# define HG(v) TSRMG(hardened_globals_id, hardened_globals_struct *, v) ++extern int hardened_globals_id; ++#else ++# define HG(v) (hardened_globals.v) ++extern struct _hardened_globals hardened_globals; ++#endif ++ ++ ++struct _hardened_globals { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_1; ++ unsigned int canary_2; ++#endif ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_3; ++ unsigned int canary_4; ++ unsigned int ll_canary_inited; ++#endif ++ zend_bool hphp_sql_bailout_on_error; ++ zend_bool hphp_multiheader; ++ HashTable *eval_whitelist; ++ HashTable *eval_blacklist; ++ HashTable *func_whitelist; ++ HashTable *func_blacklist; ++ unsigned int dummy; ++}; ++ ++ ++#endif /* HARDENED_GLOBALS_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nura php-5.0.5/main/hardening_patch.c hardening-patch-5.0.5-0.4.2/main/hardening_patch.c +--- php-5.0.5/main/hardening_patch.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/main/hardening_patch.c 2005-09-07 14:19:05.000000000 +0200 +@@ -0,0 +1,323 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: hardening_patch.c,v 1.2 2004/11/21 09:38:52 ionic Exp $ */ ++ ++#include "php.h" ++ ++#include ++#include ++ ++#if HAVE_UNISTD_H ++#include ++#endif ++#include "SAPI.h" ++#include "php_globals.h" ++ ++#if HARDENING_PATCH ++ ++#ifdef HAVE_SYS_SOCKET_H ++#include ++#endif ++ ++#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE) ++#undef AF_UNIX ++#endif ++ ++#if defined(AF_UNIX) ++#include ++#endif ++ ++#define SYSLOG_PATH "/dev/log" ++ ++#include "snprintf.h" ++ ++#include "hardening_patch.h" ++ ++#ifdef ZTS ++#include "hardened_globals.h" ++int hardened_globals_id; ++#else ++struct _hardened_globals hardened_globals; ++#endif ++ ++static void hardened_globals_ctor(hardened_globals_struct *hardened_globals TSRMLS_DC) ++{ ++ memset(hardened_globals, 0, sizeof(*hardened_globals)); ++} ++ ++ ++PHPAPI void hardened_startup() ++{ ++#ifdef ZTS ++ ts_allocate_id(&hardened_globals_id, sizeof(hardened_globals_struct), (ts_allocate_ctor) hardened_globals_ctor, NULL); ++#else ++ hardened_globals_ctor(&hardened_globals TSRMLS_CC); ++#endif ++} ++ ++char *loglevel2string(int loglevel) ++{ ++ switch (loglevel) { ++ case S_FILES: ++ return "FILES"; ++ case S_INCLUDE: ++ return "INCLUDE"; ++ case S_MEMORY: ++ return "MEMORY"; ++ case S_MISC: ++ return "MISC"; ++ case S_SQL: ++ return "SQL"; ++ case S_EXECUTOR: ++ return "EXECUTOR"; ++ case S_VARS: ++ return "VARS"; ++ default: ++ return "UNKNOWN"; ++ } ++} ++ ++PHPAPI void php_security_log(int loglevel, char *fmt, ...) ++{ ++#if defined(AF_UNIX) ++ int s, r, i=0; ++ struct sockaddr_un saun; ++ char buf[4096+64]; ++ char error[4096+100]; ++ char *ip_address; ++ char *fname; ++ int lineno; ++ va_list ap; ++ TSRMLS_FETCH(); ++ ++ if (EG(hphp_log_use_x_forwarded_for)) { ++ ip_address = sapi_getenv("HTTP_X_FORWARDED_FOR", 20 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "X-FORWARDED-FOR not set"; ++ } ++ } else { ++ ip_address = sapi_getenv("REMOTE_ADDR", 11 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "REMOTE_ADDR not set"; ++ } ++ } ++ ++ ++ va_start(ap, fmt); ++ ap_php_vsnprintf(error, sizeof(error), fmt, ap); ++ va_end(ap); ++ while (error[i]) { ++ if (error[i] < 32) error[i] = '.'; ++ i++; ++ } ++ ++ if (zend_is_executing(TSRMLS_C)) { ++ lineno = zend_get_executed_lineno(TSRMLS_C); ++ fname = zend_get_executed_filename(TSRMLS_C); ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s', line %u)", error, ip_address, fname, lineno); ++ } else { ++ fname = sapi_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC); ++ if (fname==NULL) { ++ fname = "unknown"; ++ } ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s')", error, ip_address, fname); ++ } ++ ++ /* Syslog-Logging disabled? */ ++ if ((EG(hphp_log_syslog) & loglevel)==0) { ++ goto log_sapi; ++ } ++ ++ ap_php_snprintf(error, sizeof(error), "<%u>hphp[%u]: %s\n", EG(hphp_log_syslog_facility)|EG(hphp_log_syslog_priority),getpid(),buf); ++ ++ s = socket(AF_UNIX, SOCK_DGRAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ s = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ goto log_sapi; ++ } ++ } ++ send(s, error, strlen(error), 0); ++ ++ close(s); ++ ++log_sapi: ++ /* SAPI Logging activated? */ ++ if ((EG(hphp_log_syslog) & loglevel)!=0) { ++ sapi_module.log_message(buf); ++ } ++ ++log_script: ++ /* script logging activaed? */ ++ if (((EG(hphp_log_script) & loglevel)!=0) && EG(hphp_log_scriptname)!=NULL) { ++ char cmd[8192], *cmdpos, *bufpos; ++ FILE *in; ++ int space; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s \'", EG(hphp_log_scriptname), loglevel2string(loglevel)); ++ space = sizeof(cmd) - strlen(cmd); ++ cmdpos = cmd + strlen(cmd); ++ bufpos = buf; ++ if (space <= 1) return; ++ while (space > 2 && *bufpos) { ++ if (*bufpos == '\'') { ++ if (space<=5) break; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\\'; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\''; ++ bufpos++; ++ space-=4; ++ } else { ++ *cmdpos++ = *bufpos++; ++ space--; ++ } ++ } ++ *cmdpos++ = '\''; ++ *cmdpos = 0; ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_INTERNAL, "Unable to execute logging shell script: %s", EG(hphp_log_scriptname)); ++ return; ++ } ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ } ++ pclose(in); ++ } ++ ++#endif ++} ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++PHPAPI unsigned int php_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++ ++PHPAPI int php_is_valid_include(zval *z) ++{ ++ char *filename; ++ int len, i; ++ TSRMLS_FETCH(); ++ ++ /* must be of type string */ ++ if (z->type != IS_STRING || z->value.str.val == NULL) { ++ return (0); ++ } ++ ++ /* short cut */ ++ filename = z->value.str.val; ++ len = z->value.str.len; ++ ++ /* 1. must be shorter than MAXPATHLEN */ ++ if (len > MAXPATHLEN) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') longer than MAXPATHLEN chars", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 2. must not be cutted */ ++ if (len != strlen(filename)) { ++ char *fname = estrndup(filename, len); ++ for (i=0; fname[i]; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename truncated by a \\0 after '%s'", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 3. must not be a URL */ ++ if (strstr(filename, "://")) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') is an URL", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 4. must not be an uploaded file */ ++ if (SG(rfc1867_uploaded_files)) { ++ if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, len+1)) { ++ php_security_log(S_INCLUDE, "Include filename is an uploaded file"); ++ return (0); ++ } ++ } ++ ++ /* passed all tests */ ++ return (1); ++} ++ ++#endif ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-5.0.5/main/hardening_patch.h hardening-patch-5.0.5-0.4.2/main/hardening_patch.h +--- php-5.0.5/main/hardening_patch.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/main/hardening_patch.h 2005-09-07 14:19:05.000000000 +0200 +@@ -0,0 +1,46 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENING_PATCH_H ++#define HARDENING_PATCH_H ++ ++#include "zend.h" ++ ++#if HARDENING_PATCH ++PHPAPI void php_security_log(int loglevel, char *fmt, ...); ++PHPAPI void hardened_startup(); ++#define HARDENING_PATCH_VERSION "0.4.2" ++ ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++PHPAPI unsigned int php_canary(); ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++PHPAPI int php_is_valid_include(zval *z); ++#endif ++ ++#endif /* HARDENING_PATCH_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nura php-5.0.5/main/hardening_patch.m4 hardening-patch-5.0.5-0.4.2/main/hardening_patch.m4 +--- php-5.0.5/main/hardening_patch.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/main/hardening_patch.m4 2005-09-07 13:49:17.000000000 +0200 +@@ -0,0 +1,95 @@ ++dnl ++dnl $Id: hardening_patch.m4,v 1.1 2004/11/14 13:24:24 ionic Exp $ ++dnl ++dnl This file contains Hardening Patch for PHP specific autoconf functions. ++dnl ++ ++AC_ARG_ENABLE(hardening-patch-mm-protect, ++[ --disable-hardening-patch-mm-protect Disable the Memory Manager protection.],[ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-ll-protect, ++[ --disable-hardening-patch-ll-protect Disable the Linked List protection.],[ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-inc-protect, ++[ --disable-hardening-patch-inc-protect Disable include/require protection.],[ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-fmt-protect, ++[ --disable-hardening-patch-fmt-protect Disable format string protection.],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-hash-protect, ++[ --disable-hardening-patch-hash-protect Disable HashTable destructor protection.],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++]) ++ ++AC_MSG_CHECKING(whether to protect the Zend Memory Manager) ++AC_MSG_RESULT($DO_HARDENING_PATCH_MM_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the Zend Linked Lists) ++AC_MSG_RESULT($DO_HARDENING_PATCH_LL_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect include/require statements) ++AC_MSG_RESULT($DO_HARDENING_PATCH_INC_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect PHP Format String functions) ++AC_MSG_RESULT($DO_HARDENING_PATCH_FMT_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the destructor of Zend HashTables) ++AC_MSG_RESULT($DO_HARDENING_PATCH_HASH_PROTECT) ++ ++ ++AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 1, [Memory Manager Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 0, [Memory Manager Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 1, [Linked List Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 0, [Linked List Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 1, [Include/Require Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 0, [Include/Require Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 1, [Fmt String Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 0, [Fmt String Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 1, [HashTable DTOR Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 0, [HashTable DTOR Protection]) ++fi ++ +diff -Nura php-5.0.5/main/main.c hardening-patch-5.0.5-0.4.2/main/main.c +--- php-5.0.5/main/main.c 2005-08-16 20:11:34.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/main/main.c 2005-09-07 13:49:17.000000000 +0200 +@@ -85,6 +85,10 @@ + + #include "SAPI.h" + #include "rfc1867.h" ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#endif ++ + /* }}} */ + + #ifndef ZTS +@@ -109,10 +113,33 @@ + */ + static PHP_INI_MH(OnChangeMemoryLimit) + { ++#if HARDENING_PATCH ++ long orig_memory_limit; ++ ++ if (entry->modified) { ++ orig_memory_limit = zend_atoi(entry->orig_value, entry->orig_value_length); ++ } else { ++ orig_memory_limit = 1<<30; ++ } ++ if (orig_memory_limit < 0 || orig_memory_limit > (1<<30)) { ++ orig_memory_limit = 1<<30; ++ } ++#endif + if (new_value) { + PG(memory_limit) = zend_atoi(new_value, new_value_length); ++#if HARDENING_PATCH ++ if (PG(memory_limit) > orig_memory_limit) { ++ PG(memory_limit) = orig_memory_limit; ++ php_security_log(S_MISC, "script tried to increase memory_limit above allowed value"); ++ return FAILURE; ++ } ++#endif + } else { ++#if HARDENING_PATCH ++ PG(memory_limit) = orig_memory_limit; ++#else + PG(memory_limit) = 1<<30; /* effectively, no limit */ ++#endif + } + return zend_set_memory_limit(PG(memory_limit)); + } +@@ -1322,6 +1349,10 @@ + tsrm_ls = ts_resource(0); + #endif + ++#if HARDENING_PATCH ++ hardened_startup(); ++#endif ++ + module_shutdown = 0; + module_startup = 1; + sapi_initialize_empty_request(TSRMLS_C); +@@ -1335,6 +1366,12 @@ + + php_output_startup(); + ++#if HARDENING_PATCH_INC_PROTECT ++ zuf.is_valid_include = php_is_valid_include; ++#endif ++#if HARDENING_PATCH ++ zuf.security_log_function = php_security_log; ++#endif + zuf.error_function = php_error_cb; + zuf.printf_function = php_printf; + zuf.write_function = php_body_write_wrapper; +@@ -1438,6 +1475,10 @@ + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, sizeof(PHP_CONFIG_FILE_PATH)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("HARDENING_PATCH", 1, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_STRINGL_CONSTANT("HARDENING_PATCH_VERSION", HARDENING_PATCH_VERSION, sizeof(HARDENING_PATCH_VERSION)-1, CONST_PERSISTENT | CONST_CS); ++#endif + REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("PHP_INT_MAX", LONG_MAX, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", sizeof(long), CONST_PERSISTENT | CONST_CS); +diff -Nura php-5.0.5/main/php_config.h.in hardening-patch-5.0.5-0.4.2/main/php_config.h.in +--- php-5.0.5/main/php_config.h.in 2005-09-05 13:16:27.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/main/php_config.h.in 2005-09-07 13:49:17.000000000 +0200 +@@ -752,6 +752,39 @@ + /* Enabling BIND8 compatibility for Panther */ + #undef BIND_8_COMPAT + ++/* Hardening-Patch for PHP */ ++#undef HARDENING_PATCH ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ + /* Whether you have AOLserver */ + #undef HAVE_AOLSERVER + +@@ -1083,6 +1116,12 @@ + /* Define if you have the getaddrinfo function */ + #undef HAVE_GETADDRINFO + ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ + /* Whether system headers declare timezone */ + #undef HAVE_DECLARED_TIMEZONE + +diff -Nura php-5.0.5/main/php.h hardening-patch-5.0.5-0.4.2/main/php.h +--- php-5.0.5/main/php.h 2005-06-29 08:41:15.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/main/php.h 2005-09-07 13:49:17.000000000 +0200 +@@ -35,11 +35,19 @@ + #include "zend_qsort.h" + #include "php_compat.h" + ++ + #include "zend_API.h" + + #undef sprintf + #define sprintf php_sprintf + ++#if HARDENING_PATCH ++#if HAVE_REALPATH ++#undef realpath ++#define realpath php_realpath ++#endif ++#endif ++ + /* PHP's DEBUG value must match Zend's ZEND_DEBUG value */ + #undef PHP_DEBUG + #define PHP_DEBUG ZEND_DEBUG +@@ -330,6 +338,7 @@ + #define PHP_FUNCTION ZEND_FUNCTION + #define PHP_METHOD ZEND_METHOD + ++#define PHP_STATIC_FE ZEND_STATIC_FE + #define PHP_NAMED_FE ZEND_NAMED_FE + #define PHP_FE ZEND_FE + #define PHP_FALIAS ZEND_FALIAS +@@ -435,6 +444,10 @@ + #endif + #endif /* !XtOffsetOf */ + ++#if HARDENING_PATCH ++#include "hardening_patch.h" ++#endif ++ + #endif + + /* +diff -Nura php-5.0.5/main/php_variables.c hardening-patch-5.0.5-0.4.2/main/php_variables.c +--- php-5.0.5/main/php_variables.c 2005-09-01 21:15:51.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/main/php_variables.c 2005-09-07 13:49:17.000000000 +0200 +@@ -514,7 +514,7 @@ + */ + static inline void php_register_server_variables(TSRMLS_D) + { +- zval *array_ptr=NULL; ++ zval *array_ptr=NULL, *vptr; + /* turn off magic_quotes while importing server variables */ + int magic_quotes_gpc = PG(magic_quotes_gpc); + +@@ -530,6 +530,16 @@ + /* Server variables */ + if (sapi_module.register_server_variables) { + sapi_module.register_server_variables(array_ptr TSRMLS_CC); ++ if (zend_hash_find(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA"), (void **)&vptr)==SUCCESS) { ++ char *str; ++ if (vptr->type != IS_STRING) { ++ str = "Array"; ++ } else { ++ str = vptr->value.str.val; ++ } ++ php_security_log(S_VARS, "Attacker tried to overwrite HTTP_RAW_POST_DATA with '%s' through a HTTP header", str); ++ zend_hash_del(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA")); ++ } + } + + /* PHP Authentication support */ +diff -Nura php-5.0.5/main/rfc1867.c hardening-patch-5.0.5-0.4.2/main/rfc1867.c +--- php-5.0.5/main/rfc1867.c 2005-07-13 22:51:12.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/main/rfc1867.c 2005-09-07 14:14:13.000000000 +0200 +@@ -132,6 +132,7 @@ + #define UPLOAD_ERROR_D 4 /* No file uploaded */ + #define UPLOAD_ERROR_E 6 /* Missing /tmp or similar directory */ + #define UPLOAD_ERROR_F 7 /* Failed to write file to disk */ ++#define UPLOAD_ERROR_X 32 /* Filter forbids fileupload */ + + void php_rfc1867_register_constants(TSRMLS_D) + { +@@ -142,6 +143,7 @@ + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE", UPLOAD_ERROR_D, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_CANT_WRITE", UPLOAD_ERROR_F, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FILTER", UPLOAD_ERROR_X, CONST_CS | CONST_PERSISTENT); + } + + static void normalize_protected_variable(char *varname TSRMLS_DC) +@@ -854,6 +856,7 @@ + char buff[FILLUNIT]; + char *cd=NULL,*param=NULL,*filename=NULL, *tmp=NULL; + int blen=0, wlen=0; ++ unsigned long offset; + + zend_llist_clean(&header); + +@@ -994,6 +997,11 @@ + cancel_upload = UPLOAD_ERROR_D; + } + ++ if (sapi_module.pre_upload_filter && sapi_module.pre_upload_filter(param, filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_X; ++ } ++ ++ offset = 0; + end = 0; + while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC))) + { +@@ -1008,6 +1016,10 @@ + #endif + cancel_upload = UPLOAD_ERROR_B; + } else if (blen > 0) { ++ if (sapi_module.upload_content_filter && sapi_module.upload_content_filter(offset, buff, blen, &blen TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_X; ++ } ++ + wlen = write(fd, buff, blen); + + if (wlen < blen) { +@@ -1036,6 +1048,10 @@ + } + #endif + ++ if (!cancel_upload && sapi_module.post_upload_filter && sapi_module.post_upload_filter(temp_filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_X; ++ } ++ + if (cancel_upload) { + if (temp_filename) { + if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */ +diff -Nura php-5.0.5/main/SAPI.c hardening-patch-5.0.5-0.4.2/main/SAPI.c +--- php-5.0.5/main/SAPI.c 2005-02-22 15:46:15.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/main/SAPI.c 2005-09-07 13:49:17.000000000 +0200 +@@ -821,6 +821,30 @@ + zend_hash_del(&known_post_content_types, post_entry->content_type, post_entry->content_type_len+1); + } + ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) ++{ ++ sapi_module.input_filter = input_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)) ++{ ++ sapi_module.pre_upload_filter = pre_upload_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)) ++{ ++ sapi_module.upload_content_filter = upload_content_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)) ++{ ++ sapi_module.post_upload_filter = post_upload_filter; ++ return SUCCESS; ++} ++ + + SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D)) + { +@@ -835,11 +859,6 @@ + return SUCCESS; + } + +-SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) +-{ +- sapi_module.input_filter = input_filter; +- return SUCCESS; +-} + + SAPI_API int sapi_flush(TSRMLS_D) + { +diff -Nura php-5.0.5/main/SAPI.h hardening-patch-5.0.5-0.4.2/main/SAPI.h +--- php-5.0.5/main/SAPI.h 2004-01-08 18:33:04.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/main/SAPI.h 2005-09-07 13:49:17.000000000 +0200 +@@ -103,9 +103,10 @@ + char *current_user; + int current_user_length; + +- /* this is necessary for CLI module */ +- int argc; +- char **argv; ++ /* this is necessary for CLI module */ ++ int argc; ++ char **argv; ++ + } sapi_request_info; + + +@@ -183,6 +184,10 @@ + SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC)); + SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)); + ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)); ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)); ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)); ++ + SAPI_API int sapi_flush(TSRMLS_D); + SAPI_API struct stat *sapi_get_stat(TSRMLS_D); + SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC); +@@ -245,6 +250,10 @@ + int (*get_target_gid)(gid_t * TSRMLS_DC); + + unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); ++ ++ unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC); ++ unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC); ++ unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC); + + void (*ini_defaults)(HashTable *configuration_hash); + int phpinfo_as_text; +@@ -270,7 +279,11 @@ + + #define SAPI_DEFAULT_MIMETYPE "text/html" + #define SAPI_DEFAULT_CHARSET "" ++#if HARDENING_PATCH ++#define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION " with Hardening-Patch" ++#else + #define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION ++#endif + + #define SAPI_POST_READER_FUNC(post_reader) void post_reader(TSRMLS_D) + #define SAPI_POST_HANDLER_FUNC(post_handler) void post_handler(char *content_type_dup, void *arg TSRMLS_DC) +@@ -278,6 +291,10 @@ + #define SAPI_TREAT_DATA_FUNC(treat_data) void treat_data(int arg, char *str, zval* destArray TSRMLS_DC) + #define SAPI_INPUT_FILTER_FUNC(input_filter) unsigned int input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) + ++#define SAPI_PRE_UPLOAD_FILTER_FUNC(pre_upload_filter) unsigned int pre_upload_filter(char *varname, char *filename TSRMLS_DC) ++#define SAPI_UPLOAD_CONTENT_FILTER_FUNC(upload_content_filter) unsigned int upload_content_filter(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC) ++#define SAPI_POST_UPLOAD_FILTER_FUNC(post_upload_filter) unsigned int post_upload_filter(char *tmpfilename TSRMLS_DC) ++ + BEGIN_EXTERN_C() + SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data); + SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader); +diff -Nura php-5.0.5/main/snprintf.c hardening-patch-5.0.5-0.4.2/main/snprintf.c +--- php-5.0.5/main/snprintf.c 2004-11-16 00:14:40.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/main/snprintf.c 2005-09-07 13:49:17.000000000 +0200 +@@ -1013,7 +1013,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Nura php-5.0.5/main/spprintf.c hardening-patch-5.0.5-0.4.2/main/spprintf.c +--- php-5.0.5/main/spprintf.c 2004-04-16 01:04:49.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/main/spprintf.c 2005-09-07 13:49:17.000000000 +0200 +@@ -630,7 +630,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = xbuf->len; ++#endif + break; + + /* +diff -Nura php-5.0.5/php.ini-dist hardening-patch-5.0.5-0.4.2/php.ini-dist +--- php-5.0.5/php.ini-dist 2005-05-05 14:33:56.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/php.ini-dist 2005-09-07 13:49:17.000000000 +0200 +@@ -1197,6 +1197,185 @@ + ; instead of original one. + soap.wsdl_cache_ttl=86400 + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's Executor options ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++; White-/blacklist for function calls during normal execution ++;hphp.executor.func.whitelist = ord,chr ++;hphp.executor.func.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for function calls during eval() execution ++;hphp.executor.eval.whitelist = ord,chr ++;hphp.executor.eval.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nura php-5.0.5/php.ini-recommended hardening-patch-5.0.5-0.4.2/php.ini-recommended +--- php-5.0.5/php.ini-recommended 2005-05-05 14:33:56.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/php.ini-recommended 2005-09-07 13:49:17.000000000 +0200 +@@ -1255,6 +1255,184 @@ + ; instead of original one. + soap.wsdl_cache_ttl=86400 + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's Executor options ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++; White-/blacklist for function calls during normal execution ++;hphp.executor.func.whitelist = ord,chr ++;hphp.executor.func.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for function calls during eval() execution ++;hphp.executor.eval.whitelist = ord,chr ++;hphp.executor.eval.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nura php-5.0.5/sapi/apache/mod_php5.c hardening-patch-5.0.5-0.4.2/sapi/apache/mod_php5.c +--- php-5.0.5/sapi/apache/mod_php5.c 2005-08-01 10:12:42.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/sapi/apache/mod_php5.c 2005-09-07 13:49:17.000000000 +0200 +@@ -455,7 +455,7 @@ + sapi_apache_get_fd, + sapi_apache_force_http_10, + sapi_apache_get_target_uid, +- sapi_apache_get_target_gid ++ sapi_apache_get_target_gid, + }; + /* }}} */ + +@@ -907,7 +907,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component("PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component("PHP/" PHP_VERSION); ++#endif + } + } + #endif +diff -Nura php-5.0.5/sapi/apache2filter/sapi_apache2.c hardening-patch-5.0.5-0.4.2/sapi/apache2filter/sapi_apache2.c +--- php-5.0.5/sapi/apache2filter/sapi_apache2.c 2005-07-16 14:30:10.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/sapi/apache2filter/sapi_apache2.c 2005-09-07 13:49:17.000000000 +0200 +@@ -562,7 +562,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nura php-5.0.5/sapi/apache2handler/sapi_apache2.c hardening-patch-5.0.5-0.4.2/sapi/apache2handler/sapi_apache2.c +--- php-5.0.5/sapi/apache2handler/sapi_apache2.c 2005-09-02 15:51:26.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/sapi/apache2handler/sapi_apache2.c 2005-09-07 13:49:17.000000000 +0200 +@@ -333,7 +333,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nura php-5.0.5/sapi/cgi/cgi_main.c hardening-patch-5.0.5-0.4.2/sapi/cgi/cgi_main.c +--- php-5.0.5/sapi/cgi/cgi_main.c 2005-04-28 16:24:21.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/sapi/cgi/cgi_main.c 2005-09-07 13:49:17.000000000 +0200 +@@ -1419,11 +1419,19 @@ + SG(headers_sent) = 1; + SG(request_info).no_headers = 1; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit(1); + break; +diff -Nura php-5.0.5/sapi/cli/php_cli.c hardening-patch-5.0.5-0.4.2/sapi/cli/php_cli.c +--- php-5.0.5/sapi/cli/php_cli.c 2005-03-22 16:09:20.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/sapi/cli/php_cli.c 2005-09-07 13:49:17.000000000 +0200 +@@ -694,11 +694,19 @@ + if (php_request_startup(TSRMLS_C)==FAILURE) { + goto err; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit_status=1; + goto out; +diff -Nura php-5.0.5/TSRM/TSRM.h hardening-patch-5.0.5-0.4.2/TSRM/TSRM.h +--- php-5.0.5/TSRM/TSRM.h 2005-03-11 12:12:07.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/TSRM/TSRM.h 2005-09-07 13:49:17.000000000 +0200 +@@ -33,6 +33,13 @@ + # define TSRM_API + #endif + ++#if HARDENING_PATCH ++# if HAVE_REALPATH ++# undef realpath ++# define realpath php_realpath ++# endif ++#endif ++ + /* Only compile multi-threading functions if we're in ZTS mode */ + #ifdef ZTS + +@@ -88,6 +95,7 @@ + + #define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts + ++ + #ifdef __cplusplus + extern "C" { + #endif +diff -Nura php-5.0.5/TSRM/tsrm_virtual_cwd.c hardening-patch-5.0.5-0.4.2/TSRM/tsrm_virtual_cwd.c +--- php-5.0.5/TSRM/tsrm_virtual_cwd.c 2005-07-16 13:50:59.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/TSRM/tsrm_virtual_cwd.c 2005-09-07 13:49:17.000000000 +0200 +@@ -184,6 +184,165 @@ + return p; + } + ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved) ++{ ++ struct stat sb; ++ char *p, *q, *s; ++ size_t left_len, resolved_len; ++ unsigned symlinks; ++ int serrno, slen; ++ int is_dir = 1; ++ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; ++ ++ serrno = errno; ++ symlinks = 0; ++ if (path[0] == '/') { ++ resolved[0] = '/'; ++ resolved[1] = '\0'; ++ if (path[1] == '\0') ++ return (resolved); ++ resolved_len = 1; ++ left_len = strlcpy(left, path + 1, sizeof(left)); ++ } else { ++ if (getcwd(resolved, PATH_MAX) == NULL) { ++ strlcpy(resolved, ".", PATH_MAX); ++ return (NULL); ++ } ++ resolved_len = strlen(resolved); ++ left_len = strlcpy(left, path, sizeof(left)); ++ } ++ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ ++ /* ++ * Iterate over path components in `left'. ++ */ ++ while (left_len != 0) { ++ /* ++ * Extract the next path component and adjust `left' ++ * and its length. ++ */ ++ p = strchr(left, '/'); ++ s = p ? p : left + left_len; ++ if (s - left >= sizeof(next_token)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ memcpy(next_token, left, s - left); ++ next_token[s - left] = '\0'; ++ left_len -= s - left; ++ if (p != NULL) ++ memmove(left, s + 1, left_len + 1); ++ if (resolved[resolved_len - 1] != '/') { ++ if (resolved_len + 1 >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ resolved[resolved_len++] = '/'; ++ resolved[resolved_len] = '\0'; ++ } ++ if (next_token[0] == '\0') ++ continue; ++ else if (strcmp(next_token, ".") == 0) ++ continue; ++ else if (strcmp(next_token, "..") == 0) { ++ /* ++ * Strip the last path component except when we have ++ * single "/" ++ */ ++ if (!is_dir) { ++ errno = ENOENT; ++ return (NULL); ++ } ++ if (resolved_len > 1) { ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ continue; ++ } ++ ++ /* ++ * Append the next path component and lstat() it. If ++ * lstat() fails we still can return successfully if ++ * there are no more path components left. ++ */ ++ resolved_len = strlcat(resolved, next_token, PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ if (lstat(resolved, &sb) != 0) { ++ if (errno == ENOENT && p == NULL) { ++ errno = serrno; ++ return (resolved); ++ } ++ return (NULL); ++ } ++ if (S_ISLNK(sb.st_mode)) { ++ if (symlinks++ > MAXSYMLINKS) { ++ errno = ELOOP; ++ return (NULL); ++ } ++ slen = readlink(resolved, symlink, sizeof(symlink) - 1); ++ if (slen < 0) ++ return (NULL); ++ symlink[slen] = '\0'; ++ if (symlink[0] == '/') { ++ resolved[1] = 0; ++ resolved_len = 1; ++ } else if (resolved_len > 1) { ++ /* Strip the last path component. */ ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ ++ /* ++ * If there are any path components left, then ++ * append them to symlink. The result is placed ++ * in `left'. ++ */ ++ if (p != NULL) { ++ if (symlink[slen - 1] != '/') { ++ if (slen + 1 >= sizeof(symlink)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ symlink[slen] = '/'; ++ symlink[slen + 1] = 0; ++ } ++ left_len = strlcat(symlink, left, sizeof(left)); ++ if (left_len >= sizeof(left)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ } ++ left_len = strlcpy(left, symlink, sizeof(left)); ++ } else { ++ if (S_ISDIR(sb.st_mode)) { ++ is_dir = 1; ++ } else { ++ is_dir = 0; ++ } ++ } ++ } ++ ++ /* ++ * Remove trailing slash except when the resolved pathname ++ * is a single "/". ++ */ ++ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') ++ resolved[resolved_len - 1] = '\0'; ++ return (resolved); ++} ++#endif ++ + CWD_API void virtual_cwd_startup(void) + { + char cwd[MAXPATHLEN]; +@@ -321,8 +480,7 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now +- return 1; */ ++ return 1; + } + } + } else { /* Concat current directory with relative path and then run realpath() on it */ +@@ -348,9 +506,8 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now + free(tmp); +- return 1; */ ++ return 1; + } + } + free(tmp); +diff -Nura php-5.0.5/TSRM/tsrm_virtual_cwd.h hardening-patch-5.0.5-0.4.2/TSRM/tsrm_virtual_cwd.h +--- php-5.0.5/TSRM/tsrm_virtual_cwd.h 2005-07-16 13:50:59.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/TSRM/tsrm_virtual_cwd.h 2005-09-07 13:49:17.000000000 +0200 +@@ -126,6 +126,22 @@ + + typedef int (*verify_path_func)(const cwd_state *); + ++#ifndef HAVE_STRLCPY ++CWD_API size_t php_strlcpy(char *dst, const char *src, size_t siz); ++#undef strlcpy ++#define strlcpy php_strlcpy ++#endif ++ ++#ifndef HAVE_STRLCAT ++CWD_API size_t php_strlcat(char *dst, const char *src, size_t siz); ++#undef strlcat ++#define strlcat php_strlcat ++#endif ++ ++ ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved); ++#endif + CWD_API void virtual_cwd_startup(void); + CWD_API void virtual_cwd_shutdown(void); + CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC); +diff -Nura php-5.0.5/Zend/zend_alloc.c hardening-patch-5.0.5-0.4.2/Zend/zend_alloc.c +--- php-5.0.5/Zend/zend_alloc.c 2005-08-18 17:14:23.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_alloc.c 2005-09-07 13:49:17.000000000 +0200 +@@ -64,6 +64,11 @@ + # define END_MAGIC_SIZE 0 + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++# define CANARY_SIZE sizeof(unsigned int) ++#else ++# define CANARY_SIZE 0 ++#endif + + # if MEMORY_LIMIT + # if ZEND_DEBUG +@@ -105,9 +110,17 @@ + if (p==AG(head)) { \ + AG(head) = p->pNext; \ + } else { \ ++ if (p != p->pLast->pNext) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pLast->pNext = p->pNext; \ + } \ + if (p->pNext) { \ ++ if (p != p->pNext->pLast) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pNext->pLast = p->pLast; \ + } + #else +@@ -146,6 +159,12 @@ + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (size > LONG_MAX - sizeof(zend_mem_header) - MEM_HEADER_PADDING - END_MAGIC_SIZE - CANARY_SIZE) { ++ zend_security_log(S_MEMORY, "emalloc() - requested size would result in integer overflow"); ++ exit(1); ++ } ++#endif + CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size); + + #if !ZEND_DISABLE_MEMORY_CACHE +@@ -164,6 +183,10 @@ + AG(cache_stats)[CACHE_INDEX][1]++; + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->cached = 0; + p->size = size; + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); +@@ -180,7 +203,7 @@ + AG(allocated_memory_peak) = AG(allocated_memory); + } + #endif +- p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE + CANARY_SIZE); + #if !ZEND_DISABLE_MEMORY_CACHE + } + #endif +@@ -212,7 +235,10 @@ + # endif + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif +- ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); + } +@@ -240,6 +266,10 @@ + } + } + ++ ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by safe_emalloc()"); ++#endif + zend_error(E_ERROR, "Possible integer overflow in memory allocation (%zd * %zd + %zd)", nmemb, size, offset); + return 0; + } +@@ -248,9 +278,25 @@ + + ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p = (zend_mem_header *) ((char *)ptr - sizeof(zend_mem_header) - MEM_HEADER_PADDING); + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); ++ ++#if HARDENING_PATCH_MM_PROTECT ++ if (p->canary != HG(canary_1)) goto efree_canary_mismatch; ++ memcpy(&canary_2, (((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), CANARY_SIZE); ++ if (canary_2 != HG(canary_2)) { ++efree_canary_mismatch: ++ zend_security_log(S_MEMORY, "canary mismatch on efree() - heap overflow or double efree detected"); ++ exit(1); ++ } ++ /* to catch double efree()s */ ++ memset((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), 0, CANARY_SIZE); ++ p->canary = 0; ++#endif + + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { +@@ -292,23 +338,35 @@ + + ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { +- void *p; +- int final_size = size*nmemb; ++ char *p; ++ size_t _size = nmemb * size; ++ ++ if (nmemb && (_size/nmemb!=size)) { ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by ecalloc()"); ++#endif ++ fprintf(stderr,"FATAL: ecalloc(): Unable to allocate %ld * %ld bytes\n", (long) nmemb, (long) size); ++#if ZEND_DEBUG && HAVE_KILL && HAVE_GETPID ++ kill(getpid(), SIGSEGV); ++#else ++ exit(1); ++#endif ++ } + +- HANDLE_BLOCK_INTERRUPTIONS(); +- p = _emalloc(final_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); +- if (!p) { +- HANDLE_UNBLOCK_INTERRUPTIONS(); +- return (void *) p; ++ p = (char *) _emalloc(_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); ++ if (p) { ++ memset(p, 0, _size); + } +- memset(p, 0, final_size); +- HANDLE_UNBLOCK_INTERRUPTIONS(); +- return p; ++ ++ return ((void *)p); + } + + + ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p; + zend_mem_header *orig; + DECLARE_CACHE_VARS(); +@@ -320,6 +378,16 @@ + + p = orig = (zend_mem_header *) ((char *)ptr-sizeof(zend_mem_header)-MEM_HEADER_PADDING); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (p->canary != HG(canary_1)) goto erealloc_canary_mismatch; ++ memcpy(&canary_2, (((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), CANARY_SIZE); ++ if (canary_2 != HG(canary_2)) { ++erealloc_canary_mismatch: ++ zend_security_log(S_MEMORY, "canary mismatch on erealloc() - heap overflow detected"); ++ exit(1); ++ } ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + void *new_p; +@@ -343,7 +411,7 @@ + } + #endif + REMOVE_POINTER_FROM_LIST(p); +- p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE+CANARY_SIZE); + if (!p) { + if (!allow_failure) { + fprintf(stderr,"FATAL: erealloc(): Unable to allocate %ld bytes\n", (long) size); +@@ -365,6 +433,9 @@ + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->size = size; + + HANDLE_UNBLOCK_INTERRUPTIONS(); +@@ -439,6 +510,10 @@ + { + AG(head) = NULL; + ++#if HARDENING_PATCH_MM_PROTECT ++ HG(canary_1) = zend_canary(); ++ HG(canary_2) = zend_canary(); ++#endif + #if MEMORY_LIMIT + AG(memory_limit) = 1<<30; /* ridiculous limit, effectively no limit */ + AG(allocated_memory) = 0; +diff -Nura php-5.0.5/Zend/zend_alloc.h hardening-patch-5.0.5-0.4.2/Zend/zend_alloc.h +--- php-5.0.5/Zend/zend_alloc.h 2005-06-07 15:37:13.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_alloc.h 2005-09-07 13:49:17.000000000 +0200 +@@ -35,6 +35,9 @@ + #define MEM_BLOCK_CACHED_MAGIC 0xFB8277DCL + + typedef struct _zend_mem_header { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary; ++#endif + #if ZEND_DEBUG + long magic; + char *filename; +diff -Nura php-5.0.5/Zend/zend_API.h hardening-patch-5.0.5-0.4.2/Zend/zend_API.h +--- php-5.0.5/Zend/zend_API.h 2005-06-27 19:42:06.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_API.h 2005-09-07 13:49:17.000000000 +0200 +@@ -47,6 +47,7 @@ + #define ZEND_METHOD(classname, name) ZEND_NAMED_FUNCTION(ZEND_FN(classname##_##name)) + + #define ZEND_FENTRY(zend_name, name, arg_info, flags) { #zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeof(struct _zend_arg_info)-1), flags }, ++#define ZEND_STATIC_FE(zend_name, name, arg_info) { zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeof(struct _zend_arg_info)-1), 0 }, + + #define ZEND_NAMED_FE(zend_name, name, arg_info) ZEND_FENTRY(zend_name, name, arg_info, 0) + #define ZEND_FE(name, arg_info) ZEND_FENTRY(name, ZEND_FN(name), arg_info, 0) +diff -Nura php-5.0.5/Zend/zend_builtin_functions.c hardening-patch-5.0.5-0.4.2/Zend/zend_builtin_functions.c +--- php-5.0.5/Zend/zend_builtin_functions.c 2005-06-27 19:42:06.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_builtin_functions.c 2005-09-07 13:49:17.000000000 +0200 +@@ -52,6 +52,9 @@ + static ZEND_FUNCTION(crash); + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++static ZEND_FUNCTION(heap_overflow); ++#endif + static ZEND_FUNCTION(get_included_files); + static ZEND_FUNCTION(is_subclass_of); + static ZEND_FUNCTION(is_a); +@@ -111,6 +114,9 @@ + ZEND_FE(crash, NULL) + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ ZEND_FE(heap_overflow, NULL) ++#endif + ZEND_FE(get_included_files, NULL) + ZEND_FALIAS(get_required_files, get_included_files, NULL) + ZEND_FE(is_subclass_of, NULL) +@@ -991,6 +997,19 @@ + + #endif /* ZEND_DEBUG */ + ++ ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ZEND_FUNCTION(heap_overflow) ++{ ++ char *nowhere = emalloc(10); ++ ++ memcpy(nowhere, "something1234567890", sizeof("something1234567890")); ++ ++ efree(nowhere); ++} ++#endif ++ ++ + /* {{{ proto array get_included_files(void) + Returns an array with the file names that were include_once()'d */ + ZEND_FUNCTION(get_included_files) +diff -Nura php-5.0.5/Zend/zend.c hardening-patch-5.0.5-0.4.2/Zend/zend.c +--- php-5.0.5/Zend/zend.c 2005-07-22 09:33:27.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend.c 2005-09-07 14:19:23.000000000 +0200 +@@ -54,6 +54,12 @@ + ZEND_API void (*zend_unblock_interruptions)(void); + ZEND_API void (*zend_ticks_function)(int ticks); + ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); ++#if HARDENING_PATCH ++ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); + + void (*zend_on_timeout)(int seconds TSRMLS_DC); +@@ -72,9 +78,289 @@ + return SUCCESS; + } + ++#if HARDENING_PATCH ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog) = S_ALL & ~S_SQL | S_MEMORY | S_INTERNAL; ++ } else { ++ EG(hphp_log_syslog) = atoi(new_value) | S_MEMORY | S_INTERNAL; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_facility) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_facility) = LOG_USER; ++ } else { ++ EG(hphp_log_syslog_facility) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_priority) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_priority) = LOG_ALERT; ++ } else { ++ EG(hphp_log_syslog_priority) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_sapi) ++{ ++ if (!new_value) { ++ EG(hphp_log_sapi) = S_ALL & ~S_SQL | S_INTERNAL; ++ } else { ++ EG(hphp_log_sapi) = atoi(new_value) | S_INTERNAL; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_script) ++{ ++ if (!new_value) { ++ EG(hphp_log_script) = S_ALL & ~S_MEMORY; ++ } else { ++ EG(hphp_log_script) = atoi(new_value) & (~S_MEMORY) & (~S_INTERNAL); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_scriptname) ++{ ++ if (!new_value) { ++ EG(hphp_log_scriptname) = NULL; ++ } else { ++ if (EG(hphp_log_scriptname)) { ++ pefree(EG(hphp_log_scriptname),1); ++ } ++ EG(hphp_log_scriptname) = pestrdup(new_value,1); ++ } ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_eval_whitelist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++eval_whitelist_destroy: ++ if (HG(eval_whitelist)) { ++ zend_hash_destroy(HG(eval_whitelist)); ++ efree(HG(eval_whitelist)); ++ } ++ HG(eval_whitelist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto eval_whitelist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(eval_whitelist)); ++ zend_hash_init(HG(eval_whitelist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(eval_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(eval_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_eval_blacklist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++eval_blacklist_destroy: ++ if (HG(eval_blacklist)) { ++ zend_hash_destroy(HG(eval_blacklist)); ++ efree(HG(eval_blacklist)); ++ } ++ HG(eval_blacklist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto eval_blacklist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(eval_blacklist)); ++ zend_hash_init(HG(eval_blacklist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(eval_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(eval_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_func_whitelist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++func_whitelist_destroy: ++ if (HG(func_whitelist)) { ++ zend_hash_destroy(HG(func_whitelist)); ++ efree(HG(func_whitelist)); ++ } ++ HG(func_whitelist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto func_whitelist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(func_whitelist)); ++ zend_hash_init(HG(func_whitelist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(func_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(func_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_func_blacklist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++func_blacklist_destroy: ++ if (HG(func_blacklist)) { ++ zend_hash_destroy(HG(func_blacklist)); ++ efree(HG(func_blacklist)); ++ } ++ HG(func_blacklist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto func_blacklist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(func_blacklist)); ++ zend_hash_init(HG(func_blacklist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(func_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(func_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ ++ return SUCCESS; ++} ++ ++#endif + + ZEND_INI_BEGIN() + ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) ++#if HARDENING_PATCH ++ ZEND_INI_ENTRY("hphp.log.syslog", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog) ++ ZEND_INI_ENTRY("hphp.log.syslog.facility", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_facility) ++ ZEND_INI_ENTRY("hphp.log.syslog.priority", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_priority) ++ ZEND_INI_ENTRY("hphp.log.sapi", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_sapi) ++ ZEND_INI_ENTRY("hphp.log.script", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_script) ++ ZEND_INI_ENTRY("hphp.log.script.name", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_scriptname) ++ STD_ZEND_INI_BOOLEAN("hphp.log.use-x-forwarded-for", "0", ZEND_INI_SYSTEM, OnUpdateBool, hphp_log_use_x_forwarded_for, zend_executor_globals, executor_globals) ++ ++ ZEND_INI_ENTRY("hphp.executor.eval.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_eval_whitelist) ++ ZEND_INI_ENTRY("hphp.executor.eval.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_eval_blacklist) ++ ZEND_INI_ENTRY("hphp.executor.func.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_func_whitelist) ++ ZEND_INI_ENTRY("hphp.executor.func.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_func_blacklist) ++ ++ STD_ZEND_INI_ENTRY("hphp.executor.max_depth", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateLong, hphp_executor_max_depth, zend_executor_globals, executor_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.sql.bailout_on_error", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, hphp_sql_bailout_on_error, hardened_globals_struct, hardened_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.multiheader", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, hphp_multiheader, hardened_globals_struct, hardened_globals) ++#endif + STD_ZEND_INI_BOOLEAN("zend.ze1_compatibility_mode", "0", ZEND_INI_ALL, OnUpdateBool, ze1_compatibility_mode, zend_executor_globals, executor_globals) + ZEND_INI_END() + +@@ -476,6 +762,7 @@ + EG(user_error_handler) = NULL; + EG(user_exception_handler) = NULL; + EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(in_autoload) = NULL; + EG(current_execute_data) = NULL; + EG(current_module) = NULL; +@@ -545,6 +832,14 @@ + extern zend_scanner_globals language_scanner_globals; + #endif + ++ /* Set up Hardening-Patch utility functions first */ ++#if HARDENING_PATCH ++ zend_security_log = utility_functions->security_log_function; ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ zend_is_valid_include = utility_functions->is_valid_include; ++#endif ++ + #ifdef ZTS + ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); + #else +@@ -747,6 +1042,7 @@ + } + CG(unclean_shutdown) = 1; + CG(in_compilation) = EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(current_execute_data) = NULL; + longjmp(EG(bailout), FAILURE); + } +diff -Nura php-5.0.5/Zend/zend_canary.c hardening-patch-5.0.5-0.4.2/Zend/zend_canary.c +--- php-5.0.5/Zend/zend_canary.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_canary.c 2005-09-07 13:49:17.000000000 +0200 +@@ -0,0 +1,58 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: zend_canary.c,v 1.1 2004/11/26 12:45:41 ionic Exp $ */ ++ ++#include "zend.h" ++ ++#include ++#include ++ ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++ZEND_API unsigned int zend_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-5.0.5/Zend/zend_compile.c hardening-patch-5.0.5-0.4.2/Zend/zend_compile.c +--- php-5.0.5/Zend/zend_compile.c 2005-07-19 09:33:24.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_compile.c 2005-09-07 13:49:17.000000000 +0200 +@@ -979,6 +979,13 @@ + op_array.prototype = NULL; + + op_array.line_start = zend_get_compiled_lineno(TSRMLS_C); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array.created_by_eval = 1; ++ } else { ++ op_array.created_by_eval = 0; ++ } ++#endif + + if (is_method) { + char *short_class_name = CG(active_class_entry)->name; +diff -Nura php-5.0.5/Zend/zend_compile.h hardening-patch-5.0.5-0.4.2/Zend/zend_compile.h +--- php-5.0.5/Zend/zend_compile.h 2005-06-24 10:45:43.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_compile.h 2005-09-07 13:49:17.000000000 +0200 +@@ -203,6 +203,9 @@ + zend_uint doc_comment_len; + + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; ++#if HARDENING_PATCH ++ zend_bool created_by_eval; ++#endif + }; + + +@@ -281,6 +284,8 @@ + zval *object; + union _temp_variable *Ts; + zend_bool original_in_execution; ++ zend_uint original_in_code_type; ++ zend_uint execute_depth; + zend_class_entry *calling_scope; + struct _zend_execute_data *prev_execute_data; + }; +@@ -774,6 +779,7 @@ + #define ZEND_OVERLOADED_FUNCTION 3 + #define ZEND_EVAL_CODE 4 + #define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5 ++#define ZEND_SANDBOX_CODE 6 + + #define ZEND_INTERNAL_CLASS 1 + #define ZEND_USER_CLASS 2 +diff -Nura php-5.0.5/Zend/zend_constants.c hardening-patch-5.0.5-0.4.2/Zend/zend_constants.c +--- php-5.0.5/Zend/zend_constants.c 2004-07-13 21:22:11.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_constants.c 2005-09-07 14:19:23.000000000 +0200 +@@ -107,6 +107,73 @@ + REGISTER_MAIN_LONG_CONSTANT("E_USER_NOTICE", E_USER_NOTICE, CONST_PERSISTENT | CONST_CS); + + REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("S_MEMORY", S_MEMORY, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_VARS", S_VARS, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_FILES", S_FILES, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INCLUDE", S_INCLUDE, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_SQL", S_SQL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_EXECUTOR", S_EXECUTOR, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_MISC", S_MISC, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INTERNAL", S_INTERNAL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_ALL", S_ALL, CONST_PERSISTENT | CONST_CS); ++ ++ /* error levels */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRIT", LOG_CRIT, CONST_CS | CONST_PERSISTENT); /* critical conditions */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ERR", LOG_ERR, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_WARNING", LOG_WARNING, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOTICE", LOG_NOTICE, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_INFO", LOG_INFO, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DEBUG", LOG_DEBUG, CONST_CS | CONST_PERSISTENT); ++ /* facility: type of program logging the message */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_KERN", LOG_KERN, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_USER", LOG_USER, CONST_CS | CONST_PERSISTENT); /* generic user level */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_MAIL", LOG_MAIL, CONST_CS | CONST_PERSISTENT); /* log to email */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DAEMON", LOG_DAEMON, CONST_CS | CONST_PERSISTENT); /* other system daemons */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTH", LOG_AUTH, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_SYSLOG", LOG_SYSLOG, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LPR", LOG_LPR, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NEWS ++ /* No LOG_NEWS on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NEWS", LOG_NEWS, CONST_CS | CONST_PERSISTENT); /* usenet new */ ++#endif ++#ifdef LOG_UUCP ++ /* No LOG_UUCP on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_UUCP", LOG_UUCP, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_CRON ++ /* apparently some systems don't have this one */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRON", LOG_CRON, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_AUTHPRIV ++ /* AIX doesn't have LOG_AUTHPRIV */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTHPRIV", LOG_AUTHPRIV, CONST_CS | CONST_PERSISTENT); ++#endif ++#if !defined(PHP_WIN32) && !defined(NETWARE) ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL0", LOG_LOCAL0, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL1", LOG_LOCAL1, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL2", LOG_LOCAL2, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL3", LOG_LOCAL3, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL4", LOG_LOCAL4, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL5", LOG_LOCAL5, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL6", LOG_LOCAL6, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL7", LOG_LOCAL7, CONST_CS | CONST_PERSISTENT); ++#endif ++ /* options */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PID", LOG_PID, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CONS", LOG_CONS, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ODELAY", LOG_ODELAY, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NDELAY", LOG_NDELAY, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NOWAIT ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOWAIT", LOG_NOWAIT, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_PERROR ++ /* AIX doesn't have LOG_PERROR */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ ++#endif ++#endif + + /* true/false constants */ + { +diff -Nura php-5.0.5/Zend/zend_errors.h hardening-patch-5.0.5-0.4.2/Zend/zend_errors.h +--- php-5.0.5/Zend/zend_errors.h 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_errors.h 2005-09-07 14:19:23.000000000 +0200 +@@ -38,6 +38,18 @@ + #define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE) + #define E_CORE (E_CORE_ERROR | E_CORE_WARNING) + ++#if HARDENING_PATCH ++#define S_MEMORY (1<<0L) ++#define S_VARS (1<<1L) ++#define S_FILES (1<<2L) ++#define S_INCLUDE (1<<3L) ++#define S_SQL (1<<4L) ++#define S_EXECUTOR (1<<5L) ++#define S_MISC (1<<30L) ++#define S_INTERNAL (1<<29) ++#define S_ALL (S_MEMORY | S_VARS | S_INCLUDE | S_FILES | S_MISC | S_SQL | S_EXECUTOR) ++#endif ++ + #endif /* ZEND_ERRORS_H */ + + /* +diff -Nura php-5.0.5/Zend/zend_execute_API.c hardening-patch-5.0.5-0.4.2/Zend/zend_execute_API.c +--- php-5.0.5/Zend/zend_execute_API.c 2005-09-02 09:46:39.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_execute_API.c 2005-09-07 13:49:17.000000000 +0200 +@@ -137,6 +137,7 @@ + EG(class_table) = CG(class_table); + + EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(in_autoload) = NULL; + + zend_ptr_stack_init(&EG(argument_stack)); +@@ -725,6 +726,39 @@ + if (zend_hash_find(fci->function_table, function_name_lc, fci->function_name->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { + EX(function_state).function = NULL; + } ++#if HARDENING_PATCH ++ else { ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), function_name_lc, fci->function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", function_name_lc); ++ efree(function_name_lc); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), function_name_lc, fci->function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", function_name_lc); ++ efree(function_name_lc); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), function_name_lc, fci->function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", function_name_lc); ++ efree(function_name_lc); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), function_name_lc, fci->function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", function_name_lc); ++ efree(function_name_lc); ++ zend_bailout(); ++ } ++ } ++ } ++#endif + efree(function_name_lc); + } + +@@ -999,7 +1033,7 @@ + return retval; + } + +-ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) ++ZEND_API int zend_eval_string_ex_ex(char *str, zval *retval_ptr, char *string_name, int type TSRMLS_DC) + { + zval pv; + zend_op_array *new_op_array; +@@ -1032,6 +1066,7 @@ + zval **original_return_value_ptr_ptr = EG(return_value_ptr_ptr); + zend_op **original_opline_ptr = EG(opline_ptr); + ++ new_op_array->type = type; + EG(return_value_ptr_ptr) = &local_retval_ptr; + EG(active_op_array) = new_op_array; + EG(no_extensions)=1; +@@ -1066,6 +1101,12 @@ + } + + ++ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) ++{ ++ return (zend_eval_string_ex_ex(str, retval_ptr, string_name, ZEND_EVAL_CODE TSRMLS_CC)); ++} ++ ++ + ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC) + { + int result; +diff -Nura php-5.0.5/Zend/zend_execute.c hardening-patch-5.0.5-0.4.2/Zend/zend_execute.c +--- php-5.0.5/Zend/zend_execute.c 2005-09-01 15:21:56.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_execute.c 2005-09-07 13:49:17.000000000 +0200 +@@ -1374,6 +1374,7 @@ + efree(EX(Ts)); \ + } \ + EG(in_execution) = EX(original_in_execution); \ ++ EG(in_code_type) = EX(original_in_code_type); \ + EG(current_execute_data) = EX(prev_execute_data); \ + return 1; /* CHECK_ME */ + +@@ -1400,6 +1401,16 @@ + EX(original_in_execution) = EG(in_execution); + EX(prev_execute_data) = EG(current_execute_data); + EG(current_execute_data) = &execute_data; ++#if HARDENING_PATCH ++ EX(execute_depth) = 0; ++ ++ if ((op_array->type == ZEND_EVAL_CODE || op_array->created_by_eval)&& EG(in_code_type) != ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } else if (op_array->type == ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_SANDBOX_CODE; ++ op_array->type = ZEND_EVAL_CODE; ++ } ++#endif + + EG(in_execution) = 1; + if (op_array->start_op) { +@@ -1426,6 +1437,19 @@ + EX(function_state).function_symbol_table = NULL; + #endif + ++#if HARDENING_PATCH ++ if (EX(prev_execute_data) == NULL) { ++ EX(execute_depth) = 0; ++ } else { ++ EX(execute_depth) = EX(prev_execute_data)->execute_depth + 1; ++ } ++ ++ if (EG(hphp_executor_max_depth) > 0 && EX(execute_depth) > EG(hphp_executor_max_depth)) { ++ zend_security_log(S_EXECUTOR, "Maximum execution depth of %u violated", EG(hphp_executor_max_depth)); ++ zend_bailout(); ++ } ++#endif ++ + while (1) { + #ifdef ZEND_WIN32 + if (EG(timed_out)) { +@@ -2680,6 +2704,37 @@ + efree(lcname); + zend_error(E_ERROR, "Call to undefined function %s()", function_name_strval); + } ++#if HARDENING_PATCH ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), lcname, function_name_strlen+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", lcname); ++ efree(lcname); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), lcname, function_name_strlen+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", lcname); ++ efree(lcname); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), lcname, function_name_strlen+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", lcname); ++ efree(lcname); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), lcname, function_name_strlen+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", lcname); ++ efree(lcname); ++ zend_bailout(); ++ } ++ } ++#endif + + efree(lcname); + if (!is_const) { +@@ -2886,6 +2941,34 @@ + if (zend_hash_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { + zend_error(E_ERROR, "Unknown function: %s()\n", fname->value.str.val); + } ++#if HARDENING_PATCH ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } ++#endif ++ + EX(object) = NULL; + EX(calling_scope) = EX(function_state).function->common.scope; + +@@ -3573,7 +3656,12 @@ + int dummy = 1; + zend_file_handle file_handle; + ++#if HARDENING_PATCH_INC_PROTECT ++ if (zend_is_valid_include(inc_filename) ++ && (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC))) { ++#else + if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) { ++#endif + + if (!file_handle.opened_path) { + file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len); +@@ -3598,6 +3686,11 @@ + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: ++#if HARDENING_PATCH_INC_PROTECT ++ if (!zend_is_valid_include(inc_filename)) { ++ break; ++ } ++#endif + new_op_array = compile_filename(opline->op2.u.constant.value.lval, inc_filename TSRMLS_CC); + break; + case ZEND_EVAL: { +diff -Nura php-5.0.5/Zend/zend_extensions.c hardening-patch-5.0.5-0.4.2/Zend/zend_extensions.c +--- php-5.0.5/Zend/zend_extensions.c 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_extensions.c 2005-09-07 13:49:17.000000000 +0200 +@@ -55,23 +55,44 @@ + return FAILURE; + } + ++ /* check if module is compiled against Hardening-Patch */ ++ if (extension_version_info->zend_extension_api_no < 1000000000) { ++ fprintf(stderr, "%s is not compiled with Hardening-Patch.\n" ++ "The Hardening-Patch version %d is installed.\n\n", ++ new_extension->name, ++ HARDENING_PATCH_ZEND_EXTENSION_API_NO); ++ DL_UNLOAD(handle); ++ return FAILURE; ++ } ++ ++ ++ /* check if module is compiled against correct Hardening-Patch version */ ++ if (extension_version_info->zend_extension_api_no != HARDENING_PATCH_ZEND_EXTENSION_API_NO) { ++ fprintf(stderr, "%s requires Hardening-Patch version %d.\n" ++ "The Hardening-Patch version %d is installed.\n\n", ++ new_extension->name, ++ extension_version_info->zend_extension_api_no, ++ HARDENING_PATCH_ZEND_EXTENSION_API_NO); ++ DL_UNLOAD(handle); ++ return FAILURE; ++ } + + /* allow extension to proclaim compatibility with any Zend version */ +- if (extension_version_info->zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) { +- if (extension_version_info->zend_extension_api_no > ZEND_EXTENSION_API_NO) { ++ if (extension_version_info->real_zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) { ++ if (extension_version_info->real_zend_extension_api_no > ZEND_EXTENSION_API_NO) { + fprintf(stderr, "%s requires Zend Engine API version %d.\n" + "The Zend Engine API version %d which is installed, is outdated.\n\n", + new_extension->name, +- extension_version_info->zend_extension_api_no, ++ extension_version_info->real_zend_extension_api_no, + ZEND_EXTENSION_API_NO); + DL_UNLOAD(handle); + return FAILURE; +- } else if (extension_version_info->zend_extension_api_no < ZEND_EXTENSION_API_NO) { ++ } else if (extension_version_info->real_zend_extension_api_no < ZEND_EXTENSION_API_NO) { + fprintf(stderr, "%s requires Zend Engine API version %d.\n" + "The Zend Engine API version %d which is installed, is newer.\n" + "Contact %s at %s for a later version of %s.\n\n", + new_extension->name, +- extension_version_info->zend_extension_api_no, ++ extension_version_info->real_zend_extension_api_no, + ZEND_EXTENSION_API_NO, + new_extension->author, + new_extension->URL, +diff -Nura php-5.0.5/Zend/zend_extensions.h hardening-patch-5.0.5-0.4.2/Zend/zend_extensions.h +--- php-5.0.5/Zend/zend_extensions.h 2004-11-25 21:26:48.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_extensions.h 2005-09-07 13:49:17.000000000 +0200 +@@ -24,9 +24,11 @@ + + #include "zend_compile.h" + +-/* The first number is the engine version and the rest is the date. ++/* The first API number is a flag saying that Hardening-Patch is used. ++ * The second number is the engine version and the date. + * This way engine 2 API no. is always greater than engine 1 API no.. + */ ++#define HARDENING_PATCH_ZEND_EXTENSION_API_NO 1002050805 + #define ZEND_EXTENSION_API_NO 220040412 + + typedef struct _zend_extension_version_info { +@@ -34,6 +36,7 @@ + char *required_zend_version; + unsigned char thread_safe; + unsigned char debug; ++ int real_zend_extension_api_no; + } zend_extension_version_info; + + +@@ -101,7 +104,7 @@ + + + #define ZEND_EXTENSION() \ +- ZEND_EXT_API zend_extension_version_info extension_version_info = { ZEND_EXTENSION_API_NO, ZEND_VERSION, ZTS_V, ZEND_DEBUG } ++ ZEND_EXT_API zend_extension_version_info extension_version_info = { HARDENING_PATCH_ZEND_EXTENSION_API_NO, ZEND_VERSION, ZTS_V, ZEND_DEBUG, ZEND_EXTENSION_API_NO } + + #define STANDARD_ZEND_EXTENSION_PROPERTIES NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1 + #define COMPAT_ZEND_EXTENSION_PROPERTIES NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1 +diff -Nura php-5.0.5/Zend/zend_globals.h hardening-patch-5.0.5-0.4.2/Zend/zend_globals.h +--- php-5.0.5/Zend/zend_globals.h 2004-11-04 00:14:31.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_globals.h 2005-09-07 13:49:17.000000000 +0200 +@@ -174,6 +174,16 @@ + + int error_reporting; + int orig_error_reporting; ++#if HARDENING_PATCH ++ int hphp_log_syslog; ++ int hphp_log_syslog_facility; ++ int hphp_log_syslog_priority; ++ int hphp_log_sapi; ++ int hphp_log_script; ++ char *hphp_log_scriptname; ++ zend_bool hphp_log_use_x_forwarded_for; ++ long hphp_executor_max_depth; ++#endif + int exit_status; + + zend_op_array *active_op_array; +@@ -191,6 +201,7 @@ + int ticks_count; + + zend_bool in_execution; ++ zend_uint in_code_type; + HashTable *in_autoload; + zend_bool bailout_set; + zend_bool full_tables_cleanup; +diff -Nura php-5.0.5/Zend/zend.h hardening-patch-5.0.5-0.4.2/Zend/zend.h +--- php-5.0.5/Zend/zend.h 2005-08-25 19:41:08.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend.h 2005-09-07 13:49:17.000000000 +0200 +@@ -290,6 +290,7 @@ + /* Variable information */ + zvalue_value value; /* value */ + zend_uint refcount; ++ zend_ushort flags; + zend_uchar type; /* active type */ + zend_uchar is_ref; + }; +@@ -359,6 +360,12 @@ + void (*on_timeout)(int seconds TSRMLS_DC); + int (*stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); + int (*vspprintf_function)(char **pbuf, size_t max_len, const char *format, va_list ap); ++#if HARDENING_PATCH ++ void (*security_log_function)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ int (*is_valid_include)(zval *z); ++#endif + } zend_utility_functions; + + +@@ -497,6 +504,16 @@ + extern void (*zend_on_timeout)(int seconds TSRMLS_DC); + extern ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); + extern int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); ++#if HARDENING_PATCH ++extern ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++extern ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ZEND_API unsigned int zend_canary(void); ++#endif + + + ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +@@ -621,6 +638,11 @@ + #define ZEND_MAX_RESERVED_RESOURCES 4 + + ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#include "php_syslog.h" ++#endif ++ + #endif /* ZEND_H */ + + /* +diff -Nura php-5.0.5/Zend/zend_hash.c hardening-patch-5.0.5-0.4.2/Zend/zend_hash.c +--- php-5.0.5/Zend/zend_hash.c 2005-04-25 08:11:00.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_hash.c 2005-09-07 13:49:17.000000000 +0200 +@@ -21,6 +21,18 @@ + + #include "zend.h" + ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int zend_hash_canary = 0x1234567; ++ zend_bool zend_hash_canary_inited = 0; ++#endif ++ ++#define CHECK_HASH_CANARY(hash) \ ++ if (zend_hash_canary != (hash)->canary) { \ ++ zend_security_log(S_MEMORY, "Zend HashTable canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++ + #define CONNECT_TO_BUCKET_DLLIST(element, list_head) \ + (element)->pNext = (list_head); \ + (element)->pLast = NULL; \ +@@ -138,6 +150,9 @@ + { + uint i = 3; + Bucket **tmp; ++#if HARDENING_PATCH_HASH_PROTECT ++ TSRMLS_FETCH(); ++#endif + + SET_INCONSISTENT(HT_OK); + +@@ -147,6 +162,13 @@ + + ht->nTableSize = 1 << i; + ht->nTableMask = ht->nTableSize - 1; ++#if HARDENING_PATCH_HASH_PROTECT ++ if (zend_hash_canary_inited==0) { ++ zend_hash_canary = zend_canary(); ++ zend_hash_canary_inited = 1; ++ } ++ ht->canary = zend_hash_canary; ++#endif + ht->pDestructor = pDestructor; + ht->arBuckets = NULL; + ht->pListHead = NULL; +@@ -226,6 +248,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -291,6 +316,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -366,6 +394,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -414,7 +445,7 @@ + IS_CONSISTENT(ht); + + if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */ +- t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); ++ t = (Bucket **) perealloc(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); + if (t) { + HANDLE_BLOCK_INTERRUPTIONS(); + ht->arBuckets = t; +@@ -424,6 +455,7 @@ + HANDLE_UNBLOCK_INTERRUPTIONS(); + return SUCCESS; + } ++ zend_error(E_ERROR, "zend_hash_do_resize - out of memory"); + return FAILURE; + } + return SUCCESS; +@@ -487,6 +519,9 @@ + ht->pInternalPointer = p->pListNext; + } + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +@@ -516,6 +551,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -542,6 +580,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -571,6 +612,9 @@ + HANDLE_BLOCK_INTERRUPTIONS(); + + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +diff -Nura php-5.0.5/Zend/zend_hash.h hardening-patch-5.0.5-0.4.2/Zend/zend_hash.h +--- php-5.0.5/Zend/zend_hash.h 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_hash.h 2005-09-07 13:49:17.000000000 +0200 +@@ -58,6 +58,9 @@ + } Bucket; + + typedef struct _hashtable { ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int canary; ++#endif + uint nTableSize; + uint nTableMask; + uint nNumOfElements; +diff -Nura php-5.0.5/Zend/zend_language_scanner.l hardening-patch-5.0.5-0.4.2/Zend/zend_language_scanner.l +--- php-5.0.5/Zend/zend_language_scanner.l 2005-06-09 10:54:24.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_language_scanner.l 2005-09-07 13:49:17.000000000 +0200 +@@ -386,6 +386,13 @@ + compilation_successful=0; + } else { + init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array->created_by_eval = 1; ++ } else { ++ op_array->created_by_eval = 0; ++ } ++#endif + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + compiler_result = zendparse(TSRMLS_C); +diff -Nura php-5.0.5/Zend/zend_language_scanner.c hardening-patch-5.0.5-0.4.2/Zend/zend_language_scanner.c +--- php-5.0.5/Zend/zend_language_scanner.c 2005-09-05 13:16:27.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_language_scanner.c 2005-09-07 13:49:17.000000000 +0200 +@@ -3153,6 +3153,13 @@ + compilation_successful=0; + } else { + init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array->created_by_eval = 1; ++ } else { ++ op_array->created_by_eval = 0; ++ } ++#endif + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + compiler_result = zendparse(TSRMLS_C); +diff -Nura php-5.0.5/Zend/zend_llist.c hardening-patch-5.0.5-0.4.2/Zend/zend_llist.c +--- php-5.0.5/Zend/zend_llist.c 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_llist.c 2005-09-07 13:49:17.000000000 +0200 +@@ -22,9 +22,34 @@ + #include "zend.h" + #include "zend_llist.h" + #include "zend_qsort.h" ++#include "zend_globals.h" ++ ++#define CHECK_LIST_CANARY(list) \ ++ if (HG(canary_3) != (list)->canary_h || HG(canary_4) != (list)->canary_t) { \ ++ zend_security_log(S_MEMORY, "linked list canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++#define CHECK_LISTELEMENT_CANARY(elem) \ ++ if (HG(canary_3) != (elem)->canary) { \ ++ zend_security_log(S_MEMORY, "linked list element canary was overwritten"); \ ++ exit(1); \ ++ } ++ + + ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ ++ if (!HG(ll_canary_inited)) { ++ HG(canary_3) = zend_canary(); ++ HG(canary_4) = zend_canary(); ++ HG(ll_canary_inited) = 1; ++ } ++ l->canary_h = HG(canary_3); ++ l->canary_t = HG(canary_4); ++#endif + l->head = NULL; + l->tail = NULL; + l->count = 0; +@@ -38,6 +63,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->prev = l->tail; + tmp->next = NULL; + if (l->tail) { +@@ -56,6 +86,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->next = l->head; + tmp->prev = NULL; + if (l->head) { +@@ -93,10 +128,20 @@ + zend_llist_element *current=l->head; + zend_llist_element *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (compare(current->data, element)) { + DEL_LLIST_ELEMENT(current, l); ++#if HARDENING_PATCH_LL_PROTECT ++ current->canary = 0; ++#endif + break; + } + current = next; +@@ -108,7 +153,14 @@ + { + zend_llist_element *current=l->head, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (l->dtor) { + l->dtor(current->data); +@@ -133,7 +185,14 @@ + zend_llist_element *old_tail; + void *data; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if ((old_tail = l->tail)) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(old_tail) ++#endif + if (l->tail->prev) { + l->tail->prev->next = NULL; + } +@@ -159,9 +218,16 @@ + { + zend_llist_element *ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(src) ++#endif + zend_llist_init(dst, src->size, src->dtor, src->persistent); + ptr = src->head; + while (ptr) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(ptr) ++#endif + zend_llist_add_element(dst, ptr->data); + ptr = ptr->next; + } +@@ -172,11 +238,21 @@ + { + zend_llist_element *element, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + element=l->head; + while (element) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + next = element->next; + if (func(element->data)) { + DEL_LLIST_ELEMENT(element, l); ++#if HARDENING_PATCH_LL_PROTECT ++ element->canary = 0; ++#endif + } + element = next; + } +@@ -187,7 +263,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data TSRMLS_CC); + } + } +@@ -199,6 +281,9 @@ + zend_llist_element **elements; + zend_llist_element *element, **ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + if (l->count <= 0) { + return; + } +@@ -208,6 +293,9 @@ + ptr = &elements[0]; + + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + *ptr++ = element; + } + +@@ -230,7 +318,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, arg TSRMLS_CC); + } + } +@@ -241,8 +335,14 @@ + zend_llist_element *element; + va_list args; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + va_start(args, num_args); + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, num_args, args TSRMLS_CC); + } + va_end(args); +@@ -251,6 +351,10 @@ + + ZEND_API int zend_llist_count(zend_llist *l) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + return l->count; + } + +@@ -259,8 +363,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->head; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -272,8 +383,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->tail; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -285,9 +403,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->next; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +@@ -299,9 +427,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->prev; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +diff -Nura php-5.0.5/Zend/zend_llist.h hardening-patch-5.0.5-0.4.2/Zend/zend_llist.h +--- php-5.0.5/Zend/zend_llist.h 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_llist.h 2005-09-07 13:49:17.000000000 +0200 +@@ -23,6 +23,9 @@ + #define ZEND_LLIST_H + + typedef struct _zend_llist_element { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary; ++#endif + struct _zend_llist_element *next; + struct _zend_llist_element *prev; + char data[1]; /* Needs to always be last in the struct */ +@@ -35,6 +38,9 @@ + typedef void (*llist_apply_func_t)(void * TSRMLS_DC); + + typedef struct _zend_llist { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_h; /* head */ ++#endif + zend_llist_element *head; + zend_llist_element *tail; + size_t count; +@@ -42,6 +48,9 @@ + llist_dtor_func_t dtor; + unsigned char persistent; + zend_llist_element *traverse_ptr; ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_t; /* tail */ ++#endif + } zend_llist; + + typedef zend_llist_element* zend_llist_position; +diff -Nura php-5.0.5/Zend/zend_modules.h hardening-patch-5.0.5-0.4.2/Zend/zend_modules.h +--- php-5.0.5/Zend/zend_modules.h 2005-03-16 00:47:12.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_modules.h 2005-09-07 13:49:17.000000000 +0200 +@@ -38,6 +38,7 @@ + extern struct _zend_arg_info fourth_arg_force_ref[5]; + extern struct _zend_arg_info all_args_by_ref[1]; + ++#define HARDENING_PATCH_ZEND_MODULE_API_NO 1002050805 + #define ZEND_MODULE_API_NO 20041030 + #ifdef ZTS + #define USING_ZTS 1 +@@ -45,10 +46,10 @@ + #define USING_ZTS 0 + #endif + +-#define STANDARD_MODULE_HEADER sizeof(zend_module_entry), ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS, NULL +-#define ZE2_STANDARD_MODULE_HEADER sizeof(zend_module_entry), ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS, ini_entries ++#define STANDARD_MODULE_HEADER sizeof(zend_module_entry), HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS, NULL ++#define ZE2_STANDARD_MODULE_HEADER sizeof(zend_module_entry), HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS, ini_entries + +-#define STANDARD_MODULE_PROPERTIES_EX 0, 0, 0, NULL, 0 ++#define STANDARD_MODULE_PROPERTIES_EX 0, 0, 0, NULL, 0, ZEND_MODULE_API_NO + + #define STANDARD_MODULE_PROPERTIES \ + NULL, STANDARD_MODULE_PROPERTIES_EX +@@ -81,6 +82,7 @@ + unsigned char type; + void *handle; + int module_number; ++ unsigned int real_zend_api; + }; + + +diff -Nura php-5.0.5/Zend/zend_opcode.c hardening-patch-5.0.5-0.4.2/Zend/zend_opcode.c +--- php-5.0.5/Zend/zend_opcode.c 2004-06-06 10:37:12.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.2/Zend/zend_opcode.c 2005-09-07 13:49:17.000000000 +0200 +@@ -92,6 +92,9 @@ + op_array->uses_this = 0; + + op_array->start_op = NULL; ++#if HARDENING_PATCH ++ op_array->created_by_eval = 0; ++#endif + + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC); + } diff --git a/0.4.3/.hardening-patch-5.0.5-0.4.3.patch.swp b/0.4.3/.hardening-patch-5.0.5-0.4.3.patch.swp new file mode 100644 index 0000000..0679ecb Binary files /dev/null and b/0.4.3/.hardening-patch-5.0.5-0.4.3.patch.swp differ diff --git a/0.4.3/hardening-patch-4.4.0-0.4.3.patch b/0.4.3/hardening-patch-4.4.0-0.4.3.patch new file mode 100644 index 0000000..853680e --- /dev/null +++ b/0.4.3/hardening-patch-4.4.0-0.4.3.patch @@ -0,0 +1,15043 @@ +diff -Nura php-4.4.0/acinclude.m4 hardening-patch-4.4.0-0.4.3/acinclude.m4 +--- php-4.4.0/acinclude.m4 2005-04-30 11:31:09.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/acinclude.m4 2005-09-11 23:31:08.000000000 +0200 +@@ -1173,6 +1173,36 @@ + fi + ]) + ++dnl ++dnl Check for broken realpath() ++dnl ++dnl realpath("/etc/hosts/../passwd",XXX) should not return ++dnl "/etc/passwd" ++dnl ++AC_DEFUN([PHP_AC_BROKEN_REALPATH],[ ++ AC_CACHE_CHECK(whether realpath is broken, ac_cv_broken_realpath,[ ++ AC_TRY_RUN([ ++main() { ++ char buf[4096+1]; ++ buf[0] = 0; ++ realpath("/etc/hosts/../passwd", buf); ++ exit(strcmp(buf, "/etc/passwd")==0); ++} ++ ],[ ++ ac_cv_broken_realpath=no ++ ],[ ++ ac_cv_broken_realpath=yes ++ ],[ ++ ac_cv_broken_realpath=no ++ ]) ++ ]) ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ AC_DEFINE(PHP_BROKEN_REALPATH, 1, [Whether realpath is broken]) ++ else ++ AC_DEFINE(PHP_BROKEN_REALPATH, 0, [Whether realpath is broken]) ++ fi ++]) ++ + dnl PHP_SHARED_MODULE(module-name, object-var, build-dir, cxx) + dnl + dnl Basically sets up the link-stage for building module-name +diff -Nura php-4.4.0/configure hardening-patch-4.4.0-0.4.3/configure +--- php-4.4.0/configure 2005-07-11 12:07:33.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/configure 2005-09-11 23:31:08.000000000 +0200 +@@ -394,6 +394,16 @@ + ac_default_prefix=/usr/local + # Any additions from configure.in: + ac_help="$ac_help ++ --disable-hardening-patch-mm-protect Disable the Memory Manager protection." ++ac_help="$ac_help ++ --disable-hardening-patch-ll-protect Disable the Linked List protection." ++ac_help="$ac_help ++ --disable-hardening-patch-inc-protect Disable include/require protection." ++ac_help="$ac_help ++ --disable-hardening-patch-fmt-protect Disable format string protection." ++ac_help="$ac_help ++ --disable-hardening-patch-hash-protect Disable Zend HashTable DTOR protection." ++ac_help="$ac_help + + SAPI modules: + " +@@ -846,6 +856,8 @@ + ac_help="$ac_help + --disable-tokenizer Disable tokenizer support" + ac_help="$ac_help ++ --disable-varfilter Disable Hardening-Patch's variable filter" ++ac_help="$ac_help + --enable-wddx Enable WDDX support." + ac_help="$ac_help + --disable-xml Disable XML support using bundled expat lib" +@@ -2682,6 +2694,157 @@ + + + ++# Check whether --enable-hardening-patch-mm-protect or --disable-hardening-patch-mm-protect was given. ++if test "${enable_hardening_patch_mm_protect+set}" = set; then ++ enableval="$enable_hardening_patch_mm_protect" ++ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-ll-protect or --disable-hardening-patch-ll-protect was given. ++if test "${enable_hardening_patch_ll_protect+set}" = set; then ++ enableval="$enable_hardening_patch_ll_protect" ++ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-inc-protect or --disable-hardening-patch-inc-protect was given. ++if test "${enable_hardening_patch_inc_protect+set}" = set; then ++ enableval="$enable_hardening_patch_inc_protect" ++ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-fmt-protect or --disable-hardening-patch-fmt-protect was given. ++if test "${enable_hardening_patch_fmt_protect+set}" = set; then ++ enableval="$enable_hardening_patch_fmt_protect" ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-hash-protect or --disable-hardening-patch-hash-protect was given. ++if test "${enable_hardening_patch_hash_protect+set}" = set; then ++ enableval="$enable_hardening_patch_hash_protect" ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++ ++fi ++ ++ ++echo $ac_n "checking whether to protect the Zend Memory Manager""... $ac_c" 1>&6 ++echo "configure:2725: checking whether to protect the Zend Memory Manager" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_MM_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend Linked Lists""... $ac_c" 1>&6 ++echo "configure:2729: checking whether to protect the Zend Linked Lists" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_LL_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect include/require statements""... $ac_c" 1>&6 ++echo "configure:2733: checking whether to protect include/require statements" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_INC_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect PHP Format String functions""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect PHP Format String functions" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_FMT_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend HashTable Destructors""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect the Zend HashTable Destructors" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_HASH_PROTECT" 1>&6 ++ ++ ++cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH 1 ++EOF ++ ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 0 ++EOF ++ ++fi + + + +@@ -15733,6 +15896,62 @@ + fi + + ++ echo $ac_n "checking whether realpath is broken""... $ac_c" 1>&6 ++echo "configure:14928: checking whether realpath is broken" >&5 ++if eval "test \"`echo '$''{'ac_cv_broken_realpath'+set}'`\" = set"; then ++ echo $ac_n "(cached) $ac_c" 1>&6 ++else ++ ++ if test "$cross_compiling" = yes; then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null ++then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ echo "configure: failed program was:" >&5 ++ cat conftest.$ac_ext >&5 ++ rm -fr conftest* ++ ++ ac_cv_broken_realpath=yes ++ ++fi ++rm -fr conftest* ++fi ++ ++ ++fi ++ ++echo "$ac_t""$ac_cv_broken_realpath" 1>&6 ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 1 ++EOF ++ ++ else ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 0 ++EOF ++ ++ fi ++ ++ + echo $ac_n "checking for declared timezone""... $ac_c" 1>&6 + echo "configure:15738: checking for declared timezone" >&5 + if eval "test \"`echo '$''{'ac_cv_declared_timezone'+set}'`\" = set"; then +@@ -83268,7 +83487,7 @@ + if test "$ac_cv_crypt_blowfish" = "yes"; then + ac_result=1 + else +- ac_result=0 ++ ac_result=1 + fi + cat >> confdefs.h <&6 ++echo "configure:82041: checking whether to enable Hardening-Patch's variable filter" >&5 ++# Check whether --enable-varfilter or --disable-varfilter was given. ++if test "${enable_varfilter+set}" = set; then ++ enableval="$enable_varfilter" ++ PHP_VARFILTER=$enableval ++else ++ ++ PHP_VARFILTER=yes ++ ++ if test "$PHP_ENABLE_ALL" && test "yes" = "yes"; then ++ PHP_VARFILTER=$PHP_ENABLE_ALL ++ fi ++ ++fi ++ ++ ++ ++ext_output="yes, shared" ++ext_shared=yes ++case $PHP_VARFILTER in ++shared,*) ++ PHP_VARFILTER=`echo "$PHP_VARFILTER"|sed 's/^shared,//'` ++ ;; ++shared) ++ PHP_VARFILTER=yes ++ ;; ++no) ++ ext_output=no ++ ext_shared=no ++ ;; ++*) ++ ext_output=yes ++ ext_shared=no ++ ;; ++esac ++ ++ ++ ++echo "$ac_t""$ext_output" 1>&6 ++ ++ ++ ++ ++if test "$PHP_VARFILTER" != "no"; then ++ cat >> confdefs.h <<\EOF ++#define HAVE_VARFILTER 1 ++EOF ++ ++ ++ ext_builddir=ext/varfilter ++ ext_srcdir=$abs_srcdir/ext/varfilter ++ ++ ac_extra= ++ ++ if test "$ext_shared" != "shared" && test "$ext_shared" != "yes" && test "" != "cli"; then ++ ++ ++ ++ case ext/varfilter in ++ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;; ++ /*) ac_srcdir=`echo "ext/varfilter"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;; ++ *) ac_srcdir="$abs_srcdir/ext/varfilter/"; ac_bdir="ext/varfilter/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;; ++ esac ++ ++ ++ ++ b_c_pre=$php_c_pre ++ b_cxx_pre=$php_cxx_pre ++ b_c_meta=$php_c_meta ++ b_cxx_meta=$php_cxx_meta ++ b_c_post=$php_c_post ++ b_cxx_post=$php_cxx_post ++ b_lo=$php_lo ++ ++ ++ old_IFS=$IFS ++ for ac_src in varfilter.c; do ++ ++ IFS=. ++ set $ac_src ++ ac_obj=$1 ++ IFS=$old_IFS ++ ++ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo" ++ ++ case $ac_src in ++ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;; ++ *.cpp) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;; ++ esac ++ ++ cat >>Makefile.objects<>Makefile.objects<>Makefile.objects<> confdefs.h <>Makefile.objects<>Makefile.objects<&6 +@@ -99988,7 +100466,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c; do ++ output.c memory_streams.c user_streams.c hardening_patch.c; do + + IFS=. + set $ac_src +@@ -100161,7 +100639,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c; do ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c; do + + IFS=. + set $ac_src +diff -Nura php-4.4.0/configure.in hardening-patch-4.4.0-0.4.3/configure.in +--- php-4.4.0/configure.in 2005-07-11 09:45:09.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/configure.in 2005-09-11 23:31:08.000000000 +0200 +@@ -238,7 +238,7 @@ + sinclude(Zend/acinclude.m4) + sinclude(Zend/Zend.m4) + sinclude(TSRM/tsrm.m4) +- ++sinclude(main/hardening_patch.m4) + + + divert(2) +@@ -612,6 +612,7 @@ + AC_FUNC_ALLOCA + dnl PHP_AC_BROKEN_SPRINTF + dnl PHP_AC_BROKEN_SNPRINTF ++PHP_AC_BROKEN_REALPATH + PHP_DECLARED_TIMEZONE + PHP_TIME_R_TYPE + PHP_READDIR_R_TYPE +@@ -1241,7 +1242,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + streams.c network.c php_open_temporary_file.c php_logos.c \ +- output.c memory_streams.c user_streams.c) ++ output.c memory_streams.c user_streams.c hardening_patch.c) + PHP_ADD_SOURCES(/main, internal_functions.c,, sapi) + PHP_ADD_SOURCES(/main, internal_functions_cli.c,, cli) + +@@ -1254,7 +1255,7 @@ + zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ +- zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c) ++ zend_ini.c zend_qsort.c zend_multibyte.c zend_strtod.c zend_canary.c ) + + if test -r "$abs_srcdir/Zend/zend_objects.c"; then + PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_mm.c) +diff -Nura php-4.4.0/ext/fbsql/php_fbsql.c hardening-patch-4.4.0-0.4.3/ext/fbsql/php_fbsql.c +--- php-4.4.0/ext/fbsql/php_fbsql.c 2005-02-09 20:33:32.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/fbsql/php_fbsql.c 2005-09-11 23:31:08.000000000 +0200 +@@ -1797,8 +1797,24 @@ + } + else if (fbcmdErrorsFound(md)) + { ++#if HARDENING_PATCH ++ char* query_copy; ++ int i; ++#endif + FBCErrorMetaData* emd = fbcdcErrorMetaData(c, md); + char* emg = fbcemdAllErrorMessages(emd); ++#if HARDENING_PATCH ++ query_copy=estrdup(query_copy); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "fbsql error: %s - query: %s", emg, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ free(emg); ++ fbcemdRelease(emd); ++ result = 0; ++ zend_bailout(); ++ } ++#endif + if (FB_SQL_G(generateWarnings)) + { + if (emg) +diff -Nura php-4.4.0/ext/mbstring/mbstring.c hardening-patch-4.4.0-0.4.3/ext/mbstring/mbstring.c +--- php-4.4.0/ext/mbstring/mbstring.c 2005-02-21 09:03:47.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/mbstring/mbstring.c 2005-09-11 23:31:08.000000000 +0200 +@@ -1487,6 +1487,7 @@ + char *strtok_buf = NULL, **val_list; + zval *array_ptr = (zval *) arg; + int n, num, val_len, *len_list; ++ unsigned int new_val_len; + enum mbfl_no_encoding from_encoding; + mbfl_string string, resvar, resval; + mbfl_encoding_detector *identd = NULL; +@@ -1609,8 +1610,14 @@ + val_len = len_list[n]; + } + n++; +- /* add variable to symbol table */ +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ /* we need val to be emalloc()ed */ ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(info->data_type, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ /* add variable to symbol table */ ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); ++ + if (convd != NULL){ + mbfl_string_clear(&resvar); + mbfl_string_clear(&resval); +diff -Nura php-4.4.0/ext/mysql/php_mysql.c hardening-patch-4.4.0-0.4.3/ext/mysql/php_mysql.c +--- php-4.4.0/ext/mysql/php_mysql.c 2005-04-08 00:23:01.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/ext/mysql/php_mysql.c 2005-09-11 23:31:08.000000000 +0200 +@@ -1218,6 +1218,8 @@ + { + php_mysql_conn *mysql; + MYSQL_RES *mysql_result; ++ char *copy_query; ++ int i; + + ZEND_FETCH_RESOURCE2(mysql, php_mysql_conn *, mysql_link, link_id, "MySQL-Link", le_link, le_plink); + +@@ -1268,6 +1270,13 @@ + php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #else +@@ -1275,12 +1284,20 @@ + /* check possible error */ + if (MySG(trace_mode)){ + if (mysql_errno(&mysql->conn)){ +- php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, mysql_error(&mysql->conn)); ++ php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #endif ++ + if(use_store == MYSQL_USE_RESULT) { + mysql_result=mysql_use_result(&mysql->conn); + } else { +diff -Nura php-4.4.0/ext/pgsql/pgsql.c hardening-patch-4.4.0-0.4.3/ext/pgsql/pgsql.c +--- php-4.4.0/ext/pgsql/pgsql.c 2005-07-05 14:50:03.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/ext/pgsql/pgsql.c 2005-09-11 23:31:08.000000000 +0200 +@@ -1001,10 +1001,28 @@ + case PGRES_EMPTY_QUERY: + case PGRES_BAD_RESPONSE: + case PGRES_NONFATAL_ERROR: +- case PGRES_FATAL_ERROR: +- PHP_PQ_ERROR("Query failed: %s", pgsql); +- PQclear(pgsql_result); +- RETURN_FALSE; ++ case PGRES_FATAL_ERROR: ++ { ++#if HARDENING_PATCH ++ int i; ++ char *query_copy; ++#endif ++ char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); ++ PQclear(pgsql_result); ++#if HARDENING_PATCH ++ query_copy = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "PgSQL error: %s - query: %s", msgbuf, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ efree(msgbuf); ++ zend_bailout(); ++ } ++#endif ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Query failed: %s", msgbuf); ++ efree(msgbuf); ++ RETURN_FALSE; ++ } + break; + case PGRES_COMMAND_OK: /* successful command that did not return rows */ + default: +diff -Nura php-4.4.0/ext/standard/array.c hardening-patch-4.4.0-0.4.3/ext/standard/array.c +--- php-4.4.0/ext/standard/array.c 2005-06-21 14:11:19.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/ext/standard/array.c 2005-09-11 23:31:08.000000000 +0200 +@@ -1162,6 +1162,32 @@ + } + } + } ++ ++ if (var_name[0] == 'H') { ++ if ((strcmp(var_name, "HTTP_GET_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_FILES")==0)|| ++ (strcmp(var_name, "HTTP_ENV_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(var_name, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(var_name, "HTTP_RAW_POST_DATA")==0)) { ++ return 0; ++ } ++ } else if (var_name[0] == '_') { ++ if ((strcmp(var_name, "_COOKIE")==0)|| ++ (strcmp(var_name, "_ENV")==0)|| ++ (strcmp(var_name, "_FILES")==0)|| ++ (strcmp(var_name, "_GET")==0)|| ++ (strcmp(var_name, "_POST")==0)|| ++ (strcmp(var_name, "_REQUEST")==0)|| ++ (strcmp(var_name, "_SESSION")==0)|| ++ (strcmp(var_name, "_SERVER")==0)) { ++ return 0; ++ } ++ } else if (strcmp(var_name, "GLOBALS")==0) { ++ return 0; ++ } + + return 1; + } +diff -Nura php-4.4.0/ext/standard/basic_functions.c hardening-patch-4.4.0-0.4.3/ext/standard/basic_functions.c +--- php-4.4.0/ext/standard/basic_functions.c 2005-05-16 10:55:31.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/ext/standard/basic_functions.c 2005-09-11 23:31:08.000000000 +0200 +@@ -118,12 +118,14 @@ + typedef struct _php_shutdown_function_entry { + zval **arguments; + int arg_count; ++ zend_bool created_by_eval; + } php_shutdown_function_entry; + + typedef struct _user_tick_function_entry { + zval **arguments; + int arg_count; + int calling; ++ zend_bool created_by_eval; + } user_tick_function_entry; + + /* some prototypes for local functions */ +@@ -306,6 +308,8 @@ + PHP_FE(get_html_translation_table, NULL) + PHP_FE(sha1, NULL) + PHP_FE(sha1_file, NULL) ++ PHP_FE(sha256, NULL) ++ PHP_FE(sha256_file, NULL) + PHP_NAMED_FE(md5,php_if_md5, NULL) + PHP_NAMED_FE(md5_file,php_if_md5_file, NULL) + PHP_NAMED_FE(crc32,php_if_crc32, NULL) +@@ -687,7 +691,7 @@ + PHP_FALIAS(socket_get_status, stream_get_meta_data, NULL) + + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +- PHP_FE(realpath, NULL) ++ PHP_STATIC_FE("realpath", zif_real_path, NULL) + #endif + + #ifdef HAVE_FNMATCH +@@ -2104,6 +2108,13 @@ + { + zval retval; + char *function_name = NULL; ++#if HARDENING_PATCH ++ zend_uint orig_code_type = EG(in_code_type); ++ ++ if (shutdown_function_entry->created_by_eval) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } ++#endif + + if (!zend_is_callable(shutdown_function_entry->arguments[0], 0, &function_name)) { + php_error(E_WARNING, "(Registered shutdown functions) Unable to call %s() - function does not exist", function_name); +@@ -2119,6 +2130,9 @@ + if (function_name) { + efree(function_name); + } ++#if HARDENING_PATCH ++ EG(in_code_type) = orig_code_type; ++#endif + return 0; + } + +@@ -2126,6 +2140,13 @@ + { + zval retval; + zval *function = tick_fe->arguments[0]; ++#if HARDENING_PATCH ++ zend_uint orig_code_type = EG(in_code_type); ++ ++ if (tick_fe->created_by_eval) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } ++#endif + + /* Prevent reentrant calls to the same user ticks function */ + if (! tick_fe->calling) { +@@ -2157,6 +2178,9 @@ + + tick_fe->calling = 0; + } ++#if HARDENING_PATCH ++ EG(in_code_type) = orig_code_type; ++#endif + } + + static void run_user_tick_functions(int tick_count) +@@ -2224,6 +2248,13 @@ + if (zend_get_parameters_array(ht, shutdown_function_entry.arg_count, shutdown_function_entry.arguments) == FAILURE) { + RETURN_FALSE; + } ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ shutdown_function_entry.created_by_eval = 1; ++ } else { ++ shutdown_function_entry.created_by_eval = 0; ++ } ++#endif + + /* Prevent entering of anything but valid callback (syntax check only!) */ + if (!zend_is_callable(shutdown_function_entry.arguments[0], 1, &function_name)) { +@@ -2761,6 +2792,13 @@ + } + + tick_fe.arguments = (zval **) safe_emalloc(sizeof(zval *), tick_fe.arg_count, 0); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ tick_fe.created_by_eval = 1; ++ } else { ++ tick_fe.created_by_eval = 0; ++ } ++#endif + + if (zend_get_parameters_array(ht, tick_fe.arg_count, tick_fe.arguments) == FAILURE) { + RETURN_FALSE; +@@ -3044,6 +3082,35 @@ + memcpy(new_key, prefix, prefix_len); + memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + ++ if (new_key[0] == 'H') { ++ if ((strcmp(new_key, "HTTP_GET_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_FILES")==0)|| ++ (strcmp(new_key, "HTTP_ENV_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(new_key, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(new_key, "HTTP_RAW_POST_DATA")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (new_key[0] == '_') { ++ if ((strcmp(new_key, "_COOKIE")==0)|| ++ (strcmp(new_key, "_ENV")==0)|| ++ (strcmp(new_key, "_FILES")==0)|| ++ (strcmp(new_key, "_GET")==0)|| ++ (strcmp(new_key, "_POST")==0)|| ++ (strcmp(new_key, "_REQUEST")==0)|| ++ (strcmp(new_key, "_SESSION")==0)|| ++ (strcmp(new_key, "_SERVER")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (strcmp(new_key, "GLOBALS")==0) { ++ efree(new_key); ++ return 0; ++ } ++ + zend_hash_del(&EG(symbol_table), new_key, new_key_len); + ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, (*var)->refcount+1, 0); + +diff -Nura php-4.4.0/ext/standard/config.m4 hardening-patch-4.4.0-0.4.3/ext/standard/config.m4 +--- php-4.4.0/ext/standard/config.m4 2004-12-30 08:02:18.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/standard/config.m4 2005-09-11 23:31:08.000000000 +0200 +@@ -203,7 +203,7 @@ + if test "$ac_cv_crypt_blowfish" = "yes"; then + ac_result=1 + else +- ac_result=0 ++ ac_result=1 + fi + AC_DEFINE_UNQUOTED(PHP_BLOWFISH_CRYPT, $ac_result, [Whether the system supports BlowFish salt]) + ]) +@@ -419,6 +419,6 @@ + url_scanner.c var.c versioning.c assert.c strnatcmp.c levenshtein.c \ + incomplete_class.c url_scanner_ex.c ftp_fopen_wrapper.c \ + http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \ +- var_unserializer.c ftok.c aggregation.c sha1.c ) ++ var_unserializer.c ftok.c aggregation.c sha1.c sha256.c crypt_blowfish.c ) + + PHP_ADD_MAKEFILE_FRAGMENT +diff -Nura php-4.4.0/ext/standard/crypt_blowfish.c hardening-patch-4.4.0-0.4.3/ext/standard/crypt_blowfish.c +--- php-4.4.0/ext/standard/crypt_blowfish.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/standard/crypt_blowfish.c 2005-09-11 23:31:08.000000000 +0200 +@@ -0,0 +1,748 @@ ++/* ++ * This code comes from John the Ripper password cracker, with reentrant ++ * and crypt(3) interfaces added, but optimizations specific to password ++ * cracking removed. ++ * ++ * Written by Solar Designer in 1998-2002 and ++ * placed in the public domain. ++ * ++ * There's absolutely no warranty. ++ * ++ * It is my intent that you should be able to use this on your system, ++ * as a part of a software package, or anywhere else to improve security, ++ * ensure compatibility, or for any other purpose. I would appreciate ++ * it if you give credit where it is due and keep your modifications in ++ * the public domain as well, but I don't require that in order to let ++ * you place this code and any modifications you make under a license ++ * of your choice. ++ * ++ * This implementation is compatible with OpenBSD bcrypt.c (version 2a) ++ * by Niels Provos , and uses some of his ++ * ideas. The password hashing algorithm was designed by David Mazieres ++ * . ++ * ++ * There's a paper on the algorithm that explains its design decisions: ++ * ++ * http://www.usenix.org/events/usenix99/provos.html ++ * ++ * Some of the tricks in BF_ROUND might be inspired by Eric Young's ++ * Blowfish library (I can't be sure if I would think of something if I ++ * hadn't seen his code). ++ */ ++ ++#include ++ ++#include ++#ifndef __set_errno ++#define __set_errno(val) errno = (val) ++#endif ++ ++#undef __CONST ++#ifdef __GNUC__ ++#define __CONST __const ++#else ++#define __CONST ++#endif ++ ++#ifdef __i386__ ++#define BF_ASM 0 ++#define BF_SCALE 1 ++#elif defined(__alpha__) || defined(__hppa__) ++#define BF_ASM 0 ++#define BF_SCALE 1 ++#else ++#define BF_ASM 0 ++#define BF_SCALE 0 ++#endif ++ ++typedef unsigned int BF_word; ++ ++/* Number of Blowfish rounds, this is also hardcoded into a few places */ ++#define BF_N 16 ++ ++typedef BF_word BF_key[BF_N + 2]; ++ ++typedef struct { ++ BF_word S[4][0x100]; ++ BF_key P; ++} BF_ctx; ++ ++/* ++ * Magic IV for 64 Blowfish encryptions that we do at the end. ++ * The string is "OrpheanBeholderScryDoubt" on big-endian. ++ */ ++static BF_word BF_magic_w[6] = { ++ 0x4F727068, 0x65616E42, 0x65686F6C, ++ 0x64657253, 0x63727944, 0x6F756274 ++}; ++ ++/* ++ * P-box and S-box tables initialized with digits of Pi. ++ */ ++static BF_ctx BF_init_state = { ++ { ++ { ++ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, ++ 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, ++ 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, ++ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, ++ 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, ++ 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, ++ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, ++ 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, ++ 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, ++ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, ++ 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, ++ 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, ++ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, ++ 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, ++ 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, ++ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, ++ 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, ++ 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, ++ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, ++ 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, ++ 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, ++ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, ++ 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, ++ 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, ++ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, ++ 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, ++ 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, ++ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, ++ 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, ++ 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, ++ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, ++ 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, ++ 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, ++ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, ++ 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, ++ 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, ++ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, ++ 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, ++ 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, ++ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, ++ 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, ++ 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, ++ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, ++ 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, ++ 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, ++ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, ++ 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, ++ 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, ++ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, ++ 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, ++ 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, ++ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, ++ 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, ++ 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, ++ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, ++ 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, ++ 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, ++ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, ++ 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, ++ 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, ++ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, ++ 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, ++ 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, ++ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a ++ }, { ++ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, ++ 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, ++ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, ++ 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, ++ 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, ++ 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, ++ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, ++ 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, ++ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, ++ 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, ++ 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, ++ 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, ++ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, ++ 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, ++ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, ++ 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, ++ 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, ++ 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, ++ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, ++ 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, ++ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, ++ 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, ++ 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, ++ 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, ++ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, ++ 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, ++ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, ++ 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, ++ 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, ++ 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, ++ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, ++ 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, ++ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, ++ 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, ++ 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, ++ 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, ++ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, ++ 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, ++ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, ++ 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, ++ 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, ++ 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, ++ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, ++ 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, ++ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, ++ 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, ++ 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, ++ 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, ++ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, ++ 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, ++ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, ++ 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, ++ 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, ++ 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, ++ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, ++ 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, ++ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, ++ 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, ++ 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, ++ 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, ++ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, ++ 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, ++ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, ++ 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 ++ }, { ++ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, ++ 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, ++ 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, ++ 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, ++ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, ++ 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, ++ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, ++ 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, ++ 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, ++ 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, ++ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, ++ 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, ++ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, ++ 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, ++ 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, ++ 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, ++ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, ++ 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, ++ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, ++ 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, ++ 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, ++ 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, ++ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, ++ 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, ++ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, ++ 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, ++ 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, ++ 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, ++ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, ++ 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, ++ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, ++ 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, ++ 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, ++ 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, ++ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, ++ 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, ++ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, ++ 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, ++ 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, ++ 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, ++ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, ++ 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, ++ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, ++ 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, ++ 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, ++ 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, ++ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, ++ 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, ++ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, ++ 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, ++ 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, ++ 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, ++ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, ++ 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, ++ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, ++ 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, ++ 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, ++ 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, ++ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, ++ 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, ++ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, ++ 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, ++ 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, ++ 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 ++ }, { ++ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, ++ 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, ++ 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, ++ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, ++ 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, ++ 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, ++ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, ++ 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, ++ 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, ++ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, ++ 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, ++ 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, ++ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, ++ 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, ++ 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, ++ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, ++ 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, ++ 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, ++ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, ++ 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, ++ 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, ++ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, ++ 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, ++ 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, ++ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, ++ 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, ++ 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, ++ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, ++ 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, ++ 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, ++ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, ++ 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, ++ 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, ++ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, ++ 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, ++ 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, ++ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, ++ 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, ++ 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, ++ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, ++ 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, ++ 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, ++ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, ++ 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, ++ 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, ++ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, ++ 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, ++ 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, ++ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, ++ 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, ++ 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, ++ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, ++ 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, ++ 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, ++ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, ++ 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, ++ 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, ++ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, ++ 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, ++ 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, ++ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, ++ 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, ++ 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, ++ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 ++ } ++ }, { ++ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, ++ 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, ++ 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, ++ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, ++ 0x9216d5d9, 0x8979fb1b ++ } ++}; ++ ++static unsigned char BF_itoa64[64 + 1] = ++ "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; ++ ++static unsigned char BF_atoi64[0x60] = { ++ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, ++ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64, ++ 64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ++ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64, ++ 64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, ++ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 ++}; ++ ++/* ++ * This may be optimized out if built with function inlining and no BF_ASM. ++ */ ++static void clean(void *data, int size) ++{ ++#if BF_ASM ++ extern void _BF_clean(void *data); ++#endif ++ memset(data, 0, size); ++#if BF_ASM ++ _BF_clean(data); ++#endif ++} ++ ++#define BF_safe_atoi64(dst, src) \ ++{ \ ++ tmp = (unsigned char)(src); \ ++ if (tmp == '$') break; \ ++ if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ ++ tmp = BF_atoi64[tmp]; \ ++ if (tmp > 63) return -1; \ ++ (dst) = tmp; \ ++} ++ ++static int BF_decode(BF_word *dst, __CONST char *src, int size) ++{ ++ unsigned char *dptr = (unsigned char *)dst; ++ unsigned char *end = dptr + size; ++ unsigned char *sptr = (unsigned char *)src; ++ unsigned int tmp, c1, c2, c3, c4; ++ ++ do { ++ BF_safe_atoi64(c1, *sptr++); ++ BF_safe_atoi64(c2, *sptr++); ++ *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4); ++ if (dptr >= end) break; ++ ++ BF_safe_atoi64(c3, *sptr++); ++ *dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2); ++ if (dptr >= end) break; ++ ++ BF_safe_atoi64(c4, *sptr++); ++ *dptr++ = ((c3 & 0x03) << 6) | c4; ++ } while (dptr < end); ++ ++ while (dptr < end) ++ *dptr++ = 0; ++ ++ return 0; ++} ++ ++static void BF_encode(char *dst, __CONST BF_word *src, int size) ++{ ++ unsigned char *sptr = (unsigned char *)src; ++ unsigned char *end = sptr + size; ++ unsigned char *dptr = (unsigned char *)dst; ++ unsigned int c1, c2; ++ ++ do { ++ c1 = *sptr++; ++ *dptr++ = BF_itoa64[c1 >> 2]; ++ c1 = (c1 & 0x03) << 4; ++ if (sptr >= end) { ++ *dptr++ = BF_itoa64[c1]; ++ break; ++ } ++ ++ c2 = *sptr++; ++ c1 |= c2 >> 4; ++ *dptr++ = BF_itoa64[c1]; ++ c1 = (c2 & 0x0f) << 2; ++ if (sptr >= end) { ++ *dptr++ = BF_itoa64[c1]; ++ break; ++ } ++ ++ c2 = *sptr++; ++ c1 |= c2 >> 6; ++ *dptr++ = BF_itoa64[c1]; ++ *dptr++ = BF_itoa64[c2 & 0x3f]; ++ } while (sptr < end); ++} ++ ++static void BF_swap(BF_word *x, int count) ++{ ++ static int endianness_check = 1; ++ char *is_little_endian = (char *)&endianness_check; ++ BF_word tmp; ++ ++ if (*is_little_endian) ++ do { ++ tmp = *x; ++ tmp = (tmp << 16) | (tmp >> 16); ++ *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF); ++ } while (--count); ++} ++ ++#if BF_SCALE ++/* Architectures which can shift addresses left by 2 bits with no extra cost */ ++#define BF_ROUND(L, R, N) \ ++ tmp1 = L & 0xFF; \ ++ tmp2 = L >> 8; \ ++ tmp2 &= 0xFF; \ ++ tmp3 = L >> 16; \ ++ tmp3 &= 0xFF; \ ++ tmp4 = L >> 24; \ ++ tmp1 = data.ctx.S[3][tmp1]; \ ++ tmp2 = data.ctx.S[2][tmp2]; \ ++ tmp3 = data.ctx.S[1][tmp3]; \ ++ tmp3 += data.ctx.S[0][tmp4]; \ ++ tmp3 ^= tmp2; \ ++ R ^= data.ctx.P[N + 1]; \ ++ tmp3 += tmp1; \ ++ R ^= tmp3; ++#else ++/* Architectures with no complicated addressing modes supported */ ++#define BF_INDEX(S, i) \ ++ (*((BF_word *)(((unsigned char *)S) + (i)))) ++#define BF_ROUND(L, R, N) \ ++ tmp1 = L & 0xFF; \ ++ tmp1 <<= 2; \ ++ tmp2 = L >> 6; \ ++ tmp2 &= 0x3FC; \ ++ tmp3 = L >> 14; \ ++ tmp3 &= 0x3FC; \ ++ tmp4 = L >> 22; \ ++ tmp4 &= 0x3FC; \ ++ tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \ ++ tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \ ++ tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \ ++ tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \ ++ tmp3 ^= tmp2; \ ++ R ^= data.ctx.P[N + 1]; \ ++ tmp3 += tmp1; \ ++ R ^= tmp3; ++#endif ++ ++/* ++ * Encrypt one block, BF_N is hardcoded here. ++ */ ++#define BF_ENCRYPT \ ++ L ^= data.ctx.P[0]; \ ++ BF_ROUND(L, R, 0); \ ++ BF_ROUND(R, L, 1); \ ++ BF_ROUND(L, R, 2); \ ++ BF_ROUND(R, L, 3); \ ++ BF_ROUND(L, R, 4); \ ++ BF_ROUND(R, L, 5); \ ++ BF_ROUND(L, R, 6); \ ++ BF_ROUND(R, L, 7); \ ++ BF_ROUND(L, R, 8); \ ++ BF_ROUND(R, L, 9); \ ++ BF_ROUND(L, R, 10); \ ++ BF_ROUND(R, L, 11); \ ++ BF_ROUND(L, R, 12); \ ++ BF_ROUND(R, L, 13); \ ++ BF_ROUND(L, R, 14); \ ++ BF_ROUND(R, L, 15); \ ++ tmp4 = R; \ ++ R = L; \ ++ L = tmp4 ^ data.ctx.P[BF_N + 1]; ++ ++#if BF_ASM ++#define BF_body() \ ++ _BF_body_r(&data.ctx); ++#else ++#define BF_body() \ ++ L = R = 0; \ ++ ptr = data.ctx.P; \ ++ do { \ ++ ptr += 2; \ ++ BF_ENCRYPT; \ ++ *(ptr - 2) = L; \ ++ *(ptr - 1) = R; \ ++ } while (ptr < &data.ctx.P[BF_N + 2]); \ ++\ ++ ptr = data.ctx.S[0]; \ ++ do { \ ++ ptr += 2; \ ++ BF_ENCRYPT; \ ++ *(ptr - 2) = L; \ ++ *(ptr - 1) = R; \ ++ } while (ptr < &data.ctx.S[3][0xFF]); ++#endif ++ ++static void BF_set_key(__CONST char *key, BF_key expanded, BF_key initial) ++{ ++ __CONST char *ptr = key; ++ int i, j; ++ BF_word tmp; ++ ++ for (i = 0; i < BF_N + 2; i++) { ++ tmp = 0; ++ for (j = 0; j < 4; j++) { ++ tmp <<= 8; ++ tmp |= *ptr; ++ ++ if (!*ptr) ptr = key; else ptr++; ++ } ++ ++ expanded[i] = tmp; ++ initial[i] = BF_init_state.P[i] ^ tmp; ++ } ++} ++ ++char *_crypt_blowfish_rn(__CONST char *key, __CONST char *setting, ++ char *output, int size) ++{ ++#if BF_ASM ++ extern void _BF_body_r(BF_ctx *ctx); ++#endif ++ struct { ++ BF_ctx ctx; ++ BF_key expanded_key; ++ union { ++ BF_word salt[4]; ++ BF_word output[6]; ++ } binary; ++ } data; ++ BF_word L, R; ++ BF_word tmp1, tmp2, tmp3, tmp4; ++ BF_word *ptr; ++ BF_word count; ++ int i; ++ ++ if (size < 7 + 22 + 31 + 1) { ++ __set_errno(ERANGE); ++ return NULL; ++ } ++ ++ if (setting[0] != '$' || ++ setting[1] != '2' || ++ setting[2] != 'a' || ++ setting[3] != '$' || ++ setting[4] < '0' || setting[4] > '3' || ++ setting[5] < '0' || setting[5] > '9' || ++ setting[6] != '$') { ++ __set_errno(EINVAL); ++ return NULL; ++ } ++ ++ count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); ++ if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16)) { ++ clean(data.binary.salt, sizeof(data.binary.salt)); ++ __set_errno(EINVAL); ++ return NULL; ++ } ++ ++ BF_swap(data.binary.salt, 4); ++ ++ BF_set_key(key, data.expanded_key, data.ctx.P); ++ ++ memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); ++ ++ L = R = 0; ++ for (i = 0; i < BF_N + 2; i += 2) { ++ L ^= data.binary.salt[i & 2]; ++ R ^= data.binary.salt[(i & 2) + 1]; ++ BF_ENCRYPT; ++ data.ctx.P[i] = L; ++ data.ctx.P[i + 1] = R; ++ } ++ ++ ptr = data.ctx.S[0]; ++ do { ++ ptr += 4; ++ L ^= data.binary.salt[(BF_N + 2) & 3]; ++ R ^= data.binary.salt[(BF_N + 3) & 3]; ++ BF_ENCRYPT; ++ *(ptr - 4) = L; ++ *(ptr - 3) = R; ++ ++ L ^= data.binary.salt[(BF_N + 4) & 3]; ++ R ^= data.binary.salt[(BF_N + 5) & 3]; ++ BF_ENCRYPT; ++ *(ptr - 2) = L; ++ *(ptr - 1) = R; ++ } while (ptr < &data.ctx.S[3][0xFF]); ++ ++ do { ++ data.ctx.P[0] ^= data.expanded_key[0]; ++ data.ctx.P[1] ^= data.expanded_key[1]; ++ data.ctx.P[2] ^= data.expanded_key[2]; ++ data.ctx.P[3] ^= data.expanded_key[3]; ++ data.ctx.P[4] ^= data.expanded_key[4]; ++ data.ctx.P[5] ^= data.expanded_key[5]; ++ data.ctx.P[6] ^= data.expanded_key[6]; ++ data.ctx.P[7] ^= data.expanded_key[7]; ++ data.ctx.P[8] ^= data.expanded_key[8]; ++ data.ctx.P[9] ^= data.expanded_key[9]; ++ data.ctx.P[10] ^= data.expanded_key[10]; ++ data.ctx.P[11] ^= data.expanded_key[11]; ++ data.ctx.P[12] ^= data.expanded_key[12]; ++ data.ctx.P[13] ^= data.expanded_key[13]; ++ data.ctx.P[14] ^= data.expanded_key[14]; ++ data.ctx.P[15] ^= data.expanded_key[15]; ++ data.ctx.P[16] ^= data.expanded_key[16]; ++ data.ctx.P[17] ^= data.expanded_key[17]; ++ ++ BF_body(); ++ ++ tmp1 = data.binary.salt[0]; ++ tmp2 = data.binary.salt[1]; ++ tmp3 = data.binary.salt[2]; ++ tmp4 = data.binary.salt[3]; ++ data.ctx.P[0] ^= tmp1; ++ data.ctx.P[1] ^= tmp2; ++ data.ctx.P[2] ^= tmp3; ++ data.ctx.P[3] ^= tmp4; ++ data.ctx.P[4] ^= tmp1; ++ data.ctx.P[5] ^= tmp2; ++ data.ctx.P[6] ^= tmp3; ++ data.ctx.P[7] ^= tmp4; ++ data.ctx.P[8] ^= tmp1; ++ data.ctx.P[9] ^= tmp2; ++ data.ctx.P[10] ^= tmp3; ++ data.ctx.P[11] ^= tmp4; ++ data.ctx.P[12] ^= tmp1; ++ data.ctx.P[13] ^= tmp2; ++ data.ctx.P[14] ^= tmp3; ++ data.ctx.P[15] ^= tmp4; ++ data.ctx.P[16] ^= tmp1; ++ data.ctx.P[17] ^= tmp2; ++ ++ BF_body(); ++ } while (--count); ++ ++ for (i = 0; i < 6; i += 2) { ++ L = BF_magic_w[i]; ++ R = BF_magic_w[i + 1]; ++ ++ count = 64; ++ do { ++ BF_ENCRYPT; ++ } while (--count); ++ ++ data.binary.output[i] = L; ++ data.binary.output[i + 1] = R; ++ } ++ ++ memcpy(output, setting, 7 + 22 - 1); ++ output[7 + 22 - 1] = BF_itoa64[(int) ++ BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30]; ++ ++/* This has to be bug-compatible with the original implementation, so ++ * only encode 23 of the 24 bytes. :-) */ ++ BF_swap(data.binary.output, 6); ++ BF_encode(&output[7 + 22], data.binary.output, 23); ++ output[7 + 22 + 31] = '\0'; ++ ++/* Overwrite the most obvious sensitive data we have on the stack. Note ++ * that this does not guarantee there's no sensitive data left on the ++ * stack and/or in registers; I'm not aware of portable code that does. */ ++ clean(&data, sizeof(data)); ++ ++ return output; ++} ++ ++char *_crypt_gensalt_blowfish_rn(unsigned long count, ++ __CONST char *input, int size, char *output, int output_size) ++{ ++ if (size < 16 || output_size < 7 + 22 + 1 || ++ (count && (count < 4 || count > 31))) { ++ if (output_size > 0) output[0] = '\0'; ++ __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); ++ return NULL; ++ } ++ ++ if (!count) count = 5; ++ ++ output[0] = '$'; ++ output[1] = '2'; ++ output[2] = 'a'; ++ output[3] = '$'; ++ output[4] = '0' + count / 10; ++ output[5] = '0' + count % 10; ++ output[6] = '$'; ++ ++ BF_encode(&output[7], (BF_word *)input, 16); ++ output[7 + 22] = '\0'; ++ ++ return output; ++} +diff -Nura php-4.4.0/ext/standard/crypt.c hardening-patch-4.4.0-0.4.3/ext/standard/crypt.c +--- php-4.4.0/ext/standard/crypt.c 2004-01-19 04:16:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/standard/crypt.c 2005-09-11 23:31:08.000000000 +0200 +@@ -100,6 +100,8 @@ + return SUCCESS; + } + ++char *_crypt_blowfish_rn(char *key, char *setting, char *output, int size); ++char *_crypt_gensalt_blowfish_rn(unsigned long count, char *input, int size, char *output, int output_size); + + static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +@@ -135,7 +137,14 @@ + + /* The automatic salt generation only covers standard DES and md5-crypt */ + if(!*salt) { +-#if PHP_MD5_CRYPT ++#if PHP_BLOWFISH_CRYPT ++ char randat[16]; ++ int i; ++ ++ for (i=0; i<16; i++) randat[i] = PHP_CRYPT_RAND; ++ ++ _crypt_gensalt_blowfish_rn(5, randat, sizeof(randat), salt, sizeof(salt)); ++#elif PHP_MD5_CRYPT + strcpy(salt, "$1$"); + php_to64(&salt[3], PHP_CRYPT_RAND, 4); + php_to64(&salt[7], PHP_CRYPT_RAND, 4); +@@ -145,8 +154,24 @@ + salt[2] = '\0'; + #endif + } +- +- RETVAL_STRING(crypt(str, salt), 1); ++ ++ if (salt[0] == '$' && ++ salt[1] == '2' && ++ salt[2] == 'a' && ++ salt[3] == '$' && ++ salt[4] >= '0' && salt[4] <= '3' && ++ salt[5] >= '0' && salt[5] <= '9' && ++ salt[6] == '$') { ++ ++ char output[PHP_MAX_SALT_LEN+1]; ++ ++ output[0] = 0; ++ _crypt_blowfish_rn(str, salt, output, sizeof(output)); ++ RETVAL_STRING(output, 1); ++ ++ } else { ++ RETVAL_STRING(crypt(str, salt), 1); ++ } + } + /* }}} */ + #endif +diff -Nura php-4.4.0/ext/standard/dl.c hardening-patch-4.4.0-0.4.3/ext/standard/dl.c +--- php-4.4.0/ext/standard/dl.c 2003-01-29 16:40:24.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/standard/dl.c 2005-09-11 23:31:08.000000000 +0200 +@@ -182,8 +182,35 @@ + RETURN_FALSE; + } + module_entry = get_module(); ++ ++ /* check if Hardening-Patch is installed */ ++ if (module_entry->zend_api < 1000000000) { ++ php_error_docref(NULL TSRMLS_CC, error_type, ++ "%s: Unable to initialize module\n" ++ "Module compiled without Hardening-Patch, module API=%d, debug=%d, thread-safety=%d\n" ++ "PHP compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "These options need to match\n", ++ module_entry->name, module_entry->zend_api, module_entry->zend_debug, module_entry->zts, ++ HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS); ++ DL_UNLOAD(handle); ++ RETURN_FALSE; ++ } ++ ++ /* check if correct Hardening-Patch is installed */ ++ if (module_entry->zend_api != HARDENING_PATCH_ZEND_MODULE_API_NO) { ++ php_error_docref(NULL TSRMLS_CC, error_type, ++ "%s: Unable to initialize module\n" ++ "Module compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "PHP compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "These options need to match\n", ++ module_entry->name, module_entry->zend_api, module_entry->real_zend_api, module_entry->zend_debug, module_entry->zts, ++ HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS); ++ DL_UNLOAD(handle); ++ RETURN_FALSE; ++ } ++ + if ((module_entry->zend_debug != ZEND_DEBUG) || (module_entry->zts != USING_ZTS) +- || (module_entry->zend_api != ZEND_MODULE_API_NO)) { ++ || (module_entry->real_zend_api != ZEND_MODULE_API_NO)) { + /* Check for pre-4.1.0 module which has a slightly different module_entry structure :( */ + struct pre_4_1_0_module_entry { + char *name; +@@ -217,7 +244,7 @@ + zts = ((struct pre_4_1_0_module_entry *)module_entry)->zts; + } else { + name = module_entry->name; +- zend_api = module_entry->zend_api; ++ zend_api = module_entry->real_zend_api; + zend_debug = module_entry->zend_debug; + zts = module_entry->zts; + } +diff -Nura php-4.4.0/ext/standard/file.c hardening-patch-4.4.0-0.4.3/ext/standard/file.c +--- php-4.4.0/ext/standard/file.c 2005-03-27 17:53:59.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/ext/standard/file.c 2005-09-11 23:31:08.000000000 +0200 +@@ -2469,7 +2469,7 @@ + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) + /* {{{ proto string realpath(string path) + Return the resolved path */ +-PHP_FUNCTION(realpath) ++PHP_FUNCTION(real_path) + { + zval **path; + char resolved_path_buff[MAXPATHLEN]; +diff -Nura php-4.4.0/ext/standard/file.h hardening-patch-4.4.0-0.4.3/ext/standard/file.h +--- php-4.4.0/ext/standard/file.h 2004-06-21 21:33:47.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/ext/standard/file.h 2005-09-11 23:31:08.000000000 +0200 +@@ -64,7 +64,7 @@ + PHP_FUNCTION(fd_set); + PHP_FUNCTION(fd_isset); + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +-PHP_FUNCTION(realpath); ++PHP_FUNCTION(real_path); + #endif + #ifdef HAVE_FNMATCH + PHP_FUNCTION(fnmatch); +diff -Nura php-4.4.0/ext/standard/head.c hardening-patch-4.4.0-0.4.3/ext/standard/head.c +--- php-4.4.0/ext/standard/head.c 2005-01-07 22:14:23.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/standard/head.c 2005-09-11 23:31:08.000000000 +0200 +@@ -45,10 +45,31 @@ + { + zend_bool rep = 1; + sapi_header_line ctr = {0}; ++#if HARDENING_PATCH ++ int i; ++#endif + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &ctr.line, + &ctr.line_len, &rep, &ctr.response_code) == FAILURE) + return; ++ ++#if HARDENING_PATCH ++ if (!HG(hphp_multiheader)) { ++ for (i=0; i0 && (iPHP Version %s with Hardening-Patch %s\n", PHP_VERSION, HARDENING_PATCH_VERSION); ++ } else { ++ char temp_ver[40]; ++ ++ snprintf(temp_ver, sizeof(temp_ver), "%s/%s", PHP_VERSION, HARDENING_PATCH_VERSION); ++ php_info_print_table_row(2, "PHP/Hardening-Patch Version", temp_ver); ++ } ++#else + if (!sapi_module.phpinfo_as_text) { + php_printf("

PHP Version %s

\n", PHP_VERSION); + } else { + php_info_print_table_row(2, "PHP Version", PHP_VERSION); + } ++#endif + php_info_print_box_end(); + php_info_print_table_start(); + php_info_print_table_row(2, "System", php_uname ); +diff -Nura php-4.4.0/ext/standard/php_standard.h hardening-patch-4.4.0-0.4.3/ext/standard/php_standard.h +--- php-4.4.0/ext/standard/php_standard.h 2002-12-31 17:35:33.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/standard/php_standard.h 2005-09-11 23:31:08.000000000 +0200 +@@ -28,6 +28,7 @@ + #include "php_mail.h" + #include "md5.h" + #include "sha1.h" ++#include "sha256.h" + #include "html.h" + #include "exec.h" + #include "file.h" +diff -Nura php-4.4.0/ext/standard/sha256.c hardening-patch-4.4.0-0.4.3/ext/standard/sha256.c +--- php-4.4.0/ext/standard/sha256.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/standard/sha256.c 2005-09-11 23:31:08.000000000 +0200 +@@ -0,0 +1,398 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 5 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2004 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 3.0 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available through the world-wide-web at the following url: | ++ | http://www.php.net/license/3_0.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++*/ ++ ++/* $Id: sha256.c,v 1.9 2004/01/08 08:17:34 andi Exp $ */ ++ ++#include ++#include "php.h" ++ ++/* This code is heavily based on the PHP md5/sha1 implementations */ ++ ++#include "sha256.h" ++ ++PHPAPI void make_sha256_digest(char *sha256str, unsigned char *digest) ++{ ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ sprintf(sha256str, "%02x", digest[i]); ++ sha256str += 2; ++ } ++ ++ *sha256str = '\0'; ++} ++ ++/* {{{ proto string sha256(string str [, bool raw_output]) ++ Calculate the sha256 hash of a string */ ++PHP_FUNCTION(sha256) ++{ ++ char *arg; ++ int arg_len; ++ zend_bool raw_output = 0; ++ char sha256str[65]; ++ PHP_SHA256_CTX context; ++ unsigned char digest[32]; ++ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &arg, &arg_len, &raw_output) == FAILURE) { ++ return; ++ } ++ ++ sha256str[0] = '\0'; ++ PHP_SHA256Init(&context); ++ PHP_SHA256Update(&context, arg, arg_len); ++ PHP_SHA256Final(digest, &context); ++ if (raw_output) { ++ RETURN_STRINGL(digest, 32, 1); ++ } else { ++ make_sha256_digest(sha256str, digest); ++ RETVAL_STRING(sha256str, 1); ++ } ++ ++} ++ ++/* }}} */ ++ ++/* {{{ proto string sha256_file(string filename [, bool raw_output]) ++ Calculate the sha256 hash of given filename */ ++PHP_FUNCTION(sha256_file) ++{ ++ char *arg; ++ int arg_len; ++ zend_bool raw_output = 0; ++ char sha256str[65]; ++ unsigned char buf[1024]; ++ unsigned char digest[32]; ++ PHP_SHA256_CTX context; ++ int n; ++ FILE *fp; ++ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &arg, &arg_len, &raw_output) == FAILURE) { ++ return; ++ } ++ ++ if (PG(safe_mode) && (!php_checkuid(arg, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { ++ RETURN_FALSE; ++ } ++ ++ if (php_check_open_basedir(arg TSRMLS_CC)) { ++ RETURN_FALSE; ++ } ++ ++ if ((fp = VCWD_FOPEN(arg, "rb")) == NULL) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open file"); ++ RETURN_FALSE; ++ } ++ ++ PHP_SHA256Init(&context); ++ ++ while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { ++ PHP_SHA256Update(&context, buf, n); ++ } ++ ++ PHP_SHA256Final(digest, &context); ++ ++ if (ferror(fp)) { ++ fclose(fp); ++ RETURN_FALSE; ++ } ++ ++ fclose(fp); ++ ++ if (raw_output) { ++ RETURN_STRINGL(digest, 32, 1); ++ } else { ++ make_sha256_digest(sha256str, digest); ++ RETVAL_STRING(sha256str, 1); ++ } ++} ++/* }}} */ ++ ++ ++static void SHA256Transform(php_uint32[8], const unsigned char[64]); ++static void SHA256Encode(unsigned char *, php_uint32 *, unsigned int); ++static void SHA256Decode(php_uint32 *, const unsigned char *, unsigned int); ++ ++static unsigned char PADDING[64] = ++{ ++ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ++}; ++ ++/* F, G, H and I are basic SHA256 functions. ++ */ ++#define F(x) (ROTATE_RIGHT(x,2) ^ ROTATE_RIGHT(x,13) ^ ROTATE_RIGHT(x,22)) ++#define G(x, y, z) (((x) & (y)) | ((z) & ((y) | (x)))) ++#define H(x) (ROTATE_RIGHT(x,6) ^ ROTATE_RIGHT(x,11) ^ ROTATE_RIGHT(x,25)) ++#define I(x, y, z) (((x) & (y)) | ((~x) & z)) ++ ++/* ROTATE_RIGHT rotates x right n bits. ++ */ ++#define ROTATE_RIGHT(x, n) (((x) >> (n)) | ((x) << (32-(n)))) ++ ++/* W[i] ++ */ ++#define W(i) ( tmp1=ROTATE_RIGHT(x[(i-15)&15],7)^ROTATE_RIGHT(x[(i-15)&15],18)^(x[(i-15)&15] >> 3), \ ++ tmp2=ROTATE_RIGHT(x[(i-2)&15],17)^ROTATE_RIGHT(x[(i-2)&15],19)^(x[(i-2)&15] >> 10), \ ++ (x[i&15]=x[i&15] + tmp1 + x[(i-7)&15] + tmp2) ) ++ ++/* ROUND function of sha256 ++ */ ++ ++#define ROUND(a,b,c,d,e,f,g,h,w,k) { \ ++ t1 = (h) + H((e)) + I((e), (f), (g)) + (k) + (php_uint32)(w); \ ++ (h) = F((a)) + G((a), (b), (c)) + t1; \ ++ (d) += t1; \ ++ } ++ ++ ++/* {{{ PHP_SHA256Init ++ * SHA256 initialization. Begins an SHA256 operation, writing a new context. ++ */ ++PHPAPI void PHP_SHA256Init(PHP_SHA256_CTX * context) ++{ ++ context->count[0] = context->count[1] = 0; ++ /* Load magic initialization constants. ++ */ ++ context->state[0] = 0x6a09e667; ++ context->state[1] = 0xbb67ae85; ++ context->state[2] = 0x3c6ef372; ++ context->state[3] = 0xa54ff53a; ++ context->state[4] = 0x510e527f; ++ context->state[5] = 0x9b05688c; ++ context->state[6] = 0x1f83d9ab; ++ context->state[7] = 0x5be0cd19; ++} ++/* }}} */ ++ ++/* {{{ PHP_SHA256Update ++ SHA256 block update operation. Continues an SHA256 message-digest ++ operation, processing another message block, and updating the ++ context. ++ */ ++PHPAPI void PHP_SHA256Update(PHP_SHA256_CTX * context, const unsigned char *input, ++ unsigned int inputLen) ++{ ++ unsigned int i, index, partLen; ++ ++ /* Compute number of bytes mod 64 */ ++ index = (unsigned int) ((context->count[0] >> 3) & 0x3F); ++ ++ /* Update number of bits */ ++ if ((context->count[0] += ((php_uint32) inputLen << 3)) ++ < ((php_uint32) inputLen << 3)) ++ context->count[1]++; ++ context->count[1] += ((php_uint32) inputLen >> 29); ++ ++ partLen = 64 - index; ++ ++ /* Transform as many times as possible. ++ */ ++ if (inputLen >= partLen) { ++ memcpy ++ ((unsigned char*) & context->buffer[index], (unsigned char*) input, partLen); ++ SHA256Transform(context->state, context->buffer); ++ ++ for (i = partLen; i + 63 < inputLen; i += 64) ++ SHA256Transform(context->state, &input[i]); ++ ++ index = 0; ++ } else ++ i = 0; ++ ++ /* Buffer remaining input */ ++ memcpy ++ ((unsigned char*) & context->buffer[index], (unsigned char*) & input[i], ++ inputLen - i); ++} ++/* }}} */ ++ ++/* {{{ PHP_SHA256Final ++ SHA256 finalization. Ends an SHA256 message-digest operation, writing the ++ the message digest and zeroizing the context. ++ */ ++PHPAPI void PHP_SHA256Final(unsigned char digest[32], PHP_SHA256_CTX * context) ++{ ++ unsigned char bits[8]; ++ unsigned int index, padLen; ++ ++ /* Save number of bits */ ++ bits[7] = context->count[0] & 0xFF; ++ bits[6] = (context->count[0] >> 8) & 0xFF; ++ bits[5] = (context->count[0] >> 16) & 0xFF; ++ bits[4] = (context->count[0] >> 24) & 0xFF; ++ bits[3] = context->count[1] & 0xFF; ++ bits[2] = (context->count[1] >> 8) & 0xFF; ++ bits[1] = (context->count[1] >> 16) & 0xFF; ++ bits[0] = (context->count[1] >> 24) & 0xFF; ++ ++ /* Pad out to 56 mod 64. ++ */ ++ index = (unsigned int) ((context->count[0] >> 3) & 0x3f); ++ padLen = (index < 56) ? (56 - index) : (120 - index); ++ PHP_SHA256Update(context, PADDING, padLen); ++ ++ /* Append length (before padding) */ ++ PHP_SHA256Update(context, bits, 8); ++ ++ /* Store state in digest */ ++ SHA256Encode(digest, context->state, 32); ++ ++ /* Zeroize sensitive information. ++ */ ++ memset((unsigned char*) context, 0, sizeof(*context)); ++} ++/* }}} */ ++ ++/* {{{ SHA256Transform ++ * SHA256 basic transformation. Transforms state based on block. ++ */ ++static void SHA256Transform(state, block) ++php_uint32 state[8]; ++const unsigned char block[64]; ++{ ++ php_uint32 a = state[0], b = state[1], c = state[2]; ++ php_uint32 d = state[3], e = state[4], f = state[5]; ++ php_uint32 g = state[6], h = state[7], x[16], tmp1, tmp2, t1; ++ ++ SHA256Decode(x, block, 64); ++ ++ ROUND(a, b, c, d, e, f, g, h, x[0], 0x428a2f98) ++ ROUND(h, a, b, c, d, e, f, g, x[1], 0x71374491) ++ ROUND(g, h, a, b, c, d, e, f, x[2], 0xb5c0fbcf) ++ ROUND(f, g, h, a, b, c, d, e, x[3], 0xe9b5dba5) ++ ROUND(e, f, g, h, a, b, c, d, x[4], 0x3956c25b) ++ ROUND(d, e, f, g, h, a, b, c, x[5], 0x59f111f1) ++ ROUND(c, d, e, f, g, h, a, b, x[6], 0x923f82a4) ++ ROUND(b, c, d, e, f, g, h, a, x[7], 0xab1c5ed5) ++ ROUND(a, b, c, d, e, f, g, h, x[8], 0xd807aa98) ++ ROUND(h, a, b, c, d, e, f, g, x[9], 0x12835b01) ++ ROUND(g, h, a, b, c, d, e, f, x[10], 0x243185be) ++ ROUND(f, g, h, a, b, c, d, e, x[11], 0x550c7dc3) ++ ROUND(e, f, g, h, a, b, c, d, x[12], 0x72be5d74) ++ ROUND(d, e, f, g, h, a, b, c, x[13], 0x80deb1fe) ++ ROUND(c, d, e, f, g, h, a, b, x[14], 0x9bdc06a7) ++ ROUND(b, c, d, e, f, g, h, a, x[15], 0xc19bf174) ++ ROUND(a, b, c, d, e, f, g, h, W(16), 0xe49b69c1) ++ ROUND(h, a, b, c, d, e, f, g, W(17), 0xefbe4786) ++ ROUND(g, h, a, b, c, d, e, f, W(18), 0x0fc19dc6) ++ ROUND(f, g, h, a, b, c, d, e, W(19), 0x240ca1cc) ++ ROUND(e, f, g, h, a, b, c, d, W(20), 0x2de92c6f) ++ ROUND(d, e, f, g, h, a, b, c, W(21), 0x4a7484aa) ++ ROUND(c, d, e, f, g, h, a, b, W(22), 0x5cb0a9dc) ++ ROUND(b, c, d, e, f, g, h, a, W(23), 0x76f988da) ++ ROUND(a, b, c, d, e, f, g, h, W(24), 0x983e5152) ++ ROUND(h, a, b, c, d, e, f, g, W(25), 0xa831c66d) ++ ROUND(g, h, a, b, c, d, e, f, W(26), 0xb00327c8) ++ ROUND(f, g, h, a, b, c, d, e, W(27), 0xbf597fc7) ++ ROUND(e, f, g, h, a, b, c, d, W(28), 0xc6e00bf3) ++ ROUND(d, e, f, g, h, a, b, c, W(29), 0xd5a79147) ++ ROUND(c, d, e, f, g, h, a, b, W(30), 0x06ca6351) ++ ROUND(b, c, d, e, f, g, h, a, W(31), 0x14292967) ++ ROUND(a, b, c, d, e, f, g, h, W(32), 0x27b70a85) ++ ROUND(h, a, b, c, d, e, f, g, W(33), 0x2e1b2138) ++ ROUND(g, h, a, b, c, d, e, f, W(34), 0x4d2c6dfc) ++ ROUND(f, g, h, a, b, c, d, e, W(35), 0x53380d13) ++ ROUND(e, f, g, h, a, b, c, d, W(36), 0x650a7354) ++ ROUND(d, e, f, g, h, a, b, c, W(37), 0x766a0abb) ++ ROUND(c, d, e, f, g, h, a, b, W(38), 0x81c2c92e) ++ ROUND(b, c, d, e, f, g, h, a, W(39), 0x92722c85) ++ ROUND(a, b, c, d, e, f, g, h, W(40), 0xa2bfe8a1) ++ ROUND(h, a, b, c, d, e, f, g, W(41), 0xa81a664b) ++ ROUND(g, h, a, b, c, d, e, f, W(42), 0xc24b8b70) ++ ROUND(f, g, h, a, b, c, d, e, W(43), 0xc76c51a3) ++ ROUND(e, f, g, h, a, b, c, d, W(44), 0xd192e819) ++ ROUND(d, e, f, g, h, a, b, c, W(45), 0xd6990624) ++ ROUND(c, d, e, f, g, h, a, b, W(46), 0xf40e3585) ++ ROUND(b, c, d, e, f, g, h, a, W(47), 0x106aa070) ++ ROUND(a, b, c, d, e, f, g, h, W(48), 0x19a4c116) ++ ROUND(h, a, b, c, d, e, f, g, W(49), 0x1e376c08) ++ ROUND(g, h, a, b, c, d, e, f, W(50), 0x2748774c) ++ ROUND(f, g, h, a, b, c, d, e, W(51), 0x34b0bcb5) ++ ROUND(e, f, g, h, a, b, c, d, W(52), 0x391c0cb3) ++ ROUND(d, e, f, g, h, a, b, c, W(53), 0x4ed8aa4a) ++ ROUND(c, d, e, f, g, h, a, b, W(54), 0x5b9cca4f) ++ ROUND(b, c, d, e, f, g, h, a, W(55), 0x682e6ff3) ++ ROUND(a, b, c, d, e, f, g, h, W(56), 0x748f82ee) ++ ROUND(h, a, b, c, d, e, f, g, W(57), 0x78a5636f) ++ ROUND(g, h, a, b, c, d, e, f, W(58), 0x84c87814) ++ ROUND(f, g, h, a, b, c, d, e, W(59), 0x8cc70208) ++ ROUND(e, f, g, h, a, b, c, d, W(60), 0x90befffa) ++ ROUND(d, e, f, g, h, a, b, c, W(61), 0xa4506ceb) ++ ROUND(c, d, e, f, g, h, a, b, W(62), 0xbef9a3f7) ++ ROUND(b, c, d, e, f, g, h, a, W(63), 0xc67178f2) ++ ++ state[0] += a; ++ state[1] += b; ++ state[2] += c; ++ state[3] += d; ++ state[4] += e; ++ state[5] += f; ++ state[6] += g; ++ state[7] += h; ++ ++ /* Zeroize sensitive information. */ ++ memset((unsigned char*) x, 0, sizeof(x)); ++} ++/* }}} */ ++ ++/* {{{ SHA256Encode ++ Encodes input (php_uint32) into output (unsigned char). Assumes len is ++ a multiple of 4. ++ */ ++static void SHA256Encode(output, input, len) ++unsigned char *output; ++php_uint32 *input; ++unsigned int len; ++{ ++ unsigned int i, j; ++ ++ for (i = 0, j = 0; j < len; i++, j += 4) { ++ output[j] = (unsigned char) ((input[i] >> 24) & 0xff); ++ output[j + 1] = (unsigned char) ((input[i] >> 16) & 0xff); ++ output[j + 2] = (unsigned char) ((input[i] >> 8) & 0xff); ++ output[j + 3] = (unsigned char) (input[i] & 0xff); ++ } ++} ++/* }}} */ ++ ++/* {{{ SHA256Decode ++ Decodes input (unsigned char) into output (php_uint32). Assumes len is ++ a multiple of 4. ++ */ ++static void SHA256Decode(output, input, len) ++php_uint32 *output; ++const unsigned char *input; ++unsigned int len; ++{ ++ unsigned int i, j; ++ ++ for (i = 0, j = 0; j < len; i++, j += 4) ++ output[i] = ((php_uint32) input[j + 3]) | (((php_uint32) input[j + 2]) << 8) | ++ (((php_uint32) input[j + 1]) << 16) | (((php_uint32) input[j]) << 24); ++} ++/* }}} */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-4.4.0/ext/standard/sha256.h hardening-patch-4.4.0-0.4.3/ext/standard/sha256.h +--- php-4.4.0/ext/standard/sha256.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/standard/sha256.h 2005-09-11 23:31:08.000000000 +0200 +@@ -0,0 +1,40 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 5 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2004 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 3.0 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available through the world-wide-web at the following url: | ++ | http://www.php.net/license/3_0.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++*/ ++ ++/* $Id: sha256.h,v 1.4 2004/01/08 17:32:52 sniper Exp $ */ ++ ++#ifndef SHA256_H ++#define SHA256_H ++ ++#include "ext/standard/basic_functions.h" ++ ++/* SHA1 context. */ ++typedef struct { ++ php_uint32 state[8]; /* state (ABCD) */ ++ php_uint32 count[2]; /* number of bits, modulo 2^64 (lsb first) */ ++ unsigned char buffer[64]; /* input buffer */ ++} PHP_SHA256_CTX; ++ ++PHPAPI void PHP_SHA256Init(PHP_SHA256_CTX *); ++PHPAPI void PHP_SHA256Update(PHP_SHA256_CTX *, const unsigned char *, unsigned int); ++PHPAPI void PHP_SHA256Final(unsigned char[32], PHP_SHA256_CTX *); ++ ++PHP_FUNCTION(sha256); ++PHP_FUNCTION(sha256_file); ++ ++#endif +diff -Nura php-4.4.0/ext/standard/syslog.c hardening-patch-4.4.0-0.4.3/ext/standard/syslog.c +--- php-4.4.0/ext/standard/syslog.c 2004-07-30 16:38:29.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/ext/standard/syslog.c 2005-09-11 23:31:08.000000000 +0200 +@@ -42,6 +42,8 @@ + */ + PHP_MINIT_FUNCTION(syslog) + { ++ ++#if !HARDENING_PATCH + /* error levels */ + REGISTER_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ + REGISTER_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ +@@ -97,7 +99,7 @@ + /* AIX doesn't have LOG_PERROR */ + REGISTER_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ + #endif +- ++#endif + return SUCCESS; + } + /* }}} */ +diff -Nura php-4.4.0/ext/varfilter/config.m4 hardening-patch-4.4.0-0.4.3/ext/varfilter/config.m4 +--- php-4.4.0/ext/varfilter/config.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/varfilter/config.m4 2005-09-11 23:31:08.000000000 +0200 +@@ -0,0 +1,11 @@ ++dnl ++dnl $Id: config.m4,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++dnl ++ ++PHP_ARG_ENABLE(varfilter, whether to enable Hardening-Patch's variable filter, ++[ --disable-varfilter Disable Hardening-Patch's variable filter], yes) ++ ++if test "$PHP_VARFILTER" != "no"; then ++ AC_DEFINE(HAVE_VARFILTER, 1, [ ]) ++ PHP_NEW_EXTENSION(varfilter, varfilter.c, $ext_shared) ++fi +diff -Nura php-4.4.0/ext/varfilter/CREDITS hardening-patch-4.4.0-0.4.3/ext/varfilter/CREDITS +--- php-4.4.0/ext/varfilter/CREDITS 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/varfilter/CREDITS 2005-09-11 23:31:08.000000000 +0200 +@@ -0,0 +1,2 @@ ++varfilter ++Stefan Esser +\ Kein Zeilenumbruch am Dateiende. +diff -Nura php-4.4.0/ext/varfilter/php_varfilter.h hardening-patch-4.4.0-0.4.3/ext/varfilter/php_varfilter.h +--- php-4.4.0/ext/varfilter/php_varfilter.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/varfilter/php_varfilter.h 2005-09-12 18:15:08.000000000 +0200 +@@ -0,0 +1,112 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: php_varfilter.h,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifndef PHP_VARFILTER_H ++#define PHP_VARFILTER_H ++ ++extern zend_module_entry varfilter_module_entry; ++#define phpext_varfilter_ptr &varfilter_module_entry ++ ++#ifdef PHP_WIN32 ++#define PHP_VARFILTER_API __declspec(dllexport) ++#else ++#define PHP_VARFILTER_API ++#endif ++ ++#ifdef ZTS ++#include "TSRM.h" ++#endif ++ ++#include "SAPI.h" ++ ++#include "php_variables.h" ++ ++ ++PHP_MINIT_FUNCTION(varfilter); ++PHP_MSHUTDOWN_FUNCTION(varfilter); ++PHP_RINIT_FUNCTION(varfilter); ++PHP_RSHUTDOWN_FUNCTION(varfilter); ++PHP_MINFO_FUNCTION(varfilter); ++ ++ ++ZEND_BEGIN_MODULE_GLOBALS(varfilter) ++/* request variables */ ++ long max_request_variables; ++ long cur_request_variables; ++ long max_varname_length; ++ long max_totalname_length; ++ long max_value_length; ++ long max_array_depth; ++ long max_array_index_length; ++/* cookie variables */ ++ long max_cookie_vars; ++ long cur_cookie_vars; ++ long max_cookie_name_length; ++ long max_cookie_totalname_length; ++ long max_cookie_value_length; ++ long max_cookie_array_depth; ++ long max_cookie_array_index_length; ++/* get variables */ ++ long max_get_vars; ++ long cur_get_vars; ++ long max_get_name_length; ++ long max_get_totalname_length; ++ long max_get_value_length; ++ long max_get_array_depth; ++ long max_get_array_index_length; ++/* post variables */ ++ long max_post_vars; ++ long cur_post_vars; ++ long max_post_name_length; ++ long max_post_totalname_length; ++ long max_post_value_length; ++ long max_post_array_depth; ++ long max_post_array_index_length; ++/* fileupload */ ++ long max_uploads; ++ long cur_uploads; ++ zend_bool disallow_elf_files; ++ char *verification_script; ++ ++ZEND_END_MODULE_GLOBALS(varfilter) ++ ++ ++#ifdef ZTS ++#define VARFILTER_G(v) TSRMG(varfilter_globals_id, zend_varfilter_globals *, v) ++#else ++#define VARFILTER_G(v) (varfilter_globals.v) ++#endif ++ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter); ++SAPI_UPLOAD_VARNAME_FILTER_FUNC(varfilter_upload_varname_filter); ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter); ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter); ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter); ++ ++#endif /* PHP_VARFILTER_H */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * indent-tabs-mode: t ++ * End: ++ */ +diff -Nura php-4.4.0/ext/varfilter/varfilter.c hardening-patch-4.4.0-0.4.3/ext/varfilter/varfilter.c +--- php-4.4.0/ext/varfilter/varfilter.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/ext/varfilter/varfilter.c 2005-09-12 18:15:08.000000000 +0200 +@@ -0,0 +1,726 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: varfilter.c,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "php.h" ++#include "php_ini.h" ++#include "ext/standard/info.h" ++#include "php_varfilter.h" ++#include "hardening_patch.h" ++ ++ZEND_DECLARE_MODULE_GLOBALS(varfilter) ++ ++/* True global resources - no need for thread safety here */ ++static int le_varfilter; ++ ++/* {{{ varfilter_module_entry ++ */ ++zend_module_entry varfilter_module_entry = { ++#if ZEND_MODULE_API_NO >= 20010901 ++ STANDARD_MODULE_HEADER, ++#endif ++ "varfilter", ++ NULL, ++ PHP_MINIT(varfilter), ++ PHP_MSHUTDOWN(varfilter), ++ PHP_RINIT(varfilter), /* Replace with NULL if there's nothing to do at request start */ ++ PHP_RSHUTDOWN(varfilter), /* Replace with NULL if there's nothing to do at request end */ ++ PHP_MINFO(varfilter), ++#if ZEND_MODULE_API_NO >= 20010901 ++ "0.3.2", /* Replace with version number for your extension */ ++#endif ++ STANDARD_MODULE_PROPERTIES ++}; ++/* }}} */ ++ ++#ifdef COMPILE_DL_VARFILTER ++ZEND_GET_MODULE(varfilter) ++#endif ++ ++/* {{{ PHP_INI ++ */ ++PHP_INI_BEGIN() ++ /* for backward compatibility */ ++ STD_PHP_INI_ENTRY("varfilter.max_request_variables", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.request.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.cookie.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_cookie_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_value_length", "10000", PHP_INI_PERDIR, OnUpdateLong, max_cookie_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.get.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_get_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_get_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_value_length", "512", PHP_INI_PERDIR, OnUpdateLong, max_get_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_depth", "50", PHP_INI_PERDIR, OnUpdateLong, max_get_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.post.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_post_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_post_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_post_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_post_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.upload.max_uploads", "25", PHP_INI_PERDIR, OnUpdateLong, max_uploads, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.disallow_elf_files", "1", PHP_INI_SYSTEM, OnUpdateBool, disallow_elf_files, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.verification_script", NULL, PHP_INI_SYSTEM, OnUpdateString, verification_script, zend_varfilter_globals, varfilter_globals) ++ ++ ++PHP_INI_END() ++/* }}} */ ++ ++/* {{{ php_varfilter_init_globals ++ */ ++static void php_varfilter_init_globals(zend_varfilter_globals *varfilter_globals) ++{ ++ varfilter_globals->max_request_variables = 200; ++ varfilter_globals->max_varname_length = 64; ++ varfilter_globals->max_value_length = 10000; ++ varfilter_globals->max_array_depth = 100; ++ varfilter_globals->max_totalname_length = 256; ++ varfilter_globals->max_array_index_length = 64; ++ ++ varfilter_globals->max_cookie_vars = 100; ++ varfilter_globals->max_cookie_name_length = 64; ++ varfilter_globals->max_cookie_totalname_length = 256; ++ varfilter_globals->max_cookie_value_length = 10000; ++ varfilter_globals->max_cookie_array_depth = 100; ++ varfilter_globals->max_cookie_array_index_length = 64; ++ ++ varfilter_globals->max_get_vars = 100; ++ varfilter_globals->max_get_name_length = 64; ++ varfilter_globals->max_get_totalname_length = 256; ++ varfilter_globals->max_get_value_length = 512; ++ varfilter_globals->max_get_array_depth = 50; ++ varfilter_globals->max_get_array_index_length = 64; ++ ++ varfilter_globals->max_post_vars = 200; ++ varfilter_globals->max_post_name_length = 64; ++ varfilter_globals->max_post_totalname_length = 256; ++ varfilter_globals->max_post_value_length = 65000; ++ varfilter_globals->max_post_array_depth = 100; ++ varfilter_globals->max_post_array_index_length = 64; ++ ++ varfilter_globals->max_uploads = 25; ++ varfilter_globals->disallow_elf_files = 1; ++ varfilter_globals->verification_script = NULL; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINIT_FUNCTION ++ */ ++PHP_MINIT_FUNCTION(varfilter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(varfilter, php_varfilter_init_globals, NULL); ++ REGISTER_INI_ENTRIES(); ++ ++ sapi_register_input_filter(varfilter_input_filter); ++ sapi_register_upload_varname_filter(varfilter_upload_varname_filter); ++ sapi_register_pre_upload_filter(varfilter_pre_upload_filter); ++ sapi_register_upload_content_filter(varfilter_upload_content_filter); ++ sapi_register_post_upload_filter(varfilter_post_upload_filter); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MSHUTDOWN_FUNCTION ++ */ ++PHP_MSHUTDOWN_FUNCTION(varfilter) ++{ ++ UNREGISTER_INI_ENTRIES(); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request start */ ++/* {{{ PHP_RINIT_FUNCTION ++ */ ++PHP_RINIT_FUNCTION(varfilter) ++{ ++ VARFILTER_G(cur_request_variables) = 0; ++ VARFILTER_G(cur_get_vars) = 0; ++ VARFILTER_G(cur_post_vars) = 0; ++ VARFILTER_G(cur_cookie_vars) = 0; ++ ++ VARFILTER_G(cur_uploads) = 0; ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request end */ ++/* {{{ PHP_RSHUTDOWN_FUNCTION ++ */ ++PHP_RSHUTDOWN_FUNCTION(varfilter) ++{ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINFO_FUNCTION ++ */ ++PHP_MINFO_FUNCTION(varfilter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_header(2, "Hardening-Patch's variable filter support", "enabled"); ++ php_info_print_table_end(); ++ ++ DISPLAY_INI_ENTRIES(); ++} ++/* }}} */ ++ ++/* {{{ normalize_varname ++ */ ++static void normalize_varname(char *varname) ++{ ++ char *s=varname, *index=NULL, *indexend=NULL, *p; ++ ++ /* overjump leading space */ ++ while (*s == ' ') { ++ s++; ++ } ++ ++ /* and remove it */ ++ if (s != varname) { ++ memmove(varname, s, strlen(s)+1); ++ } ++ ++ for (p=varname; *p && *p != '['; p++) { ++ switch(*p) { ++ case ' ': ++ case '.': ++ *p='_'; ++ break; ++ } ++ } ++ ++ /* find index */ ++ index = strchr(varname, '['); ++ if (index) { ++ index++; ++ s=index; ++ } else { ++ return; ++ } ++ ++ /* done? */ ++ while (index) { ++ ++ while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') { ++ index++; ++ } ++ indexend = strchr(index, ']'); ++ indexend = indexend ? indexend + 1 : index + strlen(index); ++ ++ if (s != index) { ++ memmove(s, index, strlen(index)+1); ++ s += indexend-index; ++ } else { ++ s = indexend; ++ } ++ ++ if (*s == '[') { ++ s++; ++ index = s; ++ } else { ++ index = NULL; ++ } ++ } ++ *s++='\0'; ++} ++/* }}} */ ++ ++/* {{{ SAPI_UPLOAD_VARNAME_FILTER_FUNC ++ */ ++SAPI_UPLOAD_VARNAME_FILTER_FUNC(varfilter_upload_varname_filter) ++{ ++ char *index, *prev_index = NULL, *var; ++ unsigned int var_len, total_len, depth = 0; ++ ++ var = estrdup(varname); ++ ++ /* Normalize the variable name */ ++ normalize_varname(var); ++ ++ /* Find length of variable name */ ++ index = strchr(var, '['); ++ total_len = strlen(var); ++ var_len = index ? index-var : total_len; ++ ++ /* Drop this variable if it exceeds the varname/total length limit */ ++ if (VARFILTER_G(max_varname_length) && VARFILTER_G(max_varname_length) < var_len) { ++ php_security_log(S_FILES, "configured request variable name length limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ if (VARFILTER_G(max_totalname_length) && VARFILTER_G(max_totalname_length) < total_len) { ++ php_security_log(S_FILES, "configured request variable total name length limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ if (VARFILTER_G(max_post_name_length) && VARFILTER_G(max_post_name_length) < var_len) { ++ php_security_log(S_FILES, "configured POST variable name length limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ if (VARFILTER_G(max_post_totalname_length) && VARFILTER_G(max_post_totalname_length) < var_len) { ++ php_security_log(S_FILES, "configured POST variable total name length limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ ++ /* Find out array depth */ ++ while (index) { ++ unsigned int index_length; ++ ++ depth++; ++ index = strchr(index+1, '['); ++ ++ if (prev_index) { ++ index_length = index ? index - 1 - prev_index - 1: strlen(prev_index); ++ ++ if (VARFILTER_G(max_array_index_length) && VARFILTER_G(max_array_index_length) < index_length) { ++ php_security_log(S_FILES, "configured request variable array index length limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ if (VARFILTER_G(max_post_array_index_length) && VARFILTER_G(max_post_array_index_length) < index_length) { ++ php_security_log(S_FILES, "configured POST variable array index length limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ prev_index = index; ++ } ++ ++ } ++ ++ /* Drop this variable if it exceeds the array depth limit */ ++ if (VARFILTER_G(max_array_depth) && VARFILTER_G(max_array_depth) < depth) { ++ php_security_log(S_FILES, "configured request variable array depth limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ if (VARFILTER_G(max_post_array_depth) && VARFILTER_G(max_post_array_depth) < depth) { ++ php_security_log(S_FILES, "configured POST variable array depth limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ ++ /* Drop this variable if it is one of GLOBALS, _GET, _POST, ... */ ++ /* This is to protect several silly scripts that do globalizing themself */ ++ ++ switch (var_len) { ++ case 18: ++ if (memcmp(var, "HTTP_RAW_POST_DATA", 18)==0) goto protected_varname2; ++ break; ++ case 17: ++ if (memcmp(var, "HTTP_SESSION_VARS", 17)==0) goto protected_varname2; ++ break; ++ case 16: ++ if (memcmp(var, "HTTP_SERVER_VARS", 16)==0) goto protected_varname2; ++ if (memcmp(var, "HTTP_COOKIE_VARS", 16)==0) goto protected_varname2; ++ break; ++ case 15: ++ if (memcmp(var, "HTTP_POST_FILES", 15)==0) goto protected_varname2; ++ break; ++ case 14: ++ if (memcmp(var, "HTTP_POST_VARS", 14)==0) goto protected_varname2; ++ break; ++ case 13: ++ if (memcmp(var, "HTTP_GET_VARS", 13)==0) goto protected_varname2; ++ if (memcmp(var, "HTTP_ENV_VARS", 13)==0) goto protected_varname2; ++ break; ++ case 8: ++ if (memcmp(var, "_SESSION", 8)==0) goto protected_varname2; ++ if (memcmp(var, "_REQUEST", 8)==0) goto protected_varname2; ++ break; ++ case 7: ++ if (memcmp(var, "GLOBALS", 7)==0) goto protected_varname2; ++ if (memcmp(var, "_COOKIE", 7)==0) goto protected_varname2; ++ if (memcmp(var, "_SERVER", 7)==0) goto protected_varname2; ++ break; ++ case 6: ++ if (memcmp(var, "_FILES", 6)==0) goto protected_varname2; ++ break; ++ case 5: ++ if (memcmp(var, "_POST", 5)==0) goto protected_varname2; ++ break; ++ case 4: ++ if (memcmp(var, "_ENV", 4)==0) goto protected_varname2; ++ if (memcmp(var, "_GET", 4)==0) goto protected_varname2; ++ break; ++ } ++ ++ efree(var); ++ return SUCCESS; ++protected_varname2: ++ php_security_log(S_FILES, "tried to register forbidden variable '%s' through FILE variables", var); ++return_failure: ++ efree(var); ++ return FAILURE; ++} ++/* }}} */ ++ ++/* {{{ SAPI_PRE_UPLOAD_FILTER_FUNC ++ */ ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter) ++{ ++ /* Drop this fileupload if the limit is reached */ ++ if (VARFILTER_G(max_uploads) && VARFILTER_G(max_uploads) <= VARFILTER_G(cur_uploads)) { ++ php_security_log(S_FILES, "configured fileupload limit exceeded - file dropped"); ++ return FAILURE; ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_UPLOAD_CONTENT_FILTER_FUNC ++ */ ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter) ++{ ++ ++ if (VARFILTER_G(disallow_elf_files)) { ++ ++ if (offset == 0 && buffer_len > 10) { ++ ++ if (buffer[0] == 0x7F && buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F') { ++ php_security_log(S_FILES, "uploaded file is an ELF executable - file dropped"); ++ return FAILURE; ++ } ++ } ++ ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_POST_UPLOAD_FILTER_FUNC ++ */ ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter) ++{ ++ int retval = SUCCESS; ++ ++ if (VARFILTER_G(verification_script)) { ++ char cmd[8192]; ++ FILE *in; ++ int first=1; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s", VARFILTER_G(verification_script), tmpfilename); ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_FILES, "unable to execute fileupload verification script %s - file dropped", VARFILTER_G(verification_script)); ++ return FAILURE; ++ } ++ ++ retval = FAILURE; ++ ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ if (first) { ++ retval = atoi(cmd) == 1 ? SUCCESS : FAILURE; ++ first = 0; ++ } ++ } ++ pclose(in); ++ } ++ ++ if (retval != SUCCESS) { ++ php_security_log(S_FILES, "fileupload verification script disallows file - file dropped"); ++ return FAILURE; ++ } ++ ++ VARFILTER_G(cur_uploads)++; ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_INPUT_FILTER_FUNC ++ */ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter) ++{ ++ char *index, *prev_index = NULL; ++ unsigned int var_len, total_len, depth = 0; ++ ++ /* Drop this variable if the limit is reached */ ++ if (VARFILTER_G(max_request_variables) && VARFILTER_G(max_request_variables) <= VARFILTER_G(cur_request_variables)) { ++ php_security_log(S_VARS, "configured request variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_vars) && VARFILTER_G(max_get_vars) <= VARFILTER_G(cur_get_vars)) { ++ php_security_log(S_VARS, "configured GET variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_vars) && VARFILTER_G(max_cookie_vars) <= VARFILTER_G(cur_cookie_vars)) { ++ php_security_log(S_VARS, "configured COOKIE variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_vars) && VARFILTER_G(max_post_vars) <= VARFILTER_G(cur_post_vars)) { ++ php_security_log(S_VARS, "configured POST variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ ++ /* Drop this variable if it exceeds the value length limit */ ++ if (VARFILTER_G(max_value_length) && VARFILTER_G(max_value_length) < val_len) { ++ php_security_log(S_VARS, "configured request variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_value_length) && VARFILTER_G(max_get_value_length) < val_len) { ++ php_security_log(S_VARS, "configured GET variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_value_length) && VARFILTER_G(max_cookie_value_length) < val_len) { ++ php_security_log(S_VARS, "configured COOKIE variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_value_length) && VARFILTER_G(max_post_value_length) < val_len) { ++ php_security_log(S_VARS, "configured POST variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Normalize the variable name */ ++ normalize_varname(var); ++ ++ /* Find length of variable name */ ++ index = strchr(var, '['); ++ total_len = strlen(var); ++ var_len = index ? index-var : total_len; ++ ++ /* Drop this variable if it exceeds the varname/total length limit */ ++ if (VARFILTER_G(max_varname_length) && VARFILTER_G(max_varname_length) < var_len) { ++ php_security_log(S_VARS, "configured request variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_totalname_length) && VARFILTER_G(max_totalname_length) < total_len) { ++ php_security_log(S_VARS, "configured request variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_name_length) && VARFILTER_G(max_get_name_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_get_totalname_length) && VARFILTER_G(max_get_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_name_length) && VARFILTER_G(max_cookie_name_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_cookie_totalname_length) && VARFILTER_G(max_cookie_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_name_length) && VARFILTER_G(max_post_name_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_post_totalname_length) && VARFILTER_G(max_post_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Find out array depth */ ++ while (index) { ++ unsigned int index_length; ++ ++ depth++; ++ index = strchr(index+1, '['); ++ ++ if (prev_index) { ++ index_length = index ? index - 1 - prev_index - 1: strlen(prev_index); ++ ++ if (VARFILTER_G(max_array_index_length) && VARFILTER_G(max_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured request variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_index_length) && VARFILTER_G(max_get_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured GET variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_index_length) && VARFILTER_G(max_cookie_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured COOKIE variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_index_length) && VARFILTER_G(max_post_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured POST variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ prev_index = index; ++ } ++ ++ } ++ ++ /* Drop this variable if it exceeds the array depth limit */ ++ if (VARFILTER_G(max_array_depth) && VARFILTER_G(max_array_depth) < depth) { ++ php_security_log(S_VARS, "configured request variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_depth) && VARFILTER_G(max_get_array_depth) < depth) { ++ php_security_log(S_VARS, "configured GET variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_depth) && VARFILTER_G(max_cookie_array_depth) < depth) { ++ php_security_log(S_VARS, "configured COOKIE variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_depth) && VARFILTER_G(max_post_array_depth) < depth) { ++ php_security_log(S_VARS, "configured POST variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Drop this variable if it is one of GLOBALS, _GET, _POST, ... */ ++ /* This is to protect several silly scripts that do globalizing themself */ ++ ++ switch (var_len) { ++ case 18: ++ if (memcmp(var, "HTTP_RAW_POST_DATA", 18)==0) goto protected_varname; ++ break; ++ case 17: ++ if (memcmp(var, "HTTP_SESSION_VARS", 17)==0) goto protected_varname; ++ break; ++ case 16: ++ if (memcmp(var, "HTTP_SERVER_VARS", 16)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_COOKIE_VARS", 16)==0) goto protected_varname; ++ break; ++ case 15: ++ if (memcmp(var, "HTTP_POST_FILES", 15)==0) goto protected_varname; ++ break; ++ case 14: ++ if (memcmp(var, "HTTP_POST_VARS", 14)==0) goto protected_varname; ++ break; ++ case 13: ++ if (memcmp(var, "HTTP_GET_VARS", 13)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_ENV_VARS", 13)==0) goto protected_varname; ++ break; ++ case 8: ++ if (memcmp(var, "_SESSION", 8)==0) goto protected_varname; ++ if (memcmp(var, "_REQUEST", 8)==0) goto protected_varname; ++ break; ++ case 7: ++ if (memcmp(var, "GLOBALS", 7)==0) goto protected_varname; ++ if (memcmp(var, "_COOKIE", 7)==0) goto protected_varname; ++ if (memcmp(var, "_SERVER", 7)==0) goto protected_varname; ++ break; ++ case 6: ++ if (memcmp(var, "_FILES", 6)==0) goto protected_varname; ++ break; ++ case 5: ++ if (memcmp(var, "_POST", 5)==0) goto protected_varname; ++ break; ++ case 4: ++ if (memcmp(var, "_ENV", 4)==0) goto protected_varname; ++ if (memcmp(var, "_GET", 4)==0) goto protected_varname; ++ break; ++ } ++ ++ /* Okay let PHP register this variable */ ++ VARFILTER_G(cur_request_variables)++; ++ switch (arg) { ++ case PARSE_GET: ++ VARFILTER_G(cur_get_vars)++; ++ break; ++ case PARSE_COOKIE: ++ VARFILTER_G(cur_cookie_vars)++; ++ break; ++ case PARSE_POST: ++ VARFILTER_G(cur_post_vars)++; ++ break; ++ } ++ ++ if (new_val_len) { ++ *new_val_len = val_len; ++ } ++ ++ return 1; ++protected_varname: ++ php_security_log(S_VARS, "tried to register forbidden variable '%s' through %s variables", var, arg == PARSE_GET ? "GET" : arg == PARSE_POST ? "POST" : "COOKIE"); ++ return 0; ++} ++/* }}} */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: noet sw=4 ts=4 fdm=marker ++ * vim<600: noet sw=4 ts=4 ++ */ ++ ++ +diff -Nura php-4.4.0/main/fopen_wrappers.c hardening-patch-4.4.0-0.4.3/main/fopen_wrappers.c +--- php-4.4.0/main/fopen_wrappers.c 2005-02-03 00:44:07.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/main/fopen_wrappers.c 2005-09-11 23:31:08.000000000 +0200 +@@ -166,6 +166,21 @@ + char *pathbuf; + char *ptr; + char *end; ++ char path_copy[MAXPATHLEN]; ++ int path_len; ++ ++ /* Special case path ends with a trailing slash */ ++ path_len = strlen(path); ++ if (path_len >= MAXPATHLEN) { ++ errno = EPERM; /* we deny permission to open it */ ++ return -1; ++ } ++ if (path_len > 0 && path[path_len-1] == PHP_DIR_SEPARATOR) { ++ memcpy(path_copy, path, path_len+1); ++ while (path_len > 0 && path_copy[path_len-1] == PHP_DIR_SEPARATOR) path_len--; ++ path_copy[path_len] = '\0'; ++ path = (const char *)&path_copy; ++ } + + pathbuf = estrdup(PG(open_basedir)); + +diff -Nura php-4.4.0/main/hardened_globals.h hardening-patch-4.4.0-0.4.3/main/hardened_globals.h +--- php-4.4.0/main/hardened_globals.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/main/hardened_globals.h 2005-09-12 18:15:08.000000000 +0200 +@@ -0,0 +1,62 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_GLOBALS_H ++#define HARDENED_GLOBALS_H ++ ++typedef struct _hardened_globals hardened_globals_struct; ++ ++#ifdef ZTS ++# define HG(v) TSRMG(hardened_globals_id, hardened_globals_struct *, v) ++extern int hardened_globals_id; ++#else ++# define HG(v) (hardened_globals.v) ++extern struct _hardened_globals hardened_globals; ++#endif ++ ++ ++struct _hardened_globals { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_1; ++ unsigned int canary_2; ++#endif ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_3; ++ unsigned int canary_4; ++ unsigned int ll_canary_inited; ++#endif ++ zend_bool hphp_sql_bailout_on_error; ++ zend_bool hphp_multiheader; ++ HashTable *eval_whitelist; ++ HashTable *eval_blacklist; ++ HashTable *func_whitelist; ++ HashTable *func_blacklist; ++ HashTable *include_whitelist; ++ HashTable *include_blacklist; ++ unsigned int dummy; ++}; ++ ++ ++#endif /* HARDENED_GLOBALS_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nura php-4.4.0/main/hardening_patch.c hardening-patch-4.4.0-0.4.3/main/hardening_patch.c +--- php-4.4.0/main/hardening_patch.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/main/hardening_patch.c 2005-09-12 18:15:08.000000000 +0200 +@@ -0,0 +1,424 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: hardening_patch.c,v 1.2 2004/11/21 09:38:52 ionic Exp $ */ ++ ++#include "php.h" ++ ++#include ++#include ++ ++#if HAVE_UNISTD_H ++#include ++#endif ++#include "SAPI.h" ++#include "php_globals.h" ++ ++#if HARDENING_PATCH ++ ++#ifdef HAVE_SYS_SOCKET_H ++#include ++#endif ++ ++#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE) ++#undef AF_UNIX ++#endif ++ ++#if defined(AF_UNIX) ++#include ++#endif ++ ++#define SYSLOG_PATH "/dev/log" ++ ++#include "snprintf.h" ++ ++#include "hardening_patch.h" ++ ++#ifdef ZTS ++#include "hardened_globals.h" ++int hardened_globals_id; ++#else ++struct _hardened_globals hardened_globals; ++#endif ++ ++static void hardened_globals_ctor(hardened_globals_struct *hardened_globals TSRMLS_DC) ++{ ++ memset(hardened_globals, 0, sizeof(*hardened_globals)); ++} ++ ++ ++PHPAPI void hardened_startup() ++{ ++#ifdef ZTS ++ ts_allocate_id(&hardened_globals_id, sizeof(hardened_globals_struct), (ts_allocate_ctor) hardened_globals_ctor, NULL); ++#else ++ hardened_globals_ctor(&hardened_globals TSRMLS_CC); ++#endif ++} ++ ++char *loglevel2string(int loglevel) ++{ ++ switch (loglevel) { ++ case S_FILES: ++ return "FILES"; ++ case S_INCLUDE: ++ return "INCLUDE"; ++ case S_MEMORY: ++ return "MEMORY"; ++ case S_MISC: ++ return "MISC"; ++ case S_SQL: ++ return "SQL"; ++ case S_EXECUTOR: ++ return "EXECUTOR"; ++ case S_VARS: ++ return "VARS"; ++ default: ++ return "UNKNOWN"; ++ } ++} ++ ++PHPAPI void php_security_log(int loglevel, char *fmt, ...) ++{ ++#if defined(AF_UNIX) ++ int s, r, i=0; ++ struct sockaddr_un saun; ++ char buf[4096+64]; ++ char error[4096+100]; ++ char *ip_address; ++ char *fname; ++ int lineno; ++ va_list ap; ++ TSRMLS_FETCH(); ++ ++ if (EG(hphp_log_use_x_forwarded_for)) { ++ ip_address = sapi_getenv("HTTP_X_FORWARDED_FOR", 20 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "X-FORWARDED-FOR not set"; ++ } ++ } else { ++ ip_address = sapi_getenv("REMOTE_ADDR", 11 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "REMOTE_ADDR not set"; ++ } ++ } ++ ++ ++ va_start(ap, fmt); ++ ap_php_vsnprintf(error, sizeof(error), fmt, ap); ++ va_end(ap); ++ while (error[i]) { ++ if (error[i] < 32) error[i] = '.'; ++ i++; ++ } ++ ++ if (zend_is_executing(TSRMLS_C)) { ++ lineno = zend_get_executed_lineno(TSRMLS_C); ++ fname = zend_get_executed_filename(TSRMLS_C); ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s', line %u)", error, ip_address, fname, lineno); ++ } else { ++ fname = sapi_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC); ++ if (fname==NULL) { ++ fname = "unknown"; ++ } ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s')", error, ip_address, fname); ++ } ++ ++ /* Syslog-Logging disabled? */ ++ if ((EG(hphp_log_syslog) & loglevel)==0) { ++ goto log_sapi; ++ } ++ ++ ap_php_snprintf(error, sizeof(error), "<%u>hphp[%u]: %s\n", EG(hphp_log_syslog_facility)|EG(hphp_log_syslog_priority),getpid(),buf); ++ ++ s = socket(AF_UNIX, SOCK_DGRAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ s = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ goto log_sapi; ++ } ++ } ++ send(s, error, strlen(error), 0); ++ ++ close(s); ++ ++log_sapi: ++ /* SAPI Logging activated? */ ++ if ((EG(hphp_log_syslog) & loglevel)!=0) { ++ sapi_module.log_message(buf); ++ } ++ ++log_script: ++ /* script logging activaed? */ ++ if (((EG(hphp_log_script) & loglevel)!=0) && EG(hphp_log_scriptname)!=NULL) { ++ char cmd[8192], *cmdpos, *bufpos; ++ FILE *in; ++ int space; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s \'", EG(hphp_log_scriptname), loglevel2string(loglevel)); ++ space = sizeof(cmd) - strlen(cmd); ++ cmdpos = cmd + strlen(cmd); ++ bufpos = buf; ++ if (space <= 1) return; ++ while (space > 2 && *bufpos) { ++ if (*bufpos == '\'') { ++ if (space<=5) break; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\\'; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\''; ++ bufpos++; ++ space-=4; ++ } else { ++ *cmdpos++ = *bufpos++; ++ space--; ++ } ++ } ++ *cmdpos++ = '\''; ++ *cmdpos = 0; ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_INTERNAL, "Unable to execute logging shell script: %s", EG(hphp_log_scriptname)); ++ return; ++ } ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ } ++ pclose(in); ++ } ++ ++#endif ++} ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++PHPAPI unsigned int php_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++ ++PHPAPI int php_is_valid_include(zval *z) ++{ ++ char *filename; ++ int len, i; ++ TSRMLS_FETCH(); ++ ++ /* must be of type string */ ++ if (z->type != IS_STRING || z->value.str.val == NULL) { ++ return (0); ++ } ++ ++ /* short cut */ ++ filename = z->value.str.val; ++ len = z->value.str.len; ++ ++ /* 1. must be shorter than MAXPATHLEN */ ++ if (len > MAXPATHLEN) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') longer than MAXPATHLEN chars", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 2. must not be cutted */ ++ if (len != strlen(filename)) { ++ char *fname = estrndup(filename, len); ++ for (i=0; fname[i]; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename truncated by a \\0 after '%s'", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 3. when it is an URL first check black/whitelist if both are empty disallow all URLs */ ++ if (strstr(filename, "://")) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ ++ /* no black or whitelist then disallow all */ ++ if (HG(include_whitelist)==NULL && HG(include_blacklist)==NULL) { ++ php_security_log(S_INCLUDE, "Include filename ('%s') is an URL", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* whitelist is stronger than blacklist */ ++ if (HG(include_whitelist)) { ++ char *s, *t, *h, *index; ++ uint indexlen; ++ ulong numindex; ++ ++ s = filename; ++ ++ do { ++ zend_bool isOk = 0; ++ int tlen; ++ ++ t = h = strstr(s, "://"); ++ if (h == NULL) break; ++ ++ ++ while (t > s && (isalpha(t[-1]) || t[-1]=='_')) { ++ t--; ++ } ++ ++ tlen = strlen(t); ++ ++ zend_hash_internal_pointer_reset(HG(include_whitelist)); ++ do { ++ int r = zend_hash_get_current_key_ex(HG(include_whitelist), &index, &indexlen, &numindex, 0, NULL); ++ ++ if (r==HASH_KEY_NON_EXISTANT) { ++ break; ++ } ++ if (r==HASH_KEY_IS_STRING) { ++ if (h-t <= indexlen-1 && tlen>=indexlen-1) { ++ if (strncmp(t, index, indexlen-1)==0) { ++ isOk = 1; ++ break; ++ } ++ } ++ } ++ ++ zend_hash_move_forward(HG(include_whitelist)); ++ } while (1); ++ ++ /* not found in whitelist */ ++ if (!isOk) { ++ php_security_log(S_INCLUDE, "Include filename ('%s') is an URL that is not allowed in whitelist", fname); ++ efree(fname); ++ return 0; ++ } ++ ++ s = h + 3; ++ } while (1); ++ } else { ++ /* okay then handle the blacklist */ ++ char *s, *t, *h, *index; ++ uint indexlen; ++ ulong numindex; ++ ++ s = filename; ++ ++ do { ++ int tlen; ++ ++ t = h = strstr(s, "://"); ++ if (h == NULL) break; ++ ++ ++ while (t > s) { ++ if (isalpha(t[-1]) || t[-1]=='_') t--; ++ } ++ ++ tlen = strlen(t); ++ ++ zend_hash_internal_pointer_reset(HG(include_blacklist)); ++ do { ++ int r = zend_hash_get_current_key_ex(HG(include_blacklist), &index, &indexlen, &numindex, 0, NULL); ++ ++ if (r==HASH_KEY_NON_EXISTANT) { ++ break; ++ } ++ if (r==HASH_KEY_IS_STRING) { ++ if (h-t <= indexlen-1 && tlen>=indexlen-1) { ++ if (strncmp(t, index, indexlen-1)==0) { ++ php_security_log(S_INCLUDE, "Include filename ('%s') is an URL that is forbidden by the blacklist", fname); ++ efree(fname); ++ return 0; ++ } ++ } ++ } ++ ++ zend_hash_move_forward(HG(include_blacklist)); ++ } while (1); ++ ++ s = h + 3; ++ } while (1); ++ } ++ ++ efree(fname); ++ } ++ ++ /* 4. must not be an uploaded file */ ++ if (SG(rfc1867_uploaded_files)) { ++ if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, len+1)) { ++ php_security_log(S_INCLUDE, "Include filename is an uploaded file"); ++ return (0); ++ } ++ } ++ ++ /* passed all tests */ ++ return (1); ++} ++ ++#endif ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-4.4.0/main/hardening_patch.h hardening-patch-4.4.0-0.4.3/main/hardening_patch.h +--- php-4.4.0/main/hardening_patch.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/main/hardening_patch.h 2005-09-12 18:15:08.000000000 +0200 +@@ -0,0 +1,46 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENING_PATCH_H ++#define HARDENING_PATCH_H ++ ++#include "zend.h" ++ ++#if HARDENING_PATCH ++PHPAPI void php_security_log(int loglevel, char *fmt, ...); ++PHPAPI void hardened_startup(); ++#define HARDENING_PATCH_VERSION "0.4.3" ++ ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++PHPAPI unsigned int php_canary(); ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++PHPAPI int php_is_valid_include(zval *z); ++#endif ++ ++#endif /* HARDENING_PATCH_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nura php-4.4.0/main/hardening_patch.m4 hardening-patch-4.4.0-0.4.3/main/hardening_patch.m4 +--- php-4.4.0/main/hardening_patch.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/main/hardening_patch.m4 2005-09-11 23:31:08.000000000 +0200 +@@ -0,0 +1,95 @@ ++dnl ++dnl $Id: hardening_patch.m4,v 1.1 2004/11/14 13:24:24 ionic Exp $ ++dnl ++dnl This file contains Hardening Patch for PHP specific autoconf functions. ++dnl ++ ++AC_ARG_ENABLE(hardening-patch-mm-protect, ++[ --disable-hardening-patch-mm-protect Disable the Memory Manager protection.],[ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-ll-protect, ++[ --disable-hardening-patch-ll-protect Disable the Linked List protection.],[ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-inc-protect, ++[ --disable-hardening-patch-inc-protect Disable include/require protection.],[ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-fmt-protect, ++[ --disable-hardening-patch-fmt-protect Disable format string protection.],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-hash-protect, ++[ --disable-hardening-patch-hash-protect Disable HashTable destructor protection.],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++]) ++ ++AC_MSG_CHECKING(whether to protect the Zend Memory Manager) ++AC_MSG_RESULT($DO_HARDENING_PATCH_MM_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the Zend Linked Lists) ++AC_MSG_RESULT($DO_HARDENING_PATCH_LL_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect include/require statements) ++AC_MSG_RESULT($DO_HARDENING_PATCH_INC_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect PHP Format String functions) ++AC_MSG_RESULT($DO_HARDENING_PATCH_FMT_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the destructor of Zend HashTables) ++AC_MSG_RESULT($DO_HARDENING_PATCH_HASH_PROTECT) ++ ++ ++AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 1, [Memory Manager Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 0, [Memory Manager Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 1, [Linked List Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 0, [Linked List Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 1, [Include/Require Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 0, [Include/Require Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 1, [Fmt String Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 0, [Fmt String Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 1, [HashTable DTOR Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 0, [HashTable DTOR Protection]) ++fi ++ +diff -Nura php-4.4.0/main/main.c hardening-patch-4.4.0-0.4.3/main/main.c +--- php-4.4.0/main/main.c 2005-06-20 21:59:43.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/main/main.c 2005-09-11 23:31:08.000000000 +0200 +@@ -100,6 +100,10 @@ + PHPAPI int core_globals_id; + #endif + ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#endif ++ + #define ERROR_BUF_LEN 1024 + + typedef struct { +@@ -150,10 +154,33 @@ + */ + static PHP_INI_MH(OnChangeMemoryLimit) + { ++#if HARDENING_PATCH ++ long orig_memory_limit; ++ ++ if (entry->modified) { ++ orig_memory_limit = zend_atoi(entry->orig_value, entry->orig_value_length); ++ } else { ++ orig_memory_limit = 1<<30; ++ } ++ if (orig_memory_limit < 0 || orig_memory_limit > (1<<30)) { ++ orig_memory_limit = 1<<30; ++ } ++#endif + if (new_value) { + PG(memory_limit) = zend_atoi(new_value, new_value_length); ++#if HARDENING_PATCH ++ if (PG(memory_limit) > orig_memory_limit) { ++ PG(memory_limit) = orig_memory_limit; ++ php_security_log(S_MISC, "script tried to increase memory_limit above allowed value"); ++ return FAILURE; ++ } ++#endif + } else { ++#if HARDENING_PATCH ++ PG(memory_limit) = orig_memory_limit; ++#else + PG(memory_limit) = 1<<30; /* effectively, no limit */ ++#endif + } + return zend_set_memory_limit(PG(memory_limit)); + } +@@ -1096,6 +1123,10 @@ + tsrm_ls = ts_resource(0); + #endif + ++#if HARDENING_PATCH ++ hardened_startup(); ++#endif ++ + sapi_initialize_empty_request(TSRMLS_C); + sapi_activate(TSRMLS_C); + +@@ -1108,6 +1139,12 @@ + php_output_startup(); + php_output_activate(TSRMLS_C); + ++#if HARDENING_PATCH_INC_PROTECT ++ zuf.is_valid_include = php_is_valid_include; ++#endif ++#if HARDENING_PATCH ++ zuf.security_log_function = php_security_log; ++#endif + zuf.error_function = php_error_cb; + zuf.printf_function = php_printf; + zuf.write_function = php_body_write_wrapper; +@@ -1209,6 +1246,10 @@ + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, sizeof(PHP_CONFIG_FILE_PATH)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("HARDENING_PATCH", 1, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_STRINGL_CONSTANT("HARDENING_PATCH_VERSION", HARDENING_PATCH_VERSION, sizeof(HARDENING_PATCH_VERSION)-1, CONST_PERSISTENT | CONST_CS); ++#endif + REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("PHP_INT_MAX", LONG_MAX, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", sizeof(long), CONST_PERSISTENT | CONST_CS); +@@ -1316,7 +1357,7 @@ + */ + static inline void php_register_server_variables(TSRMLS_D) + { +- zval *array_ptr=NULL; ++ zval *array_ptr=NULL, *vptr; + + ALLOC_ZVAL(array_ptr); + array_init(array_ptr); +@@ -1326,6 +1367,16 @@ + /* Server variables */ + if (sapi_module.register_server_variables) { + sapi_module.register_server_variables(array_ptr TSRMLS_CC); ++ if (zend_hash_find(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA"), (void **)&vptr)==SUCCESS) { ++ char *str; ++ if (vptr->type != IS_STRING) { ++ str = "Array"; ++ } else { ++ str = vptr->value.str.val; ++ } ++ php_security_log(S_VARS, "Attacker tried to overwrite HTTP_RAW_POST_DATA with '%s' through a HTTP header", str); ++ zend_hash_del(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA")); ++ } + } + + /* PHP Authentication support */ +diff -Nura php-4.4.0/main/php_config.h.in hardening-patch-4.4.0-0.4.3/main/php_config.h.in +--- php-4.4.0/main/php_config.h.in 2005-07-11 12:07:41.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/main/php_config.h.in 2005-09-11 23:31:08.000000000 +0200 +@@ -860,6 +860,39 @@ + /* Enabling BIND8 compatibility for Panther */ + #undef BIND_8_COMPAT + ++/* Hardening-Patch */ ++#undef HARDENING_PATCH ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ + /* Whether you have AOLserver */ + #undef HAVE_AOLSERVER + +@@ -1143,6 +1176,12 @@ + /* Define if you have the getaddrinfo function */ + #undef HAVE_GETADDRINFO + ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ + /* Whether system headers declare timezone */ + #undef HAVE_DECLARED_TIMEZONE + +diff -Nura php-4.4.0/main/php_content_types.c hardening-patch-4.4.0-0.4.3/main/php_content_types.c +--- php-4.4.0/main/php_content_types.c 2002-12-31 17:26:14.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/main/php_content_types.c 2005-09-11 23:31:08.000000000 +0200 +@@ -77,6 +77,7 @@ + sapi_register_post_entries(php_post_entries); + sapi_register_default_post_reader(php_default_post_reader); + sapi_register_treat_data(php_default_treat_data); ++ sapi_register_input_filter(php_default_input_filter); + return SUCCESS; + } + /* }}} */ +diff -Nura php-4.4.0/main/php.h hardening-patch-4.4.0-0.4.3/main/php.h +--- php-4.4.0/main/php.h 2005-04-17 15:37:29.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/main/php.h 2005-09-11 23:31:08.000000000 +0200 +@@ -35,11 +35,19 @@ + #include "zend_qsort.h" + #include "php_compat.h" + ++ + #include "zend_API.h" + + #undef sprintf + #define sprintf php_sprintf + ++#if HARDENING_PATCH ++#if HAVE_REALPATH ++#undef realpath ++#define realpath php_realpath ++#endif ++#endif ++ + /* PHP's DEBUG value must match Zend's ZEND_DEBUG value */ + #undef PHP_DEBUG + #define PHP_DEBUG ZEND_DEBUG +@@ -435,6 +443,10 @@ + #endif + #endif /* !XtOffsetOf */ + ++#if HARDENING_PATCH ++#include "hardening_patch.h" ++#endif ++ + #endif + + /* +diff -Nura php-4.4.0/main/php_variables.c hardening-patch-4.4.0-0.4.3/main/php_variables.c +--- php-4.4.0/main/php_variables.c 2005-05-17 20:42:35.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/main/php_variables.c 2005-09-11 23:31:08.000000000 +0200 +@@ -225,17 +225,28 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(PARSE_POST, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, "&", &strtok_buf); + } + } + ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter) ++{ ++ /* TODO: check .ini setting here and apply user-defined input filter */ ++ *new_val_len = val_len; ++ return 1; ++} ++ + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data) + { + char *res = NULL, *var, *val, *separator=NULL; +@@ -313,15 +324,26 @@ + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ +- int val_len; ++ unsigned int val_len, new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); +- php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); ++ val = estrndup(val, val_len); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } else { ++ unsigned int val_len, new_val_len; ++ + php_url_decode(var, strlen(var)); +- php_register_variable_safe(var, "", 0, array_ptr TSRMLS_CC); ++ val_len = 0; ++ val = estrndup("", 0); ++ if (sapi_module.input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { ++ php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); ++ } ++ efree(val); + } + var = php_strtok_r(NULL, separator, &strtok_buf); + } +diff -Nura php-4.4.0/main/rfc1867.c hardening-patch-4.4.0-0.4.3/main/rfc1867.c +--- php-4.4.0/main/rfc1867.c 2005-04-04 16:59:58.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/main/rfc1867.c 2005-09-12 18:15:08.000000000 +0200 +@@ -127,6 +127,7 @@ + #define UPLOAD_ERROR_C 3 /* Partially uploaded */ + #define UPLOAD_ERROR_D 4 /* No file uploaded */ + #define UPLOAD_ERROR_E 6 /* Missing /tmp or similar directory */ ++#define UPLOAD_ERROR_F 7 /* Filter forbids upload */ + + void php_rfc1867_register_constants(TSRMLS_D) + { +@@ -136,6 +137,7 @@ + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL", UPLOAD_ERROR_C, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE", UPLOAD_ERROR_D, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FILTER", UPLOAD_ERROR_F, CONST_CS | CONST_PERSISTENT); + } + + static void normalize_protected_variable(char *varname TSRMLS_DC) +@@ -844,6 +846,7 @@ + char buff[FILLUNIT]; + char *cd=NULL,*param=NULL,*filename=NULL, *tmp=NULL; + int blen=0, wlen=0; ++ unsigned long offset; + + zend_llist_clean(&header); + +@@ -891,21 +894,24 @@ + if (!filename && param) { + + char *value = multipart_buffer_read_body(mbuff TSRMLS_CC); ++ unsigned int new_val_len; /* Dummy variable */ + + if (!value) { + value = estrdup(""); + } + ++ if (sapi_module.input_filter(PARSE_POST, param, &value, strlen(value), &new_val_len TSRMLS_CC)) { + #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) +- if (php_mb_encoding_translation(TSRMLS_C)) { +- php_mb_gpc_stack_variable(param, value, &val_list, &len_list, +- &num_vars, &num_vars_max TSRMLS_CC); +- } else { +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); +- } ++ if (php_mb_encoding_translation(TSRMLS_C)) { ++ php_mb_gpc_stack_variable(param, value, &val_list, &len_list, ++ &num_vars, &num_vars_max TSRMLS_CC); ++ } else { ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ } + #else +- safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); ++ safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); + #endif ++ } + if (!strcasecmp(param, "MAX_FILE_SIZE")) { + max_file_size = atol(value); + } +@@ -957,7 +963,11 @@ + tmp++; + } + } +- ++ ++ if (sapi_module.upload_varname_filter && sapi_module.upload_varname_filter(param TSRMLS_CC)==FAILURE) { ++ skip_upload = 1; ++ } ++ + total_bytes = cancel_upload = 0; + + if (!skip_upload) { +@@ -981,6 +991,11 @@ + cancel_upload = UPLOAD_ERROR_D; + } + ++ if (sapi_module.pre_upload_filter && sapi_module.pre_upload_filter(param, filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ ++ offset = 0; + while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff) TSRMLS_CC))) + { + if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize)) { +@@ -990,6 +1005,11 @@ + sapi_module.sapi_error(E_WARNING, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename); + cancel_upload = UPLOAD_ERROR_B; + } else if (blen > 0) { ++ ++ if (sapi_module.upload_content_filter && sapi_module.upload_content_filter(offset, buff, blen, &blen TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ + wlen = write(fd, buff, blen); + + if (wlen < blen) { +@@ -997,6 +1017,7 @@ + cancel_upload = UPLOAD_ERROR_C; + } else { + total_bytes += wlen; ++ offset += wlen; + } + } + } +@@ -1011,6 +1032,10 @@ + } + #endif + ++ if (!cancel_upload && sapi_module.post_upload_filter && sapi_module.post_upload_filter(temp_filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_F; ++ } ++ + if (cancel_upload) { + if (temp_filename) { + if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */ +diff -Nura php-4.4.0/main/SAPI.c hardening-patch-4.4.0-0.4.3/main/SAPI.c +--- php-4.4.0/main/SAPI.c 2005-02-22 15:46:24.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/main/SAPI.c 2005-09-12 18:15:08.000000000 +0200 +@@ -831,6 +831,37 @@ + return SUCCESS; + } + ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) ++{ ++ sapi_module.input_filter = input_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_upload_varname_filter(unsigned int (*upload_varname_filter)(char *varname TSRMLS_DC)) ++{ ++ sapi_module.upload_varname_filter = upload_varname_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)) ++{ ++ sapi_module.pre_upload_filter = pre_upload_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)) ++{ ++ sapi_module.upload_content_filter = upload_content_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)) ++{ ++ sapi_module.post_upload_filter = post_upload_filter; ++ return SUCCESS; ++} ++ ++ + + SAPI_API int sapi_flush(TSRMLS_D) + { +diff -Nura php-4.4.0/main/SAPI.h hardening-patch-4.4.0-0.4.3/main/SAPI.h +--- php-4.4.0/main/SAPI.h 2003-04-09 22:27:55.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/main/SAPI.h 2005-09-12 22:51:45.000000000 +0200 +@@ -101,9 +101,10 @@ + char *current_user; + int current_user_length; + +- /* this is necessary for CLI module */ +- int argc; +- char **argv; ++ /* this is necessary for CLI module */ ++ int argc; ++ char **argv; ++ + } sapi_request_info; + + +@@ -177,6 +178,10 @@ + SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry); + SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D)); + SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC)); ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)); ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)); ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)); ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)); + + SAPI_API int sapi_flush(TSRMLS_D); + SAPI_API struct stat *sapi_get_stat(TSRMLS_D); +@@ -238,8 +243,16 @@ + int (*get_target_uid)(uid_t * TSRMLS_DC); + int (*get_target_gid)(gid_t * TSRMLS_DC); + ++ unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); ++ ++ unsigned int (*upload_varname_filter)(char *varname TSRMLS_DC); ++ unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC); ++ unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC); ++ unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC); ++ + void (*ini_defaults)(HashTable *configuration_hash); + int phpinfo_as_text; ++ + }; + + +@@ -262,16 +275,27 @@ + + #define SAPI_DEFAULT_MIMETYPE "text/html" + #define SAPI_DEFAULT_CHARSET "" ++ ++#if HARDENING_PATCH ++#define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION " with Hardening-Patch" ++#else + #define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION ++#endif + + #define SAPI_POST_READER_FUNC(post_reader) void post_reader(TSRMLS_D) + #define SAPI_POST_HANDLER_FUNC(post_handler) void post_handler(char *content_type_dup, void *arg TSRMLS_DC) + + #define SAPI_TREAT_DATA_FUNC(treat_data) void treat_data(int arg, char *str, zval* destArray TSRMLS_DC) ++#define SAPI_INPUT_FILTER_FUNC(input_filter) unsigned int input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) ++#define SAPI_UPLOAD_VARNAME_FILTER_FUNC(upload_varname_filter) unsigned int upload_varname_filter(char *varname TSRMLS_DC) ++#define SAPI_PRE_UPLOAD_FILTER_FUNC(pre_upload_filter) unsigned int pre_upload_filter(char *varname, char *filename TSRMLS_DC) ++#define SAPI_UPLOAD_CONTENT_FILTER_FUNC(upload_content_filter) unsigned int upload_content_filter(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC) ++#define SAPI_POST_UPLOAD_FILTER_FUNC(post_upload_filter) unsigned int post_upload_filter(char *tmpfilename TSRMLS_DC) + + SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data); + SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader); + SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data); ++SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter); + + #define STANDARD_SAPI_MODULE_PROPERTIES + +diff -Nura php-4.4.0/main/snprintf.c hardening-patch-4.4.0-0.4.3/main/snprintf.c +--- php-4.4.0/main/snprintf.c 2005-04-08 07:44:53.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/main/snprintf.c 2005-09-11 23:31:08.000000000 +0200 +@@ -1013,7 +1013,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Nura php-4.4.0/main/spprintf.c hardening-patch-4.4.0-0.4.3/main/spprintf.c +--- php-4.4.0/main/spprintf.c 2005-04-08 07:44:53.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/main/spprintf.c 2005-09-11 23:31:08.000000000 +0200 +@@ -630,7 +630,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = xbuf->len; ++#endif + break; + + /* +diff -Nura php-4.4.0/pear/go-pear-list.php hardening-patch-4.4.0-0.4.3/pear/go-pear-list.php +--- php-4.4.0/pear/go-pear-list.php 2005-07-01 11:41:04.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/pear/go-pear-list.php 2005-09-11 23:31:08.000000000 +0200 +@@ -8,7 +8,7 @@ + $packages = array( + // required packages for the installer + "PEAR" => "1.3.5", +-"XML_RPC" => "1.3.1", ++"XML_RPC" => "1.4.0", + "Console_Getopt" => "1.2", + "Archive_Tar" => "1.3.1", + +diff -Nura php-4.4.0/pear/packages/XML_RPC-1.3.1.tar hardening-patch-4.4.0-0.4.3/pear/packages/XML_RPC-1.3.1.tar +--- php-4.4.0/pear/packages/XML_RPC-1.3.1.tar 2005-07-01 11:42:14.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/pear/packages/XML_RPC-1.3.1.tar 1970-01-01 01:00:00.000000000 +0100 +@@ -1,3733 +0,0 @@ +-package2.xml100644 1750 144 32557 10260516576 6517 +- +- XML_RPC +- pear.php.net +- PHP implementation of the XML-RPC protocol +- A PEAR-ified version of Useful Inc's XML-RPC for PHP. +- +-It has support for HTTP/HTTPS transport, proxies and authentication. +- +- Stig Bakken +- ssb +- stig@php.net +- no +- +- +- Daniel Convissor +- danielc +- danielc@php.net +- yes +- +- 2005-06-29 +- +- +- 1.3.1 +- 1.3.0 +- +- +- stable +- stable +- +- PHP License +- * Security fix. Update highly recommended! +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- PEAR +- pear.php.net +- 1.4.0a1 +- 1.4.0a12 +- +- +- +- +- 4.2.0 +- 6.0.0 +- +- +- 1.4.0a1 +- +- +- +- +- +- +- +- 1.3.0RC3 +- 1.3.0 +- +- +- beta +- stable +- +- 2005-05-10 +- PHP License +- * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. +-* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. +-* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. +-* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. +-* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). +-* Use <br /> instead of <br> in XML_RPC_Value::dump(). +- +- +- +- 1.3.0RC2 +- 1.3.0 +- +- +- beta +- beta +- +- 2005-05-05 +- PHP License +- * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. +-* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. +-* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. +-* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. +- +- +- +- 1.3.0RC1 +- 1.3.0 +- +- +- beta +- beta +- +- 2005-04-07 +- PHP License +- * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. +-* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. +-* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. +-* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. +-* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. +-* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. +- +- +- +- 1.2.2 +- 1.2.0 +- +- +- stable +- stable +- +- 2005-03-07 +- PHP License +- * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. +- +- +- +- 1.2.1 +- 1.2.0 +- +- +- stable +- stable +- +- 2005-03-01 +- PHP License +- * Add isset() check before examining the dispatch map. Bug 3658. +- +- +- +- 1.2.0 +- 1.2.0 +- +- +- stable +- stable +- +- 2005-02-27 +- PHP License +- * Provide the "stable" release. +-* Add package2.xml for compatibility with PEAR 1.4.0. +-* For changes since 1.1.0, see the changelogs for the various RC releases. +- +- +- +- 1.2.0RC7 +- 1.2.0RC7 +- +- +- beta +- beta +- +- 2005-02-22 +- PHP License +- * Add the setSendEncoding() method and $send_encoding +- property to XML_RPC_Message. Request 3537. +-* Allow class methods to be mapped using either syntax: +- 'function' => 'hello::sayHello', +- or +- 'function' => array('hello', 'sayhello'), +- Bug 3363. +-* Use 8192 instead of 32768 for bytes in fread() +- in parseResponseFile(). Bug 3340. +- +- +- +- 1.2.0RC6 +- 1.2.0RC6 +- +- +- beta +- beta +- +- 2005-01-25 +- PHP License +- * Don't put the protocol in the Host field of the POST data. (danielc) +- +- +- +- 1.2.0RC5 +- 1.2.0RC5 +- +- +- beta +- beta +- +- 2005-01-24 +- PHP License +- * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. +- +- +- +- 1.2.0RC4 +- 1.2.0RC4 +- +- +- beta +- beta +- +- 2005-01-24 +- PHP License +- * When a connection attempt fails, have the method return 0. (danielc) +-* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) +-* Add tests for setting the client properties. (danielc) +-* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) +-* Bundle the tests with the package. (danielc) +- +- +- +- 1.2.0RC3 +- 1.2.0RC3 +- +- +- beta +- beta +- +- 2005-01-19 +- PHP License +- * ssl uses port 443, not 445. +- +- +- +- 1.2.0RC2 +- 1.2.0RC2 +- +- +- beta +- beta +- +- 2005-01-11 +- PHP License +- * Handle ssl:// in the $server string. (danielc) +-* Also default to port 445 for ssl:// requests as well. (danielc) +-* Enhance debugging in the server. (danielc) +- +- +- +- 1.2.0RC1 +- 1.2.0RC1 +- +- +- beta +- beta +- +- 2004-12-30 +- PHP License +- * Make things work with SSL. Bug 2489. (nkukard lbsd net) +-* Allow array function callbacks (Matt Kane) +-* Some minor speed-ups (Matt Kane) +-* Add Dump.php to the package (Christian Weiske) +-* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) +-* Silence fsockopen() errors. Bug 1714. (danielc) +-* Encode empty arrays as an array. Bug 1493. (danielc) +-* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) +-* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) +-* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) +-* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) +-* Allow raiseError() to be called statically. (danielc) +-* Stop double escaping of character entities. Bug 987. (danielc) +- NOTICE: the following have been removed: +- * XML_RPC_dh() +- * $GLOBALS['XML_RPC_entities'] +- * XML_RPC_entity_decode() +- * XML_RPC_lookup_entity() +-* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) +- +- +- +- 1.1.0 +- 1.1.0 +- +- +- stable +- stable +- +- 2004-03-15 +- PHP License +- * Added support for sequential arrays to XML_RPC_encode() (mroch) +-* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) +-* Remove "require_once 'PEAR.php'", include only when needed to raise an error +-* Replace echo and error_log() with raiseError() (mroch) +-* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) +-* be tolerant of junk after methodResponse (Luca Mariano, mroch) +-* Silent notice even in the error log (pierre) +-* fix include of shared xml extension on win32 (pierre) +- +- +- +- 1.0.4 +- 1.0.4 +- +- +- stable +- stable +- +- 2002-10-02 +- PHP License +- * added HTTP proxy authorization support (thanks to Arnaud Limbourg) +- +- +- +- 1.0.3 +- 1.0.3 +- +- +- stable +- stable +- +- 2002-05-19 +- PHP License +- * fix bug when parsing responses with boolean types +- +- +- +- 1.0.2 +- 1.0.2 +- +- +- stable +- stable +- +- 2002-04-16 +- PHP License +- * E_ALL fixes +-* fix HTTP response header parsing +- +- +- +- 1.0.1 +- 1.0.1 +- +- +- stable +- stable +- +- 2001-09-25 +- PHP License +- This is a PEAR-ified version of Useful Inc's 1.0.1 release. +-Includes an urgent security fix identified by Dan Libby <dan@libby.com>. +- +- +- +-XML_RPC-1.3.1/tests/protoport.php100644 1750 144 25543 10260516576 12042 +- * @copyright 2005 The PHP Group +- * @license http://www.php.net/license/3_0.txt PHP License +- * @version CVS: $Id: protoport.php,v 1.4 2005/01/24 17:48:47 danielc Exp $ +- * @link http://pear.php.net/package/XML_RPC +- * @since File available since Release 1.2 +- */ +- +-/* +- * If the package version number is found in the left hand +- * portion of the if() expression below, that means this file has +- * come from the PEAR installer. Therefore, let's test the +- * installed version of XML_RPC which should be in the include path. +- * +- * If the version has not been substituted in the if() expression, +- * this file has likely come from a CVS checkout or a .tar file. +- * Therefore, we'll assume the tests should use the version of +- * XML_RPC that has come from there as well. +- */ +-if ('1.3.1' != '@'.'package_version'.'@') { +- /** +- * Get the needed class from the PEAR installation +- */ +- require_once 'XML/RPC.php'; +-} else { +- /** +- * Get the needed class from the parent directory +- */ +- require_once '../RPC.php'; +-} +- +-/** +- * Compare the test result to the expected result +- * +- * If the test fails, echo out the results. +- * +- * @param array $expect the array of object properties you expect +- * from the test +- * @param object $actual the object results from the test +- * @param string $test_name the name of the test +- * +- * @return void +- */ +-function compare($expect, $actual, $test_name) { +- $actual = get_object_vars($actual); +- if (count(array_diff($actual, $expect))) { +- echo "$test_name failed.\nExpect: "; +- print_r($expect); +- echo "Actual: "; +- print_r($actual); +- echo "\n"; +- } +-} +- +-if (php_sapi_name() != 'cli') { +- echo "
\n";
+-}
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver');
+-compare($x, $c, 'defaults');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver');
+-compare($x, $c, 'defaults with http');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver');
+-compare($x, $c, 'defaults with https');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver');
+-compare($x, $c, 'defaults with ssl');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 65);
+-compare($x, $c, 'port 65');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 65);
+-compare($x, $c, 'port 65 with http');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 65);
+-compare($x, $c, 'port 65 with https');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => '',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65);
+-compare($x, $c, 'port 65 with ssl');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 0,
+-                        'theproxy');
+-compare($x, $c, 'defaults proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 8080,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 0,
+-                        'http://theproxy');
+-compare($x, $c, 'defaults with http proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 0,
+-                        'https://theproxy');
+-compare($x, $c, 'defaults with https proxy');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 0,
+-                        'ssl://theproxy');
+-compare($x, $c, 'defaults with ssl proxy');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 65,
+-                        'theproxy', 6565);
+-compare($x, $c, 'port 65 proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'http://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'http://theserver', 65,
+-                        'http://theproxy', 6565);
+-compare($x, $c, 'port 65 with http proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'https://theserver', 65,
+-                        'https://theproxy', 6565);
+-compare($x, $c, 'port 65 with https proxy 6565');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 65,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65,
+-                        'ssl://theproxy', 6565);
+-compare($x, $c, 'port 65 with ssl proxy 6565');
+-
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'ssl://',
+-    'port' => 443,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 443,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 443,
+-                        'theproxy', 443);
+-compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
+-
+-$x = array(
+-    'path' => 'thepath',
+-    'server' => 'theserver',
+-    'protocol' => 'http://',
+-    'port' => 80,
+-    'proxy' => 'theproxy',
+-    'proxy_protocol' => 'ssl://',
+-    'proxy_port' => 6565,
+-    'proxy_user' => '',
+-    'proxy_pass' => '',
+-    'errno' => 0,
+-    'errstring' => '',
+-    'debug' => 0,
+-    'username' => '',
+-    'password' => '',
+-);
+-$c = new XML_RPC_Client('thepath', 'theserver', 0,
+-                        'ssl://theproxy', 6565);
+-compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
+-XML_RPC-1.3.1/tests/test_Dump.php100644   1750    144        3042 10260516576  11704 new XML_RPC_Value('das ist der Titel', 'string'),
+-    'startDate'=>new XML_RPC_Value(mktime(0,0,0,13,11,2004), 'dateTime.iso8601'),
+-    'endDate'  =>new XML_RPC_Value(mktime(0,0,0,15,11,2004), 'dateTime.iso8601'),
+-    'error'    =>'string',
+-    'arkey'    => new XML_RPC_Value( array(
+-        new XML_RPC_Value('simple string'),
+-        new XML_RPC_Value(12345, 'int')
+-        ), 'array')
+-    )
+-    ,'struct');
+-
+-XML_RPC_Dump($val);
+-
+-echo '==============' . "\r\n";
+-$val2 = new XML_RPC_Value(44353, 'int');
+-XML_RPC_Dump($val2);
+-
+-echo '==============' . "\r\n";
+-$val3 = new XML_RPC_Value('this should be a string', 'string');
+-XML_RPC_Dump($val3);
+-
+-echo '==============' . "\r\n";
+-$val4 = new XML_RPC_Value(true, 'boolean');
+-XML_RPC_Dump($val4);
+-XML_RPC-1.3.1/Dump.php100644   1750    144       12074 10260516576   7530 
+- * @version    CVS: $Id: Dump.php,v 1.7 2005/01/24 03:47:55 danielc Exp $
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-
+-
+-/**
+- * Pull in the XML_RPC class
+- */
+-require_once 'XML/RPC.php';
+-
+-
+-/**
+- * Generates the dump of the XML_RPC_Value and echoes it
+- *
+- * @param object $value  the XML_RPC_Value object to dump
+- *
+- * @return void
+- */
+-function XML_RPC_Dump($value)
+-{
+-    $dumper = new XML_RPC_Dump();
+-    echo $dumper->generateDump($value);
+-}
+-
+-
+-/**
+- * Class which generates a dump of a XML_RPC_Value object
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Christian Weiske 
+- * @version    Release: 1.3.1
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Dump
+-{
+-    /**
+-     * The indentation array cache
+-     * @var array
+-     */
+-    var $arIndent      = array();
+-
+-    /**
+-     * The spaces used for indenting the XML
+-     * @var string
+-     */
+-    var $strBaseIndent = '    ';
+-
+-    /**
+-     * Returns the dump in XML format without printing it out
+-     *
+-     * @param object $value   the XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  the dump
+-     */
+-    function generateDump($value, $nLevel = 0)
+-    {
+-        if (!is_object($value) && get_class($value) != 'xml_rpc_value') {
+-            require_once 'PEAR.php';
+-            PEAR::raiseError('Tried to dump non-XML_RPC_Value variable' . "\r\n",
+-                             0, PEAR_ERROR_PRINT);
+-            if (is_object($value)) {
+-                $strType = get_class($value);
+-            } else {
+-                $strType = gettype($value);
+-            }
+-            return $this->getIndent($nLevel) . 'NOT A XML_RPC_Value: '
+-                   . $strType . "\r\n";
+-        }
+-
+-        switch ($value->kindOf()) {
+-        case 'struct':
+-            $ret = $this->genStruct($value, $nLevel);
+-            break;
+-        case 'array':
+-            $ret = $this->genArray($value, $nLevel);
+-            break;
+-        case 'scalar':
+-            $ret = $this->genScalar($value->scalarval(), $nLevel);
+-            break;
+-        default:
+-            require_once 'PEAR.php';
+-            PEAR::raiseError('Illegal type "' . $value->kindOf()
+-                             . '" in XML_RPC_Value' . "\r\n", 0,
+-                             PEAR_ERROR_PRINT);
+-        }
+-
+-        return $ret;
+-    }
+-
+-    /**
+-     * Returns the scalar value dump
+-     *
+-     * @param object $value   the scalar XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genScalar($value, $nLevel)
+-    {
+-        if (gettype($value) == 'object') {
+-            $strClass = ' ' . get_class($value);
+-        } else {
+-            $strClass = '';
+-        }
+-        return $this->getIndent($nLevel) . gettype($value) . $strClass
+-               . ' ' . $value . "\r\n";
+-    }
+-
+-    /**
+-     * Returns the dump of a struct
+-     *
+-     * @param object $value   the struct XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genStruct($value, $nLevel)
+-    {
+-        $value->structreset();
+-        $strOutput = $this->getIndent($nLevel) . 'struct' . "\r\n";
+-        while (list($key, $keyval) = $value->structeach()) {
+-            $strOutput .= $this->getIndent($nLevel + 1) . $key . "\r\n";
+-            $strOutput .= $this->generateDump($keyval, $nLevel + 2);
+-        }
+-        return $strOutput;
+-    }
+-
+-    /**
+-     * Returns the dump of an array
+-     *
+-     * @param object $value   the array XML_RPC_Value object to dump
+-     * @param int    $nLevel  the level of indentation
+-     *
+-     * @return string  Dumped version of the scalar value
+-     */
+-    function genArray($value, $nLevel)
+-    {
+-        $nSize     = $value->arraysize();
+-        $strOutput = $this->getIndent($nLevel) . 'array' . "\r\n";
+-        for($nA = 0; $nA < $nSize; $nA++) {
+-            $strOutput .= $this->getIndent($nLevel + 1) . $nA . "\r\n";
+-            $strOutput .= $this->generateDump($value->arraymem($nA),
+-                                              $nLevel + 2);
+-        }
+-        return $strOutput;
+-    }
+-
+-    /**
+-     * Returns the indent for a specific level and caches it for faster use
+-     *
+-     * @param int $nLevel  the level
+-     *
+-     * @return string  the indented string
+-     */
+-    function getIndent($nLevel)
+-    {
+-        if (!isset($this->arIndent[$nLevel])) {
+-            $this->arIndent[$nLevel] = str_repeat($this->strBaseIndent, $nLevel);
+-        }
+-        return $this->arIndent[$nLevel];
+-    }
+-}
+-
+-/*
+- * Local variables:
+- * tab-width: 4
+- * c-basic-offset: 4
+- * c-hanging-comment-ender-p: nil
+- * End:
+- */
+-
+-?>
+-XML_RPC-1.3.1/RPC.php100644   1750    144      150065 10260516576   7272 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
+- * @version    CVS: $Id: RPC.php,v 1.74 2005/05/09 20:51:54 danielc Exp $
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-
+-
+-if (!function_exists('xml_parser_create')) {
+-    PEAR::loadExtension('xml');
+-}
+-
+-/**#@+
+- * Error constants
+- */
+-/**
+- * Parameter values don't match parameter types
+- */
+-define('XML_RPC_ERROR_INVALID_TYPE', 101);
+-/**
+- * Parameter declared to be numeric but the values are not
+- */
+-define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102);
+-/**
+- * Communication error
+- */
+-define('XML_RPC_ERROR_CONNECTION_FAILED', 103);
+-/**
+- * The array or struct has already been started
+- */
+-define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
+-/**
+- * Incorrect parameters submitted
+- */
+-define('XML_RPC_ERROR_INCORRECT_PARAMS', 105);
+-/**
+- * Programming error by developer
+- */
+-define('XML_RPC_ERROR_PROGRAMMING', 106);
+-/**#@-*/
+-
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_I4']
+- */
+-$GLOBALS['XML_RPC_I4'] = 'i4';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Int']
+- */
+-$GLOBALS['XML_RPC_Int'] = 'int';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Boolean']
+- */
+-$GLOBALS['XML_RPC_Boolean'] = 'boolean';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Double']
+- */
+-$GLOBALS['XML_RPC_Double'] = 'double';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_String']
+- */
+-$GLOBALS['XML_RPC_String'] = 'string';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_DateTime']
+- */
+-$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Base64']
+- */
+-$GLOBALS['XML_RPC_Base64'] = 'base64';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Array']
+- */
+-$GLOBALS['XML_RPC_Array'] = 'array';
+-
+-/**
+- * Data types
+- * @global string $GLOBALS['XML_RPC_Struct']
+- */
+-$GLOBALS['XML_RPC_Struct'] = 'struct';
+-
+-
+-/**
+- * Data type meta-types
+- * @global array $GLOBALS['XML_RPC_Types']
+- */
+-$GLOBALS['XML_RPC_Types'] = array(
+-    $GLOBALS['XML_RPC_I4']       => 1,
+-    $GLOBALS['XML_RPC_Int']      => 1,
+-    $GLOBALS['XML_RPC_Boolean']  => 1,
+-    $GLOBALS['XML_RPC_String']   => 1,
+-    $GLOBALS['XML_RPC_Double']   => 1,
+-    $GLOBALS['XML_RPC_DateTime'] => 1,
+-    $GLOBALS['XML_RPC_Base64']   => 1,
+-    $GLOBALS['XML_RPC_Array']    => 2,
+-    $GLOBALS['XML_RPC_Struct']   => 3,
+-);
+-
+-
+-/**
+- * Error message numbers
+- * @global array $GLOBALS['XML_RPC_err']
+- */
+-$GLOBALS['XML_RPC_err'] = array(
+-    'unknown_method'      => 1,
+-    'invalid_return'      => 2,
+-    'incorrect_params'    => 3,
+-    'introspect_unknown'  => 4,
+-    'http_error'          => 5,
+-    'not_response_object' => 6,
+-);
+-
+-/**
+- * Error message strings
+- * @global array $GLOBALS['XML_RPC_str']
+- */
+-$GLOBALS['XML_RPC_str'] = array(
+-    'unknown_method'      => 'Unknown method',
+-    'invalid_return'      => 'Invalid return payload: enable debugging to examine incoming payload',
+-    'incorrect_params'    => 'Incorrect parameters passed to method',
+-    'introspect_unknown'  => 'Can\'t introspect: method unknown',
+-    'http_error'          => 'Didn\'t receive 200 OK from remote server.',
+-    'not_response_object' => 'The requested method didn\'t return an XML_RPC_Response object.',
+-);
+-
+-
+-/**
+- * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
+- * @global string $GLOBALS['XML_RPC_defencoding']
+- */
+-$GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
+-
+-/**
+- * User error codes start at 800
+- * @global int $GLOBALS['XML_RPC_erruser']
+- */
+-$GLOBALS['XML_RPC_erruser'] = 800;
+-
+-/**
+- * XML parse error codes start at 100
+- * @global int $GLOBALS['XML_RPC_errxml']
+- */
+-$GLOBALS['XML_RPC_errxml'] = 100;
+-
+-
+-/**
+- * Compose backslashes for escaping regexp
+- * @global string $GLOBALS['XML_RPC_backslash']
+- */
+-$GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
+-
+-
+-/**
+- * Stores state during parsing
+- *
+- * quick explanation of components:
+- *   + st     = builds up a string for evaluation
+- *   + ac     = accumulates values
+- *   + qt     = decides if quotes are needed for evaluation
+- *   + cm     = denotes struct or array (comma needed)
+- *   + isf    = indicates a fault
+- *   + lv     = indicates "looking for a value": implements the logic
+- *               to allow values with no types to be strings
+- *   + params = stores parameters in method calls
+- *   + method = stores method name
+- *
+- * @global array $GLOBALS['XML_RPC_xh']
+- */
+-$GLOBALS['XML_RPC_xh'] = array();
+-
+-
+-/**
+- * Start element handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_se($parser_resource, $name, $attrs)
+-{
+-    global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String;
+-    $parser = (int) $parser_resource;
+-
+-    switch ($name) {
+-    case 'STRUCT':
+-    case 'ARRAY':
+-        $XML_RPC_xh[$parser]['st'] .= 'array(';
+-        $XML_RPC_xh[$parser]['cm']++;
+-        // this last line turns quoting off
+-        // this means if we get an empty array we'll
+-        // simply get a bit of whitespace in the eval
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'NAME':
+-        $XML_RPC_xh[$parser]['st'] .= '"';
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        break;
+-
+-    case 'FAULT':
+-        $XML_RPC_xh[$parser]['isf'] = 1;
+-        break;
+-
+-    case 'PARAM':
+-        $XML_RPC_xh[$parser]['st'] = '';
+-        break;
+-
+-    case 'VALUE':
+-        $XML_RPC_xh[$parser]['st'] .= 'new XML_RPC_Value(';
+-        $XML_RPC_xh[$parser]['lv'] = 1;
+-        $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        // look for a value: if this is still 1 by the
+-        // time we reach the first data segment then the type is string
+-        // by implication and we need to add in a quote
+-        break;
+-
+-    case 'I4':
+-    case 'INT':
+-    case 'STRING':
+-    case 'BOOLEAN':
+-    case 'DOUBLE':
+-    case 'DATETIME.ISO8601':
+-    case 'BASE64':
+-        $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
+-
+-        if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
+-            $XML_RPC_xh[$parser]['qt'] = 1;
+-
+-            if ($name == 'DATETIME.ISO8601') {
+-                $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
+-            }
+-
+-        } elseif ($name == 'BASE64') {
+-            $XML_RPC_xh[$parser]['qt'] = 2;
+-        } else {
+-            // No quoting is required here -- but
+-            // at the end of the element we must check
+-            // for data format errors.
+-            $XML_RPC_xh[$parser]['qt'] = 0;
+-        }
+-        break;
+-
+-    case 'MEMBER':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-    }
+-
+-    if ($name != 'VALUE') {
+-        $XML_RPC_xh[$parser]['lv'] = 0;
+-    }
+-}
+-
+-/**
+- * End element handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_ee($parser_resource, $name)
+-{
+-    global $XML_RPC_xh, $XML_RPC_Types, $XML_RPC_String;
+-    $parser = (int) $parser_resource;
+-
+-    switch ($name) {
+-    case 'STRUCT':
+-    case 'ARRAY':
+-        if ($XML_RPC_xh[$parser]['cm']
+-            && substr($XML_RPC_xh[$parser]['st'], -1) == ',')
+-        {
+-            $XML_RPC_xh[$parser]['st'] = substr($XML_RPC_xh[$parser]['st'], 0, -1);
+-        }
+-
+-        $XML_RPC_xh[$parser]['st'] .= ')';
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-        $XML_RPC_xh[$parser]['cm']--;
+-        break;
+-
+-    case 'NAME':
+-        $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'] . '" => ';
+-        break;
+-
+-    case 'BOOLEAN':
+-        // special case here: we translate boolean 1 or 0 into PHP
+-        // constants true or false
+-        if ($XML_RPC_xh[$parser]['ac'] == '1') {
+-            $XML_RPC_xh[$parser]['ac'] = 'true';
+-        } else {
+-            $XML_RPC_xh[$parser]['ac'] = 'false';
+-        }
+-
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-        // Drop through intentionally.
+-
+-    case 'I4':
+-    case 'INT':
+-    case 'STRING':
+-    case 'DOUBLE':
+-    case 'DATETIME.ISO8601':
+-    case 'BASE64':
+-        if ($XML_RPC_xh[$parser]['qt'] == 1) {
+-            // we use double quotes rather than single so backslashification works OK
+-            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
+-        } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
+-            $XML_RPC_xh[$parser]['st'] .= 'base64_decode("'
+-                                        . $XML_RPC_xh[$parser]['ac'] . '")';
+-        } elseif ($name == 'BOOLEAN') {
+-            $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
+-        } else {
+-            // we have an I4, INT or a DOUBLE
+-            // we must check that only 0123456789-. are characters here
+-            if (!ereg("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
+-                XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
+-                                         XML_RPC_ERROR_NON_NUMERIC_FOUND);
+-                $XML_RPC_xh[$parser]['st'] .= 'XML_RPC_ERROR_NON_NUMERIC_FOUND';
+-            } else {
+-                // it's ok, add it on
+-                $XML_RPC_xh[$parser]['st'] .= $XML_RPC_xh[$parser]['ac'];
+-            }
+-        }
+-
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
+-        break;
+-
+-    case 'VALUE':
+-        // deal with a string value
+-        if (strlen($XML_RPC_xh[$parser]['ac']) > 0 &&
+-            $XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
+-
+-            $XML_RPC_xh[$parser]['st'] .= '"' . $XML_RPC_xh[$parser]['ac'] . '"';
+-        }
+-
+-        // This if () detects if no scalar was inside 
+-        // and pads an empty "".
+-        if ($XML_RPC_xh[$parser]['st'][strlen($XML_RPC_xh[$parser]['st'])-1] == '(') {
+-            $XML_RPC_xh[$parser]['st'] .= '""';
+-        }
+-        $XML_RPC_xh[$parser]['st'] .= ", '" . $XML_RPC_xh[$parser]['vt'] . "')";
+-        if ($XML_RPC_xh[$parser]['cm']) {
+-            $XML_RPC_xh[$parser]['st'] .= ',';
+-        }
+-        break;
+-
+-    case 'MEMBER':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'DATA':
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = 0;
+-        break;
+-
+-    case 'PARAM':
+-        $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['st'];
+-        break;
+-
+-    case 'METHODNAME':
+-    case 'RPCMETHODNAME':
+-        $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", '',
+-                                                      $XML_RPC_xh[$parser]['ac']);
+-        break;
+-    }
+-
+-    // if it's a valid type name, set the type
+-    if (isset($XML_RPC_Types[strtolower($name)])) {
+-        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
+-    }
+-}
+-
+-/**
+- * Character data handler for the XML parser
+- *
+- * @return void
+- */
+-function XML_RPC_cd($parser_resource, $data)
+-{
+-    global $XML_RPC_xh, $XML_RPC_backslash;
+-    $parser = (int) $parser_resource;
+-
+-    if ($XML_RPC_xh[$parser]['lv'] != 3) {
+-        // "lookforvalue==3" means that we've found an entire value
+-        // and should discard any further character data
+-
+-        if ($XML_RPC_xh[$parser]['lv'] == 1) {
+-            // if we've found text and we're just in a  then
+-            // turn quoting on, as this will be a string
+-            $XML_RPC_xh[$parser]['qt'] = 1;
+-            // and say we've found a value
+-            $XML_RPC_xh[$parser]['lv'] = 2;
+-        }
+-
+-        // replace characters that eval would
+-        // do special things with
+-        if (!isset($XML_RPC_xh[$parser]['ac'])) {
+-            $XML_RPC_xh[$parser]['ac'] = '';
+-        }
+-        $XML_RPC_xh[$parser]['ac'] .= str_replace('$', '\$',
+-            str_replace('"', '\"', str_replace(chr(92),
+-            $XML_RPC_backslash, $data)));
+-    }
+-}
+-
+-/**
+- * The common methods and properties for all of the XML_RPC classes
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
+- * @version    Release: 1.3.1
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Base {
+-
+-    /**
+-     * PEAR Error handling
+-     *
+-     * @return object  PEAR_Error object
+-     */
+-    function raiseError($msg, $code)
+-    {
+-        include_once 'PEAR.php';
+-        if (is_object(@$this)) {
+-            return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
+-        } else {
+-            return PEAR::raiseError('XML_RPC: ' . $msg, $code);
+-        }
+-    }
+-
+-    /**
+-     * Tell whether something is a PEAR_Error object
+-     *
+-     * @param mixed $value  the item to check
+-     *
+-     * @return bool  whether $value is a PEAR_Error object or not
+-     *
+-     * @access public
+-     */
+-    function isError($value)
+-    {
+-        return is_a($value, 'PEAR_Error');
+-    }
+-}
+-
+-/**
+- * The methods and properties for submitting XML RPC requests
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
+- * @version    Release: 1.3.1
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Client extends XML_RPC_Base {
+-
+-    /**
+-     * The path and name of the RPC server script you want the request to go to
+-     * @var string
+-     */
+-    var $path = '';
+-
+-    /**
+-     * The name of the remote server to connect to
+-     * @var string
+-     */
+-    var $server = '';
+-
+-    /**
+-     * The protocol to use in contacting the remote server
+-     * @var string
+-     */
+-    var $protocol = 'http://';
+-
+-    /**
+-     * The port for connecting to the remote server
+-     *
+-     * The default is 80 for http:// connections
+-     * and 443 for https:// and ssl:// connections.
+-     *
+-     * @var integer
+-     */
+-    var $port = 80;
+-
+-    /**
+-     * A user name for accessing the RPC server
+-     * @var string
+-     * @see XML_RPC_Client::setCredentials()
+-     */
+-    var $username = '';
+-
+-    /**
+-     * A password for accessing the RPC server
+-     * @var string
+-     * @see XML_RPC_Client::setCredentials()
+-     */
+-    var $password = '';
+-
+-    /**
+-     * The name of the proxy server to use, if any
+-     * @var string
+-     */
+-    var $proxy = '';
+-
+-    /**
+-     * The protocol to use in contacting the proxy server, if any
+-     * @var string
+-     */
+-    var $proxy_protocol = 'http://';
+-
+-    /**
+-     * The port for connecting to the proxy server
+-     *
+-     * The default is 8080 for http:// connections
+-     * and 443 for https:// and ssl:// connections.
+-     *
+-     * @var integer
+-     */
+-    var $proxy_port = 8080;
+-
+-    /**
+-     * A user name for accessing the proxy server
+-     * @var string
+-     */
+-    var $proxy_user = '';
+-
+-    /**
+-     * A password for accessing the proxy server
+-     * @var string
+-     */
+-    var $proxy_pass = '';
+-
+-    /**
+-     * The error number, if any
+-     * @var integer
+-     */
+-    var $errno = 0;
+-
+-    /**
+-     * The error message, if any
+-     * @var string
+-     */
+-    var $errstring = '';
+-
+-    /**
+-     * The current debug mode (1 = on, 0 = off)
+-     * @var integer
+-     */
+-    var $debug = 0;
+-
+-    /**
+-     * The HTTP headers for the current request.
+-     * @var string
+-     */
+-    var $headers = '';
+-
+-
+-    /**
+-     * Sets the object's properties
+-     *
+-     * @param string  $path        the path and name of the RPC server script
+-     *                              you want the request to go to
+-     * @param string  $server      the URL of the remote server to connect to.
+-     *                              If this parameter doesn't specify a
+-     *                              protocol and $port is 443, ssl:// is
+-     *                              assumed.
+-     * @param integer $port        a port for connecting to the remote server.
+-     *                              Defaults to 80 for http:// connections and
+-     *                              443 for https:// and ssl:// connections.
+-     * @param string  $proxy       the URL of the proxy server to use, if any.
+-     *                              If this parameter doesn't specify a
+-     *                              protocol and $port is 443, ssl:// is
+-     *                              assumed.
+-     * @param integer $proxy_port  a port for connecting to the remote server.
+-     *                              Defaults to 8080 for http:// connections and
+-     *                              443 for https:// and ssl:// connections.
+-     * @param string  $proxy_user  a user name for accessing the proxy server
+-     * @param string  $proxy_pass  a password for accessing the proxy server
+-     *
+-     * @return void
+-     */
+-    function XML_RPC_Client($path, $server, $port = 0,
+-                            $proxy = '', $proxy_port = 0,
+-                            $proxy_user = '', $proxy_pass = '')
+-    {
+-        $this->path       = $path;
+-        $this->proxy_user = $proxy_user;
+-        $this->proxy_pass = $proxy_pass;
+-
+-        preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match);
+-        if ($match[1] == '') {
+-            if ($port == 443) {
+-                $this->server   = $match[2];
+-                $this->protocol = 'ssl://';
+-                $this->port     = 443;
+-            } else {
+-                $this->server = $match[2];
+-                if ($port) {
+-                    $this->port = $port;
+-                }
+-            }
+-        } elseif ($match[1] == 'http://') {
+-            $this->server = $match[2];
+-            if ($port) {
+-                $this->port = $port;
+-            }
+-        } else {
+-            $this->server   = $match[2];
+-            $this->protocol = 'ssl://';
+-            if ($port) {
+-                $this->port = $port;
+-            } else {
+-                $this->port = 443;
+-            }
+-        }
+-
+-        if ($proxy) {
+-            preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match);
+-            if ($match[1] == '') {
+-                if ($proxy_port == 443) {
+-                    $this->proxy          = $match[2];
+-                    $this->proxy_protocol = 'ssl://';
+-                    $this->proxy_port     = 443;
+-                } else {
+-                    $this->proxy = $match[2];
+-                    if ($proxy_port) {
+-                        $this->proxy_port = $proxy_port;
+-                    }
+-                }
+-            } elseif ($match[1] == 'http://') {
+-                $this->proxy = $match[2];
+-                if ($proxy_port) {
+-                    $this->proxy_port = $proxy_port;
+-                }
+-            } else {
+-                $this->proxy          = $match[2];
+-                $this->proxy_protocol = 'ssl://';
+-                if ($proxy_port) {
+-                    $this->proxy_port = $proxy_port;
+-                } else {
+-                    $this->proxy_port = 443;
+-                }
+-            }
+-        }
+-    }
+-
+-    /**
+-     * Change the current debug mode
+-     *
+-     * @param int $in  where 1 = on, 0 = off
+-     *
+-     * @return void
+-     */
+-    function setDebug($in)
+-    {
+-        if ($in) {
+-            $this->debug = 1;
+-        } else {
+-            $this->debug = 0;
+-        }
+-    }
+-
+-    /**
+-     * Set username and password properties for connecting to the RPC server
+-     *
+-     * @param string $u  the user name
+-     * @param string $p  the password
+-     *
+-     * @return void
+-     *
+-     * @see XML_RPC_Client::$username, XML_RPC_Client::$password
+-     */
+-    function setCredentials($u, $p)
+-    {
+-        $this->username = $u;
+-        $this->password = $p;
+-    }
+-
+-    /**
+-     * Transmit the RPC request via HTTP 1.0 protocol
+-     *
+-     * @param object $msg       the XML_RPC_Message object
+-     * @param int    $timeout   how many seconds to wait for the request
+-     *
+-     * @return object  an XML_RPC_Response object.  0 is returned if any
+-     *                  problems happen.
+-     *
+-     * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
+-     *      XML_RPC_Client::setCredentials()
+-     */
+-    function send($msg, $timeout = 0)
+-    {
+-        if (strtolower(get_class($msg)) != 'xml_rpc_message') {
+-            $this->errstr = 'send()\'s $msg parameter must be an'
+-                          . ' XML_RPC_Message object.';
+-            $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING);
+-            return 0;
+-        }
+-        $msg->debug = $this->debug;
+-        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
+-                                        $timeout, $this->username,
+-                                        $this->password);
+-    }
+-
+-    /**
+-     * Transmit the RPC request via HTTP 1.0 protocol
+-     *
+-     * Requests should be sent using XML_RPC_Client send() rather than
+-     * calling this method directly.
+-     *
+-     * @param object $msg       the XML_RPC_Message object
+-     * @param string $server    the server to send the request to
+-     * @param int    $port      the server port send the request to
+-     * @param int    $timeout   how many seconds to wait for the request
+-     *                           before giving up
+-     * @param string $username  a user name for accessing the RPC server
+-     * @param string $password  a password for accessing the RPC server
+-     *
+-     * @return object  an XML_RPC_Response object.  0 is returned if any
+-     *                  problems happen.
+-     *
+-     * @access protected
+-     * @see XML_RPC_Client::send()
+-     */
+-    function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
+-                               $username = '', $password = '')
+-    {
+-        /*
+-         * If we're using a proxy open a socket to the proxy server
+-         * instead to the xml-rpc server
+-         */
+-        if ($this->proxy) {
+-            if ($this->proxy_protocol == 'http://') {
+-                $protocol = '';
+-            } else {
+-                $protocol = $this->proxy_protocol;
+-            }
+-            if ($timeout > 0) {
+-                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
+-                                 $this->errno, $this->errstr, $timeout);
+-            } else {
+-                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
+-                                 $this->errno, $this->errstr);
+-            }
+-        } else {
+-            if ($this->protocol == 'http://') {
+-                $protocol = '';
+-            } else {
+-                $protocol = $this->protocol;
+-            }
+-            if ($timeout > 0) {
+-                $fp = @fsockopen($protocol . $server, $port,
+-                                 $this->errno, $this->errstr, $timeout);
+-            } else {
+-                $fp = @fsockopen($protocol . $server, $port,
+-                                 $this->errno, $this->errstr);
+-            }
+-        }
+-
+-        /*
+-         * Just raising the error without returning it is strange,
+-         * but keep it here for backwards compatibility.
+-         */
+-        if (!$fp && $this->proxy) {
+-            $this->raiseError('Connection to proxy server '
+-                              . $this->proxy . ':' . $this->proxy_port
+-                              . ' failed. ' . $this->errstr,
+-                              XML_RPC_ERROR_CONNECTION_FAILED);
+-            return 0;
+-        } elseif (!$fp) {
+-            $this->raiseError('Connection to RPC server '
+-                              . $server . ':' . $port
+-                              . ' failed. ' . $this->errstr,
+-                              XML_RPC_ERROR_CONNECTION_FAILED);
+-            return 0;
+-        }
+-
+-        if ($timeout) {
+-            stream_set_timeout($fp, $timeout);
+-        }
+-
+-        // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly
+-        if ($username != $this->username) {
+-            $this->setCredentials($username, $password);
+-        }
+-
+-        // Only create the payload if it was not created previously
+-        if (empty($msg->payload)) {
+-            $msg->createPayload();
+-        }
+-        $this->createHeaders($msg);
+-
+-        $op  = $this->headers . "\r\n\r\n";
+-        $op .= $msg->payload;
+-
+-        if (!fputs($fp, $op, strlen($op))) {
+-            $this->errstr = 'Write error';
+-            return 0;
+-        }
+-        $resp = $msg->parseResponseFile($fp);
+-
+-        $meta = stream_get_meta_data($fp);
+-        if ($meta['timed_out']) {
+-            fclose($fp);
+-            $this->errstr = 'RPC server did not send response before timeout.';
+-            $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED);
+-            return 0;
+-        }
+-
+-        fclose($fp);
+-        return $resp;
+-    }
+-
+-    /**
+-     * Determines the HTTP headers and puts it in the $headers property
+-     *
+-     * @param object $msg       the XML_RPC_Message object
+-     *
+-     * @return boolean  TRUE if okay, FALSE if the message payload isn't set.
+-     *
+-     * @access protected
+-     */
+-    function createHeaders($msg)
+-    {
+-        if (empty($msg->payload)) {
+-            return false;
+-        }
+-        if ($this->proxy) {
+-            $this->headers = 'POST ' . $this->protocol . $this->server;
+-            if ($this->proxy_port) {
+-                $this->headers .= ':' . $this->port;
+-            }
+-        } else {
+-           $this->headers = 'POST ';
+-        }
+-        $this->headers .= $this->path. " HTTP/1.0\r\n";
+-        
+-        $this->headers .= "User-Agent: PEAR XML_RPC\r\n";
+-        $this->headers .= 'Host: ' . $this->server . "\r\n";
+-
+-        if ($this->proxy && $this->proxy_user) {
+-            $this->headers .= 'Proxy-Authorization: Basic '
+-                     . base64_encode("$this->proxy_user:$this->proxy_pass")
+-                     . "\r\n";
+-        }
+-
+-        // thanks to Grant Rauscher  for this
+-        if ($this->username) {
+-            $this->headers .= 'Authorization: Basic '
+-                     . base64_encode("$this->username:$this->password")
+-                     . "\r\n";
+-        }
+-
+-        $this->headers .= "Content-Type: text/xml\r\n";
+-        $this->headers .= 'Content-Length: ' . strlen($msg->payload);
+-        return true;
+-    }
+-}
+-
+-/**
+- * The methods and properties for interpreting responses to XML RPC requests
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
+- * @version    Release: 1.3.1
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Response extends XML_RPC_Base
+-{
+-    var $xv;
+-    var $fn;
+-    var $fs;
+-    var $hdrs;
+-
+-    /**
+-     * @return void
+-     */
+-    function XML_RPC_Response($val, $fcode = 0, $fstr = '')
+-    {
+-        if ($fcode != 0) {
+-            $this->fn = $fcode;
+-            $this->fs = htmlspecialchars($fstr);
+-        } else {
+-            $this->xv = $val;
+-        }
+-    }
+-
+-    /**
+-     * @return int  the error code
+-     */
+-    function faultCode()
+-    {
+-        if (isset($this->fn)) {
+-            return $this->fn;
+-        } else {
+-            return 0;
+-        }
+-    }
+-
+-    /**
+-     * @return string  the error string
+-     */
+-    function faultString()
+-    {
+-        return $this->fs;
+-    }
+-
+-    /**
+-     * @return mixed  the value
+-     */
+-    function value()
+-    {
+-        return $this->xv;
+-    }
+-
+-    /**
+-     * @return string  the error message in XML format
+-     */
+-    function serialize()
+-    {
+-        $rs = "\n";
+-        if ($this->fn) {
+-            $rs .= "
+-  
+-    
+-      
+-        faultCode
+-        " . $this->fn . "
+-      
+-      
+-        faultString
+-        " . $this->fs . "
+-      
+-    
+-  
+-";
+-        } else {
+-            $rs .= "\n\n" . $this->xv->serialize() .
+-        "\n";
+-        }
+-        $rs .= "\n";
+-        return $rs;
+-    }
+-}
+-
+-/**
+- * The methods and properties for composing XML RPC messages
+- *
+- * @category   Web Services
+- * @package    XML_RPC
+- * @author     Edd Dumbill 
+- * @author     Stig Bakken 
+- * @author     Martin Jansen 
+- * @author     Daniel Convissor 
+- * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
+- * @version    Release: 1.3.1
+- * @link       http://pear.php.net/package/XML_RPC
+- */
+-class XML_RPC_Message extends XML_RPC_Base
+-{
+-    /**
+-     * The current debug mode (1 = on, 0 = off)
+-     * @var integer
+-     */
+-    var $debug = 0;
+-
+-    /**
+-     * The encoding to be used for outgoing messages
+-     *
+-     * Defaults to the value of $GLOBALS['XML_RPC_defencoding']
+-     *
+-     * @var string
+-     * @see XML_RPC_Message::setSendEncoding(),
+-     *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
+-     */
+-    var $send_encoding = '';
+-
+-    /**
+-     * The method presently being evaluated
+-     * @var string
+-     */
+-    var $methodname = '';
+-
+-    /**
+-     * @var array
+-     */
+-    var $params = array();
+-
+-    /**
+-     * The XML message being generated
+-     * @var string
+-     */
+-    var $payload = '';
+-
+-    /**
+-     * @return void
+-     */
+-    function XML_RPC_Message($meth, $pars = 0)
+-    {
+-        $this->methodname = $meth;
+-        if (is_array($pars) && sizeof($pars) > 0) {
+-            for ($i = 0; $i < sizeof($pars); $i++) {
+-                $this->addParam($pars[$i]);
+-            }
+-        }
+-    }
+-
+-    /**
+-     * Produces the XML declaration including the encoding attribute
+-     *
+-     * The encoding is determined by this class' $send_encoding
+-     * property.  If the $send_encoding property is not set, use
+-     * $GLOBALS['XML_RPC_defencoding'].
+-     *
+-     * @return string  the XML declaration and  element
+-     *
+-     * @see XML_RPC_Message::setSendEncoding(),
+-     *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
+-     */
+-    function xml_header()
+-    {
+-        global $XML_RPC_defencoding;
+-        if (!$this->send_encoding) {
+-            $this->send_encoding = $XML_RPC_defencoding;
+-        }
+-        return 'send_encoding . '"?>'
+-               . "\n\n";
+-    }
+-
+-    /**
+-     * @return string  the closing  tag
+-     */
+-    function xml_footer()
+-    {
+-        return "\n";
+-    }
+-
+-    /**
+-     * @return void
+-     *
+-     * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
+-     */
+-    function createPayload()
+-    {
+-        $this->payload = $this->xml_header();
+-        $this->payload .= '' . $this->methodname . "\n";
+-        $this->payload .= "\n";
+-        for ($i = 0; $i < sizeof($this->params); $i++) {
+-            $p = $this->params[$i];
+-            $this->payload .= "\n" . $p->serialize() . "\n";
+-        }
+-        $this->payload .= "\n";
+-        $this->payload .= $this->xml_footer();
+-        $this->payload = ereg_replace("[\r\n]+", "\r\n", $this->payload);
+-    }
+-
+-    /**
+-     * @return string  the name of the method
+-     */
+-    function method($meth = '')
+-    {
+-        if ($meth != '') {
+-            $this->methodname = $meth;
+-        }
+-        return $this->methodname;
+-    }
+-
+-    /**
+-     * @return string  the payload
+-     */
+-    function serialize()
+-    {
+-        $this->createPayload();
+-        return $this->payload;
+-    }
+-
+-    /**
+-     * @return void
+-     */
+-    function addParam($par)
+-    {
+-        $this->params[] = $par;
+-    }
+-
+-    /**
+-     * Obtains an XML_RPC_Value object for the given parameter
+-     *
+-     * @param int $i  the index number of the parameter to obtain
+-     *
+-     * @return object  the XML_RPC_Value object.
+-     *                  If the parameter doesn't exist, an XML_RPC_Response object.
+-     *
+-     * @since Returns XML_RPC_Response object on error since Release 1.3.0
+-     */
+-    function getParam($i)
+-    {
+-        global $XML_RPC_err, $XML_RPC_str;
+-
+-        if (isset($this->params[$i])) {
+-            return $this->params[$i];
+-        } else {
+-            $this->raiseError('The submitted request did not contain this parameter',
+-                              XML_RPC_ERROR_INCORRECT_PARAMS);
+-            return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
+-                                        $XML_RPC_str['incorrect_params']);
+-        }
+-    }
+-
+-    /**
+-     * @return int  the number of parameters
+-     */
+-    function getNumParams()
+-    {
+-        return sizeof($this->params);
+-    }
+-
+-    /**
+-     * Sets the XML declaration's encoding attribute
+-     *
+-     * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
+-     *
+-     * @return void
+-     *
+-     * @see XML_RPC_Message::$send_encoding, XML_RPC_Message::xml_header()
+-     * @since Method available since Release 1.2.0
+-     */
+-    function setSendEncoding($type)
+-    {
+-        $this->send_encoding = $type;
+-    }
+-
+-    /**
+-     * Determine the XML's encoding via the encoding attribute
+-     * in the XML declaration
+-     *
+-     * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
+-     * or US-ASCII, $XML_RPC_defencoding will be returned.
+-     *
+-     * @param string $data  the XML that will be parsed
+-     *
+-     * @return string  the encoding to be used
+-     *
+-     * @link   http://php.net/xml_parser_create
+-     * @since  Method available since Release 1.2.0
+-     */
+-    function getEncoding($data)
+-    {
+-        global $XML_RPC_defencoding;
+-
+-        if (preg_match('/<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]/i',
+-                       $data, $match))
+-        {
+-            $match[1] = trim(strtoupper($match[1]));
+-            switch ($match[1]) {
+-                case 'ISO-8859-1':
+-                case 'UTF-8':
+-                case 'US-ASCII':
+-                    return $match[1];
+-                    break;
+-
+-                default:
+-                    return $XML_RPC_defencoding;
+-            }
+-        } else {
+-            return $XML_RPC_defencoding;
+-        }
+-    }
+-
+-    /**
+-     * @return object  a new XML_RPC_Response object
+-     */
+-    function parseResponseFile($fp)
+-    {
+-        $ipd = '';
+-        while ($data = @fread($fp, 8192)) {
+-            $ipd .= $data;
+-        }
+-        return $this->parseResponse($ipd);
+-    }
+-
+-    /**
+-     * @return object  a new XML_RPC_Response object
+-     */
+-    function parseResponse($data = '')
+-    {
+-        global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
+-
+-        $encoding = $this->getEncoding($data);
+-        $parser_resource = xml_parser_create($encoding);
+-        $parser = (int) $parser_resource;
+-
+-        $XML_RPC_xh[$parser] = array();
+-
+-        $XML_RPC_xh[$parser]['st'] = '';
+-        $XML_RPC_xh[$parser]['cm'] = 0;
+-        $XML_RPC_xh[$parser]['isf'] = 0;
+-        $XML_RPC_xh[$parser]['ac'] = '';
+-        $XML_RPC_xh[$parser]['qt'] = '';
+-
+-        xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
+-        xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
+-        xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
+-
+-        $hdrfnd = 0;
+-        if ($this->debug) {
+-            print "
---GOT---\n";
+-            print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
+-            print "\n---END---\n
"; +- } +- +- // See if response is a 200 or a 100 then a 200, else raise error. +- // But only do this if we're using the HTTP protocol. +- if (ereg('^HTTP', $data) && +- !ereg('^HTTP/[0-9\.]+ 200 ', $data) && +- !preg_match('@^HTTP/[0-9\.]+ 10[0-9]([A-Za-z ]+)?[\r\n]+HTTP/[0-9\.]+ 200@', $data)) +- { +- $errstr = substr($data, 0, strpos($data, "\n") - 1); +- error_log('HTTP error, got response: ' . $errstr); +- $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], +- $XML_RPC_str['http_error'] . ' (' . +- $errstr . ')'); +- xml_parser_free($parser_resource); +- return $r; +- } +- // gotta get rid of headers here +- +- +- if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) { +- $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos); +- $data = substr($data, $brpos + 4); +- $hdrfnd = 1; +- } +- +- /* +- * be tolerant of junk after methodResponse +- * (e.g. javascript automatically inserted by free hosts) +- * thanks to Luca Mariano +- */ +- $data = substr($data, 0, strpos($data, "") + 17); +- +- if (!xml_parse($parser_resource, $data, sizeof($data))) { +- // thanks to Peter Kocks +- if (xml_get_current_line_number($parser_resource) == 1) { +- $errstr = 'XML error at line 1, check URL'; +- } else { +- $errstr = sprintf('XML error: %s at line %d', +- xml_error_string(xml_get_error_code($parser_resource)), +- xml_get_current_line_number($parser_resource)); +- } +- error_log($errstr); +- $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], +- $XML_RPC_str['invalid_return']); +- xml_parser_free($parser_resource); +- return $r; +- } +- xml_parser_free($parser_resource); +- if ($this->debug) { +- print '
---EVALING---[' .
+-            strlen($XML_RPC_xh[$parser]['st']) . " chars]---\n" .
+-            htmlspecialchars($XML_RPC_xh[$parser]['st']) . ";\n---END---
"; +- } +- if (strlen($XML_RPC_xh[$parser]['st']) == 0) { +- // then something odd has happened +- // and it's time to generate a client side error +- // indicating something odd went on +- $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], +- $XML_RPC_str['invalid_return']); +- } else { +- eval('$v=' . $XML_RPC_xh[$parser]['st'] . '; $allOK=1;'); +- if ($XML_RPC_xh[$parser]['isf']) { +- $f = $v->structmem('faultCode'); +- $fs = $v->structmem('faultString'); +- $r = new XML_RPC_Response($v, $f->scalarval(), +- $fs->scalarval()); +- } else { +- $r = new XML_RPC_Response($v); +- } +- } +- $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]); +- return $r; +- } +-} +- +-/** +- * The methods and properties that represent data in XML RPC format +- * +- * @category Web Services +- * @package XML_RPC +- * @author Edd Dumbill +- * @author Stig Bakken +- * @author Martin Jansen +- * @author Daniel Convissor +- * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group +- * @version Release: 1.3.1 +- * @link http://pear.php.net/package/XML_RPC +- */ +-class XML_RPC_Value extends XML_RPC_Base +-{ +- var $me = array(); +- var $mytype = 0; +- +- /** +- * @return void +- */ +- function XML_RPC_Value($val = -1, $type = '') +- { +- global $XML_RPC_Types; +- $this->me = array(); +- $this->mytype = 0; +- if ($val != -1 || $type != '') { +- if ($type == '') { +- $type = 'string'; +- } +- if (!array_key_exists($type, $XML_RPC_Types)) { +- // XXX +- // need some way to report this error +- } elseif ($XML_RPC_Types[$type] == 1) { +- $this->addScalar($val, $type); +- } elseif ($XML_RPC_Types[$type] == 2) { +- $this->addArray($val); +- } elseif ($XML_RPC_Types[$type] == 3) { +- $this->addStruct($val); +- } +- } +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addScalar($val, $type = 'string') +- { +- global $XML_RPC_Types, $XML_RPC_Boolean; +- +- if ($this->mytype == 1) { +- $this->raiseError('Scalar can have only one value', +- XML_RPC_ERROR_INVALID_TYPE); +- return 0; +- } +- $typeof = $XML_RPC_Types[$type]; +- if ($typeof != 1) { +- $this->raiseError("Not a scalar type (${typeof})", +- XML_RPC_ERROR_INVALID_TYPE); +- return 0; +- } +- +- if ($type == $XML_RPC_Boolean) { +- if (strcasecmp($val, 'true') == 0 +- || $val == 1 +- || ($val == true && strcasecmp($val, 'false'))) +- { +- $val = 1; +- } else { +- $val = 0; +- } +- } +- +- if ($this->mytype == 2) { +- // we're adding to an array here +- $ar = $this->me['array']; +- $ar[] = new XML_RPC_Value($val, $type); +- $this->me['array'] = $ar; +- } else { +- // a scalar, so set the value and remember we're scalar +- $this->me[$type] = $val; +- $this->mytype = $typeof; +- } +- return 1; +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addArray($vals) +- { +- global $XML_RPC_Types; +- if ($this->mytype != 0) { +- $this->raiseError( +- 'Already initialized as a [' . $this->kindOf() . ']', +- XML_RPC_ERROR_ALREADY_INITIALIZED); +- return 0; +- } +- $this->mytype = $XML_RPC_Types['array']; +- $this->me['array'] = $vals; +- return 1; +- } +- +- /** +- * @return int returns 1 if successful or 0 if there are problems +- */ +- function addStruct($vals) +- { +- global $XML_RPC_Types; +- if ($this->mytype != 0) { +- $this->raiseError( +- 'Already initialized as a [' . $this->kindOf() . ']', +- XML_RPC_ERROR_ALREADY_INITIALIZED); +- return 0; +- } +- $this->mytype = $XML_RPC_Types['struct']; +- $this->me['struct'] = $vals; +- return 1; +- } +- +- /** +- * @return void +- */ +- function dump($ar) +- { +- reset($ar); +- foreach ($ar as $key => $val) { +- echo "$key => $val
"; +- if ($key == 'array') { +- foreach ($val as $key2 => $val2) { +- echo "-- $key2 => $val2
"; +- } +- } +- } +- } +- +- /** +- * @return string the data type of the current value +- */ +- function kindOf() +- { +- switch ($this->mytype) { +- case 3: +- return 'struct'; +- +- case 2: +- return 'array'; +- +- case 1: +- return 'scalar'; +- +- default: +- return 'undef'; +- } +- } +- +- /** +- * @return string the data in XML format +- */ +- function serializedata($typ, $val) +- { +- $rs = ''; +- global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean; +- if (!array_key_exists($typ, $XML_RPC_Types)) { +- // XXX +- // need some way to report this error +- return; +- } +- switch ($XML_RPC_Types[$typ]) { +- case 3: +- // struct +- $rs .= "\n"; +- reset($val); +- foreach ($val as $key2 => $val2) { +- $rs .= "${key2}\n"; +- $rs .= $this->serializeval($val2); +- $rs .= "\n"; +- } +- $rs .= ''; +- break; +- +- case 2: +- // array +- $rs .= "\n\n"; +- for ($i = 0; $i < sizeof($val); $i++) { +- $rs .= $this->serializeval($val[$i]); +- } +- $rs .= "\n"; +- break; +- +- case 1: +- switch ($typ) { +- case $XML_RPC_Base64: +- $rs .= "<${typ}>" . base64_encode($val) . ""; +- break; +- case $XML_RPC_Boolean: +- $rs .= "<${typ}>" . ($val ? '1' : '0') . ""; +- break; +- case $XML_RPC_String: +- $rs .= "<${typ}>" . htmlspecialchars($val). ""; +- break; +- default: +- $rs .= "<${typ}>${val}"; +- } +- } +- return $rs; +- } +- +- /** +- * @return string the data in XML format +- */ +- function serialize() +- { +- return $this->serializeval($this); +- } +- +- /** +- * @return string the data in XML format +- */ +- function serializeval($o) +- { +- $rs = ''; +- $ar = $o->me; +- reset($ar); +- list($typ, $val) = each($ar); +- $rs .= ''; +- $rs .= $this->serializedata($typ, $val); +- $rs .= "\n"; +- return $rs; +- } +- +- /** +- * @return mixed the contents of the element requested +- */ +- function structmem($m) +- { +- return $this->me['struct'][$m]; +- } +- +- /** +- * @return void +- */ +- function structreset() +- { +- reset($this->me['struct']); +- } +- +- /** +- * @return the key/value pair of the struct's current element +- */ +- function structeach() +- { +- return each($this->me['struct']); +- } +- +- /** +- * @return mixed the current value +- */ +- function getval() +- { +- // UNSTABLE +- global $XML_RPC_BOOLEAN, $XML_RPC_Base64; +- +- reset($this->me); +- $b = current($this->me); +- +- // contributed by I Sofer, 2001-03-24 +- // add support for nested arrays to scalarval +- // i've created a new method here, so as to +- // preserve back compatibility +- +- if (is_array($b)) { +- foreach ($b as $id => $cont) { +- $b[$id] = $cont->scalarval(); +- } +- } +- +- // add support for structures directly encoding php objects +- if (is_object($b)) { +- $t = get_object_vars($b); +- foreach ($t as $id => $cont) { +- $t[$id] = $cont->scalarval(); +- } +- foreach ($t as $id => $cont) { +- eval('$b->'.$id.' = $cont;'); +- } +- } +- +- // end contrib +- return $b; +- } +- +- /** +- * @return mixed +- */ +- function scalarval() +- { +- global $XML_RPC_Boolean, $XML_RPC_Base64; +- reset($this->me); +- return current($this->me); +- } +- +- /** +- * @return string +- */ +- function scalartyp() +- { +- global $XML_RPC_I4, $XML_RPC_Int; +- reset($this->me); +- $a = key($this->me); +- if ($a == $XML_RPC_I4) { +- $a = $XML_RPC_Int; +- } +- return $a; +- } +- +- /** +- * @return mixed the struct's current element +- */ +- function arraymem($m) +- { +- return $this->me['array'][$m]; +- } +- +- /** +- * @return int the number of elements in the array +- */ +- function arraysize() +- { +- reset($this->me); +- list($a, $b) = each($this->me); +- return sizeof($b); +- } +- +- /** +- * Determines if the item submitted is an XML_RPC_Value object +- * +- * @param mixed $val the variable to be evaluated +- * +- * @return bool TRUE if the item is an XML_RPC_Value object +- * +- * @static +- * @since Method available since Release 1.3.0 +- */ +- function isValue($val) +- { +- return (strtolower(get_class($val)) == 'xml_rpc_value'); +- } +-} +- +-/** +- * Return an ISO8601 encoded string +- * +- * While timezones ought to be supported, the XML-RPC spec says: +- * +- * "Don't assume a timezone. It should be specified by the server in its +- * documentation what assumptions it makes about timezones." +- * +- * This routine always assumes localtime unless $utc is set to 1, in which +- * case UTC is assumed and an adjustment for locale is made when encoding. +- * +- * @return string the formatted date +- */ +-function XML_RPC_iso8601_encode($timet, $utc = 0) +-{ +- if (!$utc) { +- $t = strftime('%Y%m%dT%H:%M:%S', $timet); +- } else { +- if (function_exists('gmstrftime')) { +- // gmstrftime doesn't exist in some versions +- // of PHP +- $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); +- } else { +- $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); +- } +- } +- return $t; +-} +- +-/** +- * Convert a datetime string into a Unix timestamp +- * +- * While timezones ought to be supported, the XML-RPC spec says: +- * +- * "Don't assume a timezone. It should be specified by the server in its +- * documentation what assumptions it makes about timezones." +- * +- * This routine always assumes localtime unless $utc is set to 1, in which +- * case UTC is assumed and an adjustment for locale is made when encoding. +- * +- * @return int the unix timestamp of the date submitted +- */ +-function XML_RPC_iso8601_decode($idate, $utc = 0) +-{ +- $t = 0; +- if (ereg('([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})', $idate, $regs)) { +- if ($utc) { +- $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +- } else { +- $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); +- } +- } +- return $t; +-} +- +-/** +- * Converts an XML_RPC_Value object into native PHP types +- * +- * @param object $XML_RPC_val the XML_RPC_Value object to decode +- * +- * @return mixed the PHP values +- */ +-function XML_RPC_decode($XML_RPC_val) +-{ +- $kind = $XML_RPC_val->kindOf(); +- +- if ($kind == 'scalar') { +- return $XML_RPC_val->scalarval(); +- +- } elseif ($kind == 'array') { +- $size = $XML_RPC_val->arraysize(); +- $arr = array(); +- for ($i = 0; $i < $size; $i++) { +- $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i)); +- } +- return $arr; +- +- } elseif ($kind == 'struct') { +- $XML_RPC_val->structreset(); +- $arr = array(); +- while (list($key, $value) = $XML_RPC_val->structeach()) { +- $arr[$key] = XML_RPC_decode($value); +- } +- return $arr; +- } +-} +- +-/** +- * Converts native PHP types into an XML_RPC_Value object +- * +- * @param mixed $php_val the PHP value or variable you want encoded +- * +- * @return object the XML_RPC_Value object +- */ +-function XML_RPC_encode($php_val) +-{ +- global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double, $XML_RPC_String, +- $XML_RPC_Array, $XML_RPC_Struct; +- +- $type = gettype($php_val); +- $XML_RPC_val = new XML_RPC_Value; +- +- switch ($type) { +- case 'array': +- if (empty($php_val)) { +- $XML_RPC_val->addArray($php_val); +- break; +- } +- $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); +- if (empty($tmp)) { +- $arr = array(); +- foreach ($php_val as $k => $v) { +- $arr[$k] = XML_RPC_encode($v); +- } +- $XML_RPC_val->addArray($arr); +- break; +- } +- // fall though if it's not an enumerated array +- +- case 'object': +- $arr = array(); +- foreach ($php_val as $k => $v) { +- $arr[$k] = XML_RPC_encode($v); +- } +- $XML_RPC_val->addStruct($arr); +- break; +- +- case 'integer': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Int); +- break; +- +- case 'double': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Double); +- break; +- +- case 'string': +- case 'NULL': +- $XML_RPC_val->addScalar($php_val, $XML_RPC_String); +- break; +- +- case 'boolean': +- // Add support for encoding/decoding of booleans, since they +- // are supported in PHP +- // by +- $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean); +- break; +- +- case 'unknown type': +- default: +- $XML_RPC_val = false; +- } +- return $XML_RPC_val; +-} +- +-/* +- * Local variables: +- * tab-width: 4 +- * c-basic-offset: 4 +- * c-hanging-comment-ender-p: nil +- * End: +- */ +- +-?> +-XML_RPC-1.3.1/Server.php100644 1750 144 47770 10260516576 10104 +- * @author Stig Bakken +- * @author Martin Jansen +- * @author Daniel Convissor +- * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group +- * @version CVS: $Id: Server.php,v 1.26 2005/05/09 21:39:47 danielc Exp $ +- * @link http://pear.php.net/package/XML_RPC +- */ +- +- +-/** +- * Pull in the XML_RPC class +- */ +-require_once 'XML/RPC.php'; +- +- +-/** +- * signature for system.listMethods: return = array, +- * parameters = a string or nothing +- * @global array $GLOBALS['XML_RPC_Server_listMethods_sig'] +- */ +-$GLOBALS['XML_RPC_Server_listMethods_sig'] = array( +- array($GLOBALS['XML_RPC_Array'], +- $GLOBALS['XML_RPC_String'] +- ), +- array($GLOBALS['XML_RPC_Array']) +-); +- +-/** +- * docstring for system.listMethods +- * @global string $GLOBALS['XML_RPC_Server_listMethods_doc'] +- */ +-$GLOBALS['XML_RPC_Server_listMethods_doc'] = 'This method lists all the' +- . ' methods that the XML-RPC server knows how to dispatch'; +- +-/** +- * signature for system.methodSignature: return = array, +- * parameters = string +- * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig'] +- */ +-$GLOBALS['XML_RPC_Server_methodSignature_sig'] = array( +- array($GLOBALS['XML_RPC_Array'], +- $GLOBALS['XML_RPC_String'] +- ) +-); +- +-/** +- * docstring for system.methodSignature +- * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc'] +- */ +-$GLOBALS['XML_RPC_Server_methodSignature_doc'] = 'Returns an array of known' +- . ' signatures (an array of arrays) for the method name passed. If' +- . ' no signatures are known, returns a none-array (test for type !=' +- . ' array to detect missing signature)'; +- +-/** +- * signature for system.methodHelp: return = string, +- * parameters = string +- * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig'] +- */ +-$GLOBALS['XML_RPC_Server_methodHelp_sig'] = array( +- array($GLOBALS['XML_RPC_String'], +- $GLOBALS['XML_RPC_String'] +- ) +-); +- +-/** +- * docstring for methodHelp +- * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc'] +- */ +-$GLOBALS['XML_RPC_Server_methodHelp_doc'] = 'Returns help text if defined' +- . ' for the method passed, otherwise returns an empty string'; +- +-/** +- * dispatch map for the automatically declared XML-RPC methods. +- * @global array $GLOBALS['XML_RPC_Server_dmap'] +- */ +-$GLOBALS['XML_RPC_Server_dmap'] = array( +- 'system.listMethods' => array( +- 'function' => 'XML_RPC_Server_listMethods', +- 'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc'] +- ), +- 'system.methodHelp' => array( +- 'function' => 'XML_RPC_Server_methodHelp', +- 'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc'] +- ), +- 'system.methodSignature' => array( +- 'function' => 'XML_RPC_Server_methodSignature', +- 'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'], +- 'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc'] +- ) +-); +- +-/** +- * @global string $GLOBALS['XML_RPC_Server_debuginfo'] +- */ +-$GLOBALS['XML_RPC_Server_debuginfo'] = ''; +- +- +-/** +- * Lists all the methods that the XML-RPC server knows how to dispatch +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_listMethods($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $v = new XML_RPC_Value(); +- $outAr = array(); +- foreach ($server->dmap as $key => $val) { +- $outAr[] = new XML_RPC_Value($key, 'string'); +- } +- foreach ($XML_RPC_Server_dmap as $key => $val) { +- $outAr[] = new XML_RPC_Value($key, 'string'); +- } +- $v->addArray($outAr); +- return new XML_RPC_Response($v); +-} +- +-/** +- * Returns an array of known signatures (an array of arrays) +- * for the given method +- * +- * If no signatures are known, returns a none-array +- * (test for type != array to detect missing signature) +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_methodSignature($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $methName = $m->getParam(0); +- $methName = $methName->scalarval(); +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $server->dmap; +- $sysCall = 0; +- } +- // print "\n"; +- if (isset($dmap[$methName])) { +- if ($dmap[$methName]['signature']) { +- $sigs = array(); +- $thesigs = $dmap[$methName]['signature']; +- for ($i = 0; $i < sizeof($thesigs); $i++) { +- $cursig = array(); +- $inSig = $thesigs[$i]; +- for ($j = 0; $j < sizeof($inSig); $j++) { +- $cursig[] = new XML_RPC_Value($inSig[$j], 'string'); +- } +- $sigs[] = new XML_RPC_Value($cursig, 'array'); +- } +- $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array')); +- } else { +- $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string')); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], +- $XML_RPC_str['introspect_unknown']); +- } +- return $r; +-} +- +-/** +- * Returns help text if defined for the method passed, otherwise returns +- * an empty string +- * +- * @return object a new XML_RPC_Response object +- */ +-function XML_RPC_Server_methodHelp($server, $m) +-{ +- global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; +- +- $methName = $m->getParam(0); +- $methName = $methName->scalarval(); +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $server->dmap; +- $sysCall = 0; +- } +- // print "\n"; +- if (isset($dmap[$methName])) { +- if ($dmap[$methName]['docstring']) { +- $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']), +- 'string'); +- } else { +- $r = new XML_RPC_Response(new XML_RPC_Value('', 'string')); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], +- $XML_RPC_str['introspect_unknown']); +- } +- return $r; +-} +- +-/** +- * @return void +- */ +-function XML_RPC_Server_debugmsg($m) +-{ +- global $XML_RPC_Server_debuginfo; +- $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n"; +-} +- +- +-/** +- * A server for receiving and replying to XML RPC requests +- * +- * +- * $server = new XML_RPC_Server( +- * array( +- * 'isan8' => +- * array( +- * 'function' => 'is_8', +- * 'signature' => +- * array( +- * array('boolean', 'int'), +- * array('boolean', 'int', 'boolean'), +- * array('boolean', 'string'), +- * array('boolean', 'string', 'boolean'), +- * ), +- * 'docstring' => 'Is the value an 8?' +- * ), +- * ), +- * 1, +- * 0 +- * ); +- * +- * +- * @category Web Services +- * @package XML_RPC +- * @author Edd Dumbill +- * @author Stig Bakken +- * @author Martin Jansen +- * @author Daniel Convissor +- * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group +- * @version Release: 1.3.1 +- * @link http://pear.php.net/package/XML_RPC +- */ +-class XML_RPC_Server +-{ +- /** +- * The dispatch map, listing the methods this server provides. +- * @var array +- */ +- var $dmap = array(); +- +- /** +- * The present response's encoding +- * @var string +- * @see XML_RPC_Message::getEncoding() +- */ +- var $encoding = ''; +- +- /** +- * Debug mode (0 = off, 1 = on) +- * @var integer +- */ +- var $debug = 0; +- +- /** +- * The response's HTTP headers +- * @var string +- */ +- var $server_headers = ''; +- +- /** +- * The response's XML payload +- * @var string +- */ +- var $server_payload = ''; +- +- +- /** +- * Constructor for the XML_RPC_Server class +- * +- * @param array $dispMap the dispatch map. An associative array +- * explaining each function. The keys of the main +- * array are the procedure names used by the +- * clients. The value is another associative array +- * that contains up to three elements: +- * + The 'function' element's value is the name +- * of the function or method that gets called. +- * To define a class' method: 'class::method'. +- * + The 'signature' element (optional) is an +- * array describing the return values and +- * parameters +- * + The 'docstring' element (optional) is a +- * string describing what the method does +- * @param int $serviceNow should the HTTP response be sent now? +- * (1 = yes, 0 = no) +- * @param int $debug should debug output be displayed? +- * (1 = yes, 0 = no) +- * +- * @return void +- */ +- function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) +- { +- global $HTTP_RAW_POST_DATA; +- +- if ($debug) { +- $this->debug = 1; +- } else { +- $this->debug = 0; +- } +- +- $this->dmap = $dispMap; +- +- if ($serviceNow) { +- $this->service(); +- } else { +- $this->createServerPayload(); +- $this->createServerHeaders(); +- } +- } +- +- /** +- * @return string the debug information if debug debug mode is on +- */ +- function serializeDebug() +- { +- global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA; +- +- if ($this->debug) { +- XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n" +- . $HTTP_RAW_POST_DATA +- . "\n" . '^^^ END POST DATA ^^^'); +- } +- +- if ($XML_RPC_Server_debuginfo != '') { +- return "\n"; +- } else { +- return ''; +- } +- } +- +- /** +- * Sends the response +- * +- * The encoding and content-type are determined by +- * XML_RPC_Message::getEncoding() +- * +- * @return void +- * +- * @uses XML_RPC_Server::createServerPayload(), +- * XML_RPC_Server::createServerHeaders() +- */ +- function service() +- { +- $this->createServerPayload(); +- $this->createServerHeaders(); +- header($this->server_headers); +- print $this->server_payload; +- } +- +- /** +- * Generates the payload and puts it in the $server_payload property +- * +- * @return void +- * +- * @uses XML_RPC_Server::parseRequest(), XML_RPC_Server::$encoding, +- * XML_RPC_Response::serialize(), XML_RPC_Server::serializeDebug() +- */ +- function createServerPayload() +- { +- $r = $this->parseRequest(); +- $this->server_payload = 'encoding . '"?>' . "\n" +- . $this->serializeDebug() +- . $r->serialize(); +- } +- +- /** +- * Determines the HTTP headers and puts them in the $server_headers +- * property +- * +- * @return boolean TRUE if okay, FALSE if $server_payload isn't set. +- * +- * @uses XML_RPC_Server::createServerPayload(), +- * XML_RPC_Server::$server_headers +- */ +- function createServerHeaders() +- { +- if (!$this->server_payload) { +- return false; +- } +- $this->server_headers = 'Content-Length: ' +- . strlen($this->server_payload) . "\r\n" +- . 'Content-Type: text/xml;' +- . ' charset=' . $this->encoding; +- return true; +- } +- +- /** +- * @return array +- */ +- function verifySignature($in, $sig) +- { +- for ($i = 0; $i < sizeof($sig); $i++) { +- // check each possible signature in turn +- $cursig = $sig[$i]; +- if (sizeof($cursig) == $in->getNumParams() + 1) { +- $itsOK = 1; +- for ($n = 0; $n < $in->getNumParams(); $n++) { +- $p = $in->getParam($n); +- // print "\n"; +- if ($p->kindOf() == 'scalar') { +- $pt = $p->scalartyp(); +- } else { +- $pt = $p->kindOf(); +- } +- // $n+1 as first type of sig is return type +- if ($pt != $cursig[$n+1]) { +- $itsOK = 0; +- $pno = $n+1; +- $wanted = $cursig[$n+1]; +- $got = $pt; +- break; +- } +- } +- if ($itsOK) { +- return array(1); +- } +- } +- } +- if (isset($wanted)) { +- return array(0, "Wanted ${wanted}, got ${got} at param ${pno}"); +- } else { +- $allowed = array(); +- foreach ($sig as $val) { +- end($val); +- $allowed[] = key($val); +- } +- $allowed = array_unique($allowed); +- $last = count($allowed) - 1; +- if ($last > 0) { +- $allowed[$last] = 'or ' . $allowed[$last]; +- } +- return array(0, +- 'Signature permits ' . implode(', ', $allowed) +- . ' parameters but the request had ' +- . $in->getNumParams()); +- } +- } +- +- /** +- * @return object a new XML_RPC_Response object +- * +- * @uses XML_RPC_Message::getEncoding(), XML_RPC_Server::$encoding +- */ +- function parseRequest($data = '') +- { +- global $XML_RPC_xh, $HTTP_RAW_POST_DATA, +- $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml, +- $XML_RPC_defencoding, $XML_RPC_Server_dmap; +- +- if ($data == '') { +- $data = $HTTP_RAW_POST_DATA; +- } +- +- $this->encoding = XML_RPC_Message::getEncoding($data); +- $parser_resource = xml_parser_create($this->encoding); +- $parser = (int) $parser_resource; +- +- $XML_RPC_xh[$parser] = array(); +- $XML_RPC_xh[$parser]['st'] = ''; +- $XML_RPC_xh[$parser]['cm'] = 0; +- $XML_RPC_xh[$parser]['isf'] = 0; +- $XML_RPC_xh[$parser]['params'] = array(); +- $XML_RPC_xh[$parser]['method'] = ''; +- +- $plist = ''; +- +- // decompose incoming XML into request structure +- +- xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true); +- xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee'); +- xml_set_character_data_handler($parser_resource, 'XML_RPC_cd'); +- if (!xml_parse($parser_resource, $data, 1)) { +- // return XML error as a faultCode +- $r = new XML_RPC_Response(0, +- $XML_RPC_errxml+xml_get_error_code($parser_resource), +- sprintf('XML error: %s at line %d', +- xml_error_string(xml_get_error_code($parser_resource)), +- xml_get_current_line_number($parser_resource))); +- xml_parser_free($parser_resource); +- } else { +- xml_parser_free($parser_resource); +- $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']); +- // now add parameters in +- for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) { +- // print '\n"; +- $plist .= "$i - " . $XML_RPC_xh[$parser]['params'][$i] . " \n"; +- eval('$m->addParam(' . $XML_RPC_xh[$parser]['params'][$i] . ');'); +- } +- XML_RPC_Server_debugmsg($plist); +- +- // now to deal with the method +- $methName = $XML_RPC_xh[$parser]['method']; +- if (strpos($methName, 'system.') === 0) { +- $dmap = $XML_RPC_Server_dmap; +- $sysCall = 1; +- } else { +- $dmap = $this->dmap; +- $sysCall = 0; +- } +- +- if (isset($dmap[$methName]['function']) +- && is_string($dmap[$methName]['function']) +- && strpos($dmap[$methName]['function'], '::') !== false) +- { +- $dmap[$methName]['function'] = +- explode('::', $dmap[$methName]['function']); +- } +- +- if (isset($dmap[$methName]['function']) +- && is_callable($dmap[$methName]['function'])) +- { +- // dispatch if exists +- if (isset($dmap[$methName]['signature'])) { +- $sr = $this->verifySignature($m, +- $dmap[$methName]['signature'] ); +- } +- if (!isset($dmap[$methName]['signature']) || $sr[0]) { +- // if no signature or correct signature +- if ($sysCall) { +- $r = call_user_func($dmap[$methName]['function'], $this, $m); +- } else { +- $r = call_user_func($dmap[$methName]['function'], $m); +- } +- if (!is_a($r, 'XML_RPC_Response')) { +- $r = new XML_RPC_Response(0, $XML_RPC_err['not_response_object'], +- $XML_RPC_str['not_response_object']); +- } +- } else { +- $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], +- $XML_RPC_str['incorrect_params'] +- . ': ' . $sr[1]); +- } +- } else { +- // else prepare error response +- $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'], +- $XML_RPC_str['unknown_method']); +- } +- } +- return $r; +- } +- +- /** +- * Echos back the input packet as a string value +- * +- * @return void +- * +- * Useful for debugging. +- */ +- function echoInput() +- { +- global $HTTP_RAW_POST_DATA; +- +- $r = new XML_RPC_Response(0); +- $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); +- print $r->serialize(); +- } +-} +- +-/* +- * Local variables: +- * tab-width: 4 +- * c-basic-offset: 4 +- * c-hanging-comment-ender-p: nil +- * End: +- */ +- +-?> +-package.xml100644 1750 144 22507 10260516576 6427 +- +- +- XML_RPC +- PHP implementation of the XML-RPC protocol +- A PEAR-ified version of Useful Inc's XML-RPC for PHP. +- +-It has support for HTTP/HTTPS transport, proxies and authentication. +- +- +- +- ssb +- Stig Bakken +- stig@php.net +- lead +- +- +- danielc +- Daniel Convissor +- danielc@php.net +- lead +- +- +- +- 1.3.1 +- 2005-06-29 +- PHP License +- stable +- * Security fix. Update highly recommended! +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- 1.3.0RC3 +- 2005-05-10 +- beta +- * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. +-* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. +-* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. +-* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. +-* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). +-* Use <br /> instead of <br> in XML_RPC_Value::dump(). +- +- +- +- 1.3.0RC2 +- 2005-05-05 +- beta +- * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. +-* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. +-* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. +-* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. +- +- +- +- 1.3.0RC1 +- 2005-04-07 +- beta +- * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. +-* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. +-* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. +-* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. +-* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. +-* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. +- +- +- +- 1.2.2 +- 2005-03-07 +- stable +- * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. +- +- +- +- 1.2.1 +- 2005-03-01 +- stable +- * Add isset() check before examining the dispatch map. Bug 3658. +- +- +- +- 1.2.0 +- 2005-02-27 +- stable +- * Provide the "stable" release. +-* Add package2.xml for compatibility with PEAR 1.4.0. +-* For changes since 1.1.0, see the changelogs for the various RC releases. +- +- +- +- 1.2.0RC7 +- 2005-02-22 +- beta +- * Add the setSendEncoding() method and $send_encoding +- property to XML_RPC_Message. Request 3537. +-* Allow class methods to be mapped using either syntax: +- 'function' => 'hello::sayHello', +- or +- 'function' => array('hello', 'sayhello'), +- Bug 3363. +-* Use 8192 instead of 32768 for bytes in fread() +- in parseResponseFile(). Bug 3340. +- +- +- +- 1.2.0RC6 +- 2005-01-25 +- beta +- * Don't put the protocol in the Host field of the POST data. (danielc) +- +- +- +- 1.2.0RC5 +- 2005-01-24 +- beta +- * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. +- +- +- +- 1.2.0RC4 +- 2005-01-24 +- beta +- * When a connection attempt fails, have the method return 0. (danielc) +-* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) +-* Add tests for setting the client properties. (danielc) +-* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) +-* Bundle the tests with the package. (danielc) +- +- +- +- 1.2.0RC3 +- 2005-01-19 +- beta +- * ssl uses port 443, not 445. +- +- +- +- 1.2.0RC2 +- 2005-01-11 +- beta +- * Handle ssl:// in the $server string. (danielc) +-* Also default to port 445 for ssl:// requests as well. (danielc) +-* Enhance debugging in the server. (danielc) +- +- +- +- 1.2.0RC1 +- 2004-12-30 +- beta +- * Make things work with SSL. Bug 2489. (nkukard lbsd net) +-* Allow array function callbacks (Matt Kane) +-* Some minor speed-ups (Matt Kane) +-* Add Dump.php to the package (Christian Weiske) +-* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) +-* Silence fsockopen() errors. Bug 1714. (danielc) +-* Encode empty arrays as an array. Bug 1493. (danielc) +-* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) +-* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) +-* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) +-* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) +-* Allow raiseError() to be called statically. (danielc) +-* Stop double escaping of character entities. Bug 987. (danielc) +- NOTICE: the following have been removed: +- * XML_RPC_dh() +- * $GLOBALS['XML_RPC_entities'] +- * XML_RPC_entity_decode() +- * XML_RPC_lookup_entity() +-* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) +- +- +- +- 1.1.0 +- 2004-03-15 +- stable +- * Added support for sequential arrays to XML_RPC_encode() (mroch) +-* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) +-* Remove "require_once 'PEAR.php'", include only when needed to raise an error +-* Replace echo and error_log() with raiseError() (mroch) +-* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) +-* be tolerant of junk after methodResponse (Luca Mariano, mroch) +-* Silent notice even in the error log (pierre) +-* fix include of shared xml extension on win32 (pierre) +- +- +- +- 1.0.4 +- 2002-10-02 +- stable +- * added HTTP proxy authorization support (thanks to Arnaud Limbourg) +- +- +- +- 1.0.3 +- 2002-05-19 +- stable +- * fix bug when parsing responses with boolean types +- +- +- +- 1.0.2 +- 2002-04-16 +- stable +- * E_ALL fixes +-* fix HTTP response header parsing +- +- +- +- 1.0.1 +- 2001-09-25 +- stable +- This is a PEAR-ified version of Useful Inc's 1.0.1 release. +-Includes an urgent security fix identified by Dan Libby <dan@libby.com>. +- +- +- +- +- +\ Kein Zeilenumbruch am Dateiende. +diff -Nura php-4.4.0/pear/packages/XML_RPC-1.4.0.tar hardening-patch-4.4.0-0.4.3/pear/packages/XML_RPC-1.4.0.tar +--- php-4.4.0/pear/packages/XML_RPC-1.4.0.tar 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/pear/packages/XML_RPC-1.4.0.tar 2005-09-11 23:31:08.000000000 +0200 +@@ -0,0 +1,3933 @@ ++package2.xml100666 0 0 37144 10277724746 6362 ++ ++ XML_RPC ++ pear.php.net ++ PHP implementation of the XML-RPC protocol ++ A PEAR-ified version of Useful Inc's XML-RPC for PHP. ++ ++It has support for HTTP/HTTPS transport, proxies and authentication. ++ ++ Stig Bakken ++ ssb ++ stig@php.net ++ no ++ ++ ++ Daniel Convissor ++ danielc ++ danielc@php.net ++ yes ++ ++ 2005-08-14 ++ ++ ++ 1.4.0 ++ 1.4.0 ++ ++ ++ stable ++ stable ++ ++ PHP License ++ * MAJOR SECURITY FIX: eliminate use of eval(). ++* Using socket_get_status() because stream_get_meta_data() was introduced in 4.3.0, but we need to support 4.2.0. Bug 4805. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ PEAR ++ pear.php.net ++ 1.4.0a1 ++ 1.4.0a12 ++ ++ ++ ++ ++ 4.2.0 ++ 6.0.0 ++ ++ ++ 1.4.0a1 ++ ++ ++ ++ ++ ++ ++ ++ 1.3.3 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ 2005-07-15 ++ PHP License ++ * Eliminate memory leak by resetting $XML_RPC_xh each time parseResponse() is called. Bug 4780. ++* Using socket_set_timeout() because stream_set_timeout() was introduced in 4.3.0, but we need to support 4.2.0. Bug 4805. ++ ++ ++ ++ 1.3.2 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ 2005-07-07 ++ PHP License ++ * Eliminate path disclosure vulnerabilities by suppressing error messages when eval()'ing. ++* Eliminate path disclosure vulnerability by catching bogus parameters submitted to XML_RPC_Value::serializeval(). ++* In XML_RPC_Server::service(), only call createServerPayload() and createServerHeaders() if necessary. Fixes compatibility issue introduced in Release 1.3.0RC1 for users who set the $serviceNow parameter of XML_RPC_Server() to 0. Bug 4757. ++* Change "var $errstring" to "var $errstr". Bug 4582. Was put into CVS version 1.75 of RPC.php but didn't make it into RELEASE_1_3_1. ++ ++ ++ ++ 1.3.1 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ 2005-06-29 ++ PHP License ++ * Security fix. Update highly recommended! ++ ++ ++ ++ 1.3.0 ++ 1.3.0 ++ ++ ++ stable ++ stable ++ ++ 2005-06-13 ++ PHP License ++ * Stable release. See earlier releases for changes since 1.2.2. ++ ++ ++ ++ 1.3.0RC3 ++ 1.3.0 ++ ++ ++ beta ++ stable ++ ++ 2005-05-10 ++ PHP License ++ * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. ++* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. ++* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. ++* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. ++* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). ++* Use <br /> instead of <br> in XML_RPC_Value::dump(). ++ ++ ++ ++ 1.3.0RC2 ++ 1.3.0 ++ ++ ++ beta ++ beta ++ ++ 2005-05-05 ++ PHP License ++ * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. ++* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. ++* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. ++* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. ++ ++ ++ ++ 1.3.0RC1 ++ 1.3.0 ++ ++ ++ beta ++ beta ++ ++ 2005-04-07 ++ PHP License ++ * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. ++* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. ++* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. ++* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. ++* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. ++* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. ++ ++ ++ ++ 1.2.2 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-03-07 ++ PHP License ++ * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. ++ ++ ++ ++ 1.2.1 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-03-01 ++ PHP License ++ * Add isset() check before examining the dispatch map. Bug 3658. ++ ++ ++ ++ 1.2.0 ++ 1.2.0 ++ ++ ++ stable ++ stable ++ ++ 2005-02-27 ++ PHP License ++ * Provide the "stable" release. ++* Add package2.xml for compatibility with PEAR 1.4.0. ++* For changes since 1.1.0, see the changelogs for the various RC releases. ++ ++ ++ ++ 1.2.0RC7 ++ 1.2.0RC7 ++ ++ ++ beta ++ beta ++ ++ 2005-02-22 ++ PHP License ++ * Add the setSendEncoding() method and $send_encoding ++ property to XML_RPC_Message. Request 3537. ++* Allow class methods to be mapped using either syntax: ++ 'function' => 'hello::sayHello', ++ or ++ 'function' => array('hello', 'sayhello'), ++ Bug 3363. ++* Use 8192 instead of 32768 for bytes in fread() ++ in parseResponseFile(). Bug 3340. ++ ++ ++ ++ 1.2.0RC6 ++ 1.2.0RC6 ++ ++ ++ beta ++ beta ++ ++ 2005-01-25 ++ PHP License ++ * Don't put the protocol in the Host field of the POST data. (danielc) ++ ++ ++ ++ 1.2.0RC5 ++ 1.2.0RC5 ++ ++ ++ beta ++ beta ++ ++ 2005-01-24 ++ PHP License ++ * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. ++ ++ ++ ++ 1.2.0RC4 ++ 1.2.0RC4 ++ ++ ++ beta ++ beta ++ ++ 2005-01-24 ++ PHP License ++ * When a connection attempt fails, have the method return 0. (danielc) ++* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) ++* Add tests for setting the client properties. (danielc) ++* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) ++* Bundle the tests with the package. (danielc) ++ ++ ++ ++ 1.2.0RC3 ++ 1.2.0RC3 ++ ++ ++ beta ++ beta ++ ++ 2005-01-19 ++ PHP License ++ * ssl uses port 443, not 445. ++ ++ ++ ++ 1.2.0RC2 ++ 1.2.0RC2 ++ ++ ++ beta ++ beta ++ ++ 2005-01-11 ++ PHP License ++ * Handle ssl:// in the $server string. (danielc) ++* Also default to port 445 for ssl:// requests as well. (danielc) ++* Enhance debugging in the server. (danielc) ++ ++ ++ ++ 1.2.0RC1 ++ 1.2.0RC1 ++ ++ ++ beta ++ beta ++ ++ 2004-12-30 ++ PHP License ++ * Make things work with SSL. Bug 2489. (nkukard lbsd net) ++* Allow array function callbacks (Matt Kane) ++* Some minor speed-ups (Matt Kane) ++* Add Dump.php to the package (Christian Weiske) ++* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) ++* Silence fsockopen() errors. Bug 1714. (danielc) ++* Encode empty arrays as an array. Bug 1493. (danielc) ++* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) ++* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) ++* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) ++* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) ++* Allow raiseError() to be called statically. (danielc) ++* Stop double escaping of character entities. Bug 987. (danielc) ++ NOTICE: the following have been removed: ++ * XML_RPC_dh() ++ * $GLOBALS['XML_RPC_entities'] ++ * XML_RPC_entity_decode() ++ * XML_RPC_lookup_entity() ++* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) ++ ++ ++ ++ 1.1.0 ++ 1.1.0 ++ ++ ++ stable ++ stable ++ ++ 2004-03-15 ++ PHP License ++ * Added support for sequential arrays to XML_RPC_encode() (mroch) ++* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) ++* Remove "require_once 'PEAR.php'", include only when needed to raise an error ++* Replace echo and error_log() with raiseError() (mroch) ++* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) ++* be tolerant of junk after methodResponse (Luca Mariano, mroch) ++* Silent notice even in the error log (pierre) ++* fix include of shared xml extension on win32 (pierre) ++ ++ ++ ++ 1.0.4 ++ 1.0.4 ++ ++ ++ stable ++ stable ++ ++ 2002-10-02 ++ PHP License ++ * added HTTP proxy authorization support (thanks to Arnaud Limbourg) ++ ++ ++ ++ 1.0.3 ++ 1.0.3 ++ ++ ++ stable ++ stable ++ ++ 2002-05-19 ++ PHP License ++ * fix bug when parsing responses with boolean types ++ ++ ++ ++ 1.0.2 ++ 1.0.2 ++ ++ ++ stable ++ stable ++ ++ 2002-04-16 ++ PHP License ++ * E_ALL fixes ++* fix HTTP response header parsing ++ ++ ++ ++ 1.0.1 ++ 1.0.1 ++ ++ ++ stable ++ stable ++ ++ 2001-09-25 ++ PHP License ++ This is a PEAR-ified version of Useful Inc's 1.0.1 release. ++Includes an urgent security fix identified by Dan Libby <dan@libby.com>. ++ ++ ++ ++XML_RPC-1.4.0/tests/protoport.php100666 0 0 25543 10277724745 11707 ++ * @copyright 2005 The PHP Group ++ * @license http://www.php.net/license/3_0.txt PHP License ++ * @version CVS: $Id: protoport.php,v 1.4 2005/01/24 17:48:47 danielc Exp $ ++ * @link http://pear.php.net/package/XML_RPC ++ * @since File available since Release 1.2 ++ */ ++ ++/* ++ * If the package version number is found in the left hand ++ * portion of the if() expression below, that means this file has ++ * come from the PEAR installer. Therefore, let's test the ++ * installed version of XML_RPC which should be in the include path. ++ * ++ * If the version has not been substituted in the if() expression, ++ * this file has likely come from a CVS checkout or a .tar file. ++ * Therefore, we'll assume the tests should use the version of ++ * XML_RPC that has come from there as well. ++ */ ++if ('1.4.0' != '@'.'package_version'.'@') { ++ /** ++ * Get the needed class from the PEAR installation ++ */ ++ require_once 'XML/RPC.php'; ++} else { ++ /** ++ * Get the needed class from the parent directory ++ */ ++ require_once '../RPC.php'; ++} ++ ++/** ++ * Compare the test result to the expected result ++ * ++ * If the test fails, echo out the results. ++ * ++ * @param array $expect the array of object properties you expect ++ * from the test ++ * @param object $actual the object results from the test ++ * @param string $test_name the name of the test ++ * ++ * @return void ++ */ ++function compare($expect, $actual, $test_name) { ++ $actual = get_object_vars($actual); ++ if (count(array_diff($actual, $expect))) { ++ echo "$test_name failed.\nExpect: "; ++ print_r($expect); ++ echo "Actual: "; ++ print_r($actual); ++ echo "\n"; ++ } ++} ++ ++if (php_sapi_name() != 'cli') { ++ echo "
\n";
++}
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver');
++compare($x, $c, 'defaults');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver');
++compare($x, $c, 'defaults with http');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver');
++compare($x, $c, 'defaults with https');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver');
++compare($x, $c, 'defaults with ssl');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 65);
++compare($x, $c, 'port 65');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 65);
++compare($x, $c, 'port 65 with http');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 65);
++compare($x, $c, 'port 65 with https');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => '',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65);
++compare($x, $c, 'port 65 with ssl');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 0,
++                        'theproxy');
++compare($x, $c, 'defaults proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 8080,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 0,
++                        'http://theproxy');
++compare($x, $c, 'defaults with http proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 0,
++                        'https://theproxy');
++compare($x, $c, 'defaults with https proxy');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 0,
++                        'ssl://theproxy');
++compare($x, $c, 'defaults with ssl proxy');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 65,
++                        'theproxy', 6565);
++compare($x, $c, 'port 65 proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'http://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'http://theserver', 65,
++                        'http://theproxy', 6565);
++compare($x, $c, 'port 65 with http proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'https://theserver', 65,
++                        'https://theproxy', 6565);
++compare($x, $c, 'port 65 with https proxy 6565');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 65,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'ssl://theserver', 65,
++                        'ssl://theproxy', 6565);
++compare($x, $c, 'port 65 with ssl proxy 6565');
++
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'ssl://',
++    'port' => 443,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 443,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 443,
++                        'theproxy', 443);
++compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
++
++$x = array(
++    'path' => 'thepath',
++    'server' => 'theserver',
++    'protocol' => 'http://',
++    'port' => 80,
++    'proxy' => 'theproxy',
++    'proxy_protocol' => 'ssl://',
++    'proxy_port' => 6565,
++    'proxy_user' => '',
++    'proxy_pass' => '',
++    'errno' => 0,
++    'errstring' => '',
++    'debug' => 0,
++    'username' => '',
++    'password' => '',
++);
++$c = new XML_RPC_Client('thepath', 'theserver', 0,
++                        'ssl://theproxy', 6565);
++compare($x, $c, 'port 443 no protocol and proxy port 443 no protocol');
++XML_RPC-1.4.0/tests/test_Dump.php100666      0      0        3042 10277724745  11551 new XML_RPC_Value('das ist der Titel', 'string'),
++    'startDate'=>new XML_RPC_Value(mktime(0,0,0,13,11,2004), 'dateTime.iso8601'),
++    'endDate'  =>new XML_RPC_Value(mktime(0,0,0,15,11,2004), 'dateTime.iso8601'),
++    'error'    =>'string',
++    'arkey'    => new XML_RPC_Value( array(
++        new XML_RPC_Value('simple string'),
++        new XML_RPC_Value(12345, 'int')
++        ), 'array')
++    )
++    ,'struct');
++
++XML_RPC_Dump($val);
++
++echo '==============' . "\r\n";
++$val2 = new XML_RPC_Value(44353, 'int');
++XML_RPC_Dump($val2);
++
++echo '==============' . "\r\n";
++$val3 = new XML_RPC_Value('this should be a string', 'string');
++XML_RPC_Dump($val3);
++
++echo '==============' . "\r\n";
++$val4 = new XML_RPC_Value(true, 'boolean');
++XML_RPC_Dump($val4);
++XML_RPC-1.4.0/Dump.php100666      0      0       12074 10277724745   7375 
++ * @version    CVS: $Id: Dump.php,v 1.7 2005/01/24 03:47:55 danielc Exp $
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++
++
++/**
++ * Pull in the XML_RPC class
++ */
++require_once 'XML/RPC.php';
++
++
++/**
++ * Generates the dump of the XML_RPC_Value and echoes it
++ *
++ * @param object $value  the XML_RPC_Value object to dump
++ *
++ * @return void
++ */
++function XML_RPC_Dump($value)
++{
++    $dumper = new XML_RPC_Dump();
++    echo $dumper->generateDump($value);
++}
++
++
++/**
++ * Class which generates a dump of a XML_RPC_Value object
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Christian Weiske 
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Dump
++{
++    /**
++     * The indentation array cache
++     * @var array
++     */
++    var $arIndent      = array();
++
++    /**
++     * The spaces used for indenting the XML
++     * @var string
++     */
++    var $strBaseIndent = '    ';
++
++    /**
++     * Returns the dump in XML format without printing it out
++     *
++     * @param object $value   the XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  the dump
++     */
++    function generateDump($value, $nLevel = 0)
++    {
++        if (!is_object($value) && get_class($value) != 'xml_rpc_value') {
++            require_once 'PEAR.php';
++            PEAR::raiseError('Tried to dump non-XML_RPC_Value variable' . "\r\n",
++                             0, PEAR_ERROR_PRINT);
++            if (is_object($value)) {
++                $strType = get_class($value);
++            } else {
++                $strType = gettype($value);
++            }
++            return $this->getIndent($nLevel) . 'NOT A XML_RPC_Value: '
++                   . $strType . "\r\n";
++        }
++
++        switch ($value->kindOf()) {
++        case 'struct':
++            $ret = $this->genStruct($value, $nLevel);
++            break;
++        case 'array':
++            $ret = $this->genArray($value, $nLevel);
++            break;
++        case 'scalar':
++            $ret = $this->genScalar($value->scalarval(), $nLevel);
++            break;
++        default:
++            require_once 'PEAR.php';
++            PEAR::raiseError('Illegal type "' . $value->kindOf()
++                             . '" in XML_RPC_Value' . "\r\n", 0,
++                             PEAR_ERROR_PRINT);
++        }
++
++        return $ret;
++    }
++
++    /**
++     * Returns the scalar value dump
++     *
++     * @param object $value   the scalar XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genScalar($value, $nLevel)
++    {
++        if (gettype($value) == 'object') {
++            $strClass = ' ' . get_class($value);
++        } else {
++            $strClass = '';
++        }
++        return $this->getIndent($nLevel) . gettype($value) . $strClass
++               . ' ' . $value . "\r\n";
++    }
++
++    /**
++     * Returns the dump of a struct
++     *
++     * @param object $value   the struct XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genStruct($value, $nLevel)
++    {
++        $value->structreset();
++        $strOutput = $this->getIndent($nLevel) . 'struct' . "\r\n";
++        while (list($key, $keyval) = $value->structeach()) {
++            $strOutput .= $this->getIndent($nLevel + 1) . $key . "\r\n";
++            $strOutput .= $this->generateDump($keyval, $nLevel + 2);
++        }
++        return $strOutput;
++    }
++
++    /**
++     * Returns the dump of an array
++     *
++     * @param object $value   the array XML_RPC_Value object to dump
++     * @param int    $nLevel  the level of indentation
++     *
++     * @return string  Dumped version of the scalar value
++     */
++    function genArray($value, $nLevel)
++    {
++        $nSize     = $value->arraysize();
++        $strOutput = $this->getIndent($nLevel) . 'array' . "\r\n";
++        for($nA = 0; $nA < $nSize; $nA++) {
++            $strOutput .= $this->getIndent($nLevel + 1) . $nA . "\r\n";
++            $strOutput .= $this->generateDump($value->arraymem($nA),
++                                              $nLevel + 2);
++        }
++        return $strOutput;
++    }
++
++    /**
++     * Returns the indent for a specific level and caches it for faster use
++     *
++     * @param int $nLevel  the level
++     *
++     * @return string  the indented string
++     */
++    function getIndent($nLevel)
++    {
++        if (!isset($this->arIndent[$nLevel])) {
++            $this->arIndent[$nLevel] = str_repeat($this->strBaseIndent, $nLevel);
++        }
++        return $this->arIndent[$nLevel];
++    }
++}
++
++/*
++ * Local variables:
++ * tab-width: 4
++ * c-basic-offset: 4
++ * c-hanging-comment-ender-p: nil
++ * End:
++ */
++
++?>
++XML_RPC-1.4.0/RPC.php100666      0      0      156232 10277724745   7141 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    CVS: $Id: RPC.php,v 1.83 2005/08/14 20:25:35 danielc Exp $
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++
++
++if (!function_exists('xml_parser_create')) {
++    PEAR::loadExtension('xml');
++}
++
++/**#@+
++ * Error constants
++ */
++/**
++ * Parameter values don't match parameter types
++ */
++define('XML_RPC_ERROR_INVALID_TYPE', 101);
++/**
++ * Parameter declared to be numeric but the values are not
++ */
++define('XML_RPC_ERROR_NON_NUMERIC_FOUND', 102);
++/**
++ * Communication error
++ */
++define('XML_RPC_ERROR_CONNECTION_FAILED', 103);
++/**
++ * The array or struct has already been started
++ */
++define('XML_RPC_ERROR_ALREADY_INITIALIZED', 104);
++/**
++ * Incorrect parameters submitted
++ */
++define('XML_RPC_ERROR_INCORRECT_PARAMS', 105);
++/**
++ * Programming error by developer
++ */
++define('XML_RPC_ERROR_PROGRAMMING', 106);
++/**#@-*/
++
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_I4']
++ */
++$GLOBALS['XML_RPC_I4'] = 'i4';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Int']
++ */
++$GLOBALS['XML_RPC_Int'] = 'int';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Boolean']
++ */
++$GLOBALS['XML_RPC_Boolean'] = 'boolean';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Double']
++ */
++$GLOBALS['XML_RPC_Double'] = 'double';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_String']
++ */
++$GLOBALS['XML_RPC_String'] = 'string';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_DateTime']
++ */
++$GLOBALS['XML_RPC_DateTime'] = 'dateTime.iso8601';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Base64']
++ */
++$GLOBALS['XML_RPC_Base64'] = 'base64';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Array']
++ */
++$GLOBALS['XML_RPC_Array'] = 'array';
++
++/**
++ * Data types
++ * @global string $GLOBALS['XML_RPC_Struct']
++ */
++$GLOBALS['XML_RPC_Struct'] = 'struct';
++
++
++/**
++ * Data type meta-types
++ * @global array $GLOBALS['XML_RPC_Types']
++ */
++$GLOBALS['XML_RPC_Types'] = array(
++    $GLOBALS['XML_RPC_I4']       => 1,
++    $GLOBALS['XML_RPC_Int']      => 1,
++    $GLOBALS['XML_RPC_Boolean']  => 1,
++    $GLOBALS['XML_RPC_String']   => 1,
++    $GLOBALS['XML_RPC_Double']   => 1,
++    $GLOBALS['XML_RPC_DateTime'] => 1,
++    $GLOBALS['XML_RPC_Base64']   => 1,
++    $GLOBALS['XML_RPC_Array']    => 2,
++    $GLOBALS['XML_RPC_Struct']   => 3,
++);
++
++
++/**
++ * Error message numbers
++ * @global array $GLOBALS['XML_RPC_err']
++ */
++$GLOBALS['XML_RPC_err'] = array(
++    'unknown_method'      => 1,
++    'invalid_return'      => 2,
++    'incorrect_params'    => 3,
++    'introspect_unknown'  => 4,
++    'http_error'          => 5,
++    'not_response_object' => 6,
++    'invalid_request'     => 7,
++);
++
++/**
++ * Error message strings
++ * @global array $GLOBALS['XML_RPC_str']
++ */
++$GLOBALS['XML_RPC_str'] = array(
++    'unknown_method'      => 'Unknown method',
++    'invalid_return'      => 'Invalid return payload: enable debugging to examine incoming payload',
++    'incorrect_params'    => 'Incorrect parameters passed to method',
++    'introspect_unknown'  => 'Can\'t introspect: method unknown',
++    'http_error'          => 'Didn\'t receive 200 OK from remote server.',
++    'not_response_object' => 'The requested method didn\'t return an XML_RPC_Response object.',
++    'invalid_request'     => 'Invalid request payload',
++);
++
++
++/**
++ * Default XML encoding (ISO-8859-1, UTF-8 or US-ASCII)
++ * @global string $GLOBALS['XML_RPC_defencoding']
++ */
++$GLOBALS['XML_RPC_defencoding'] = 'UTF-8';
++
++/**
++ * User error codes start at 800
++ * @global int $GLOBALS['XML_RPC_erruser']
++ */
++$GLOBALS['XML_RPC_erruser'] = 800;
++
++/**
++ * XML parse error codes start at 100
++ * @global int $GLOBALS['XML_RPC_errxml']
++ */
++$GLOBALS['XML_RPC_errxml'] = 100;
++
++
++/**
++ * Compose backslashes for escaping regexp
++ * @global string $GLOBALS['XML_RPC_backslash']
++ */
++$GLOBALS['XML_RPC_backslash'] = chr(92) . chr(92);
++
++
++/**
++ * Valid parents of XML elements
++ * @global array $GLOBALS['XML_RPC_valid_parents']
++ */
++$GLOBALS['XML_RPC_valid_parents'] = array(
++    'BOOLEAN' => array('VALUE'),
++    'I4' => array('VALUE'),
++    'INT' => array('VALUE'),
++    'STRING' => array('VALUE'),
++    'DOUBLE' => array('VALUE'),
++    'DATETIME.ISO8601' => array('VALUE'),
++    'BASE64' => array('VALUE'),
++    'ARRAY' => array('VALUE'),
++    'STRUCT' => array('VALUE'),
++    'PARAM' => array('PARAMS'),
++    'METHODNAME' => array('METHODCALL'),
++    'PARAMS' => array('METHODCALL', 'METHODRESPONSE'),
++    'MEMBER' => array('STRUCT'),
++    'NAME' => array('MEMBER'),
++    'DATA' => array('ARRAY'),
++    'FAULT' => array('METHODRESPONSE'),
++    'VALUE' => array('MEMBER', 'DATA', 'PARAM', 'FAULT'),
++);
++
++
++/**
++ * Stores state during parsing
++ *
++ * quick explanation of components:
++ *   + ac     = accumulates values
++ *   + qt     = decides if quotes are needed for evaluation
++ *   + cm     = denotes struct or array (comma needed)
++ *   + isf    = indicates a fault
++ *   + lv     = indicates "looking for a value": implements the logic
++ *               to allow values with no types to be strings
++ *   + params = stores parameters in method calls
++ *   + method = stores method name
++ *
++ * @global array $GLOBALS['XML_RPC_xh']
++ */
++$GLOBALS['XML_RPC_xh'] = array();
++
++
++/**
++ * Start element handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_se($parser_resource, $name, $attrs)
++{
++    global $XML_RPC_xh, $XML_RPC_DateTime, $XML_RPC_String, $XML_RPC_valid_parents;
++    $parser = (int) $parser_resource;
++
++    // if invalid xmlrpc already detected, skip all processing
++    if ($XML_RPC_xh[$parser]['isf'] >= 2) {
++        return;
++    }
++
++    // check for correct element nesting
++    // top level element can only be of 2 types
++    if (count($XML_RPC_xh[$parser]['stack']) == 0) {
++        if ($name != 'METHODRESPONSE' && $name != 'METHODCALL') {
++            $XML_RPC_xh[$parser]['isf'] = 2;
++            $XML_RPC_xh[$parser]['isf_reason'] = 'missing top level xmlrpc element';
++            return;
++        }
++    } else {
++        // not top level element: see if parent is OK
++        if (!in_array($XML_RPC_xh[$parser]['stack'][0], $XML_RPC_valid_parents[$name])) {
++            $name = preg_replace('[^a-zA-Z0-9._-]', '', $name);
++            $XML_RPC_xh[$parser]['isf'] = 2;
++            $XML_RPC_xh[$parser]['isf_reason'] = "xmlrpc element $name cannot be child of {$XML_RPC_xh[$parser]['stack'][0]}";
++            return;
++        }
++    }
++
++    switch ($name) {
++    case 'STRUCT':
++        $XML_RPC_xh[$parser]['cm']++;
++
++        // turn quoting off
++        $XML_RPC_xh[$parser]['qt'] = 0;
++
++        $cur_val = array();
++        $cur_val['value'] = array();
++        $cur_val['members'] = 1;
++        array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
++        break;
++
++    case 'ARRAY':
++        $XML_RPC_xh[$parser]['cm']++;
++
++        // turn quoting off
++        $XML_RPC_xh[$parser]['qt'] = 0;
++
++        $cur_val = array();
++        $cur_val['value'] = array();
++        $cur_val['members'] = 0;
++        array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
++        break;
++
++    case 'NAME':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        break;
++
++    case 'FAULT':
++        $XML_RPC_xh[$parser]['isf'] = 1;
++        break;
++
++    case 'PARAM':
++        $XML_RPC_xh[$parser]['valuestack'] = array();
++        break;
++
++    case 'VALUE':
++        $XML_RPC_xh[$parser]['lv'] = 1;
++        $XML_RPC_xh[$parser]['vt'] = $XML_RPC_String;
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        // look for a value: if this is still 1 by the
++        // time we reach the first data segment then the type is string
++        // by implication and we need to add in a quote
++        break;
++
++    case 'I4':
++    case 'INT':
++    case 'STRING':
++    case 'BOOLEAN':
++    case 'DOUBLE':
++    case 'DATETIME.ISO8601':
++    case 'BASE64':
++        $XML_RPC_xh[$parser]['ac'] = ''; // reset the accumulator
++
++        if ($name == 'DATETIME.ISO8601' || $name == 'STRING') {
++            $XML_RPC_xh[$parser]['qt'] = 1;
++
++            if ($name == 'DATETIME.ISO8601') {
++                $XML_RPC_xh[$parser]['vt'] = $XML_RPC_DateTime;
++            }
++
++        } elseif ($name == 'BASE64') {
++            $XML_RPC_xh[$parser]['qt'] = 2;
++        } else {
++            // No quoting is required here -- but
++            // at the end of the element we must check
++            // for data format errors.
++            $XML_RPC_xh[$parser]['qt'] = 0;
++        }
++        break;
++
++    case 'MEMBER':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        break;
++
++    case 'DATA':
++    case 'METHODCALL':
++    case 'METHODNAME':
++    case 'METHODRESPONSE':
++    case 'PARAMS':
++        // valid elements that add little to processing
++        break;
++    }
++
++
++    // Save current element to stack
++    array_unshift($XML_RPC_xh[$parser]['stack'], $name);
++
++    if ($name != 'VALUE') {
++        $XML_RPC_xh[$parser]['lv'] = 0;
++    }
++}
++
++/**
++ * End element handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_ee($parser_resource, $name)
++{
++    global $XML_RPC_xh, $XML_RPC_Types, $XML_RPC_String;
++    $parser = (int) $parser_resource;
++
++    if ($XML_RPC_xh[$parser]['isf'] >= 2) {
++        return;
++    }
++
++    // push this element from stack
++    // NB: if XML validates, correct opening/closing is guaranteed and
++    // we do not have to check for $name == $curr_elem.
++    // we also checked for proper nesting at start of elements...
++    $curr_elem = array_shift($XML_RPC_xh[$parser]['stack']);
++
++    switch ($name) {
++    case 'STRUCT':
++    case 'ARRAY':
++    $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
++    $XML_RPC_xh[$parser]['value'] = $cur_val['value'];
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++        $XML_RPC_xh[$parser]['cm']--;
++        break;
++
++    case 'NAME':
++    $XML_RPC_xh[$parser]['valuestack'][0]['name'] = $XML_RPC_xh[$parser]['ac'];
++        break;
++
++    case 'BOOLEAN':
++        // special case here: we translate boolean 1 or 0 into PHP
++        // constants true or false
++        if ($XML_RPC_xh[$parser]['ac'] == '1') {
++            $XML_RPC_xh[$parser]['ac'] = 'true';
++        } else {
++            $XML_RPC_xh[$parser]['ac'] = 'false';
++        }
++
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++        // Drop through intentionally.
++
++    case 'I4':
++    case 'INT':
++    case 'STRING':
++    case 'DOUBLE':
++    case 'DATETIME.ISO8601':
++    case 'BASE64':
++        if ($XML_RPC_xh[$parser]['qt'] == 1) {
++            // we use double quotes rather than single so backslashification works OK
++            $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
++        } elseif ($XML_RPC_xh[$parser]['qt'] == 2) {
++            $XML_RPC_xh[$parser]['value'] = base64_decode($XML_RPC_xh[$parser]['ac']);
++        } elseif ($name == 'BOOLEAN') {
++            $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
++        } else {
++            // we have an I4, INT or a DOUBLE
++            // we must check that only 0123456789-. are characters here
++            if (!ereg("^[+-]?[0123456789 \t\.]+$", $XML_RPC_xh[$parser]['ac'])) {
++                XML_RPC_Base::raiseError('Non-numeric value received in INT or DOUBLE',
++                                         XML_RPC_ERROR_NON_NUMERIC_FOUND);
++                $XML_RPC_xh[$parser]['value'] = XML_RPC_ERROR_NON_NUMERIC_FOUND;
++            } else {
++                // it's ok, add it on
++                $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
++            }
++        }
++
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        $XML_RPC_xh[$parser]['lv'] = 3; // indicate we've found a value
++        break;
++
++    case 'VALUE':
++        // deal with a string value
++        if (strlen($XML_RPC_xh[$parser]['ac']) > 0 &&
++            $XML_RPC_xh[$parser]['vt'] == $XML_RPC_String) {
++            $XML_RPC_xh[$parser]['value'] = $XML_RPC_xh[$parser]['ac'];
++        }
++
++        $temp = new XML_RPC_Value($XML_RPC_xh[$parser]['value'], $XML_RPC_xh[$parser]['vt']);
++
++        $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
++        if (is_array($cur_val)) {
++            if ($cur_val['members']==0) {
++                $cur_val['value'][] = $temp;
++            } else {
++                $XML_RPC_xh[$parser]['value'] = $temp;
++            }
++            array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
++        } else {
++            $XML_RPC_xh[$parser]['value'] = $temp;
++        }
++        break;
++
++    case 'MEMBER':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++
++        $cur_val = array_shift($XML_RPC_xh[$parser]['valuestack']);
++        if (is_array($cur_val)) {
++            if ($cur_val['members']==1) {
++                $cur_val['value'][$cur_val['name']] = $XML_RPC_xh[$parser]['value'];
++            }
++            array_unshift($XML_RPC_xh[$parser]['valuestack'], $cur_val);
++        }
++        break;
++
++    case 'DATA':
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = 0;
++        break;
++
++    case 'PARAM':
++        $XML_RPC_xh[$parser]['params'][] = $XML_RPC_xh[$parser]['value'];
++        break;
++
++    case 'METHODNAME':
++    case 'RPCMETHODNAME':
++        $XML_RPC_xh[$parser]['method'] = ereg_replace("^[\n\r\t ]+", '',
++                                                      $XML_RPC_xh[$parser]['ac']);
++        break;
++    }
++
++    // if it's a valid type name, set the type
++    if (isset($XML_RPC_Types[strtolower($name)])) {
++        $XML_RPC_xh[$parser]['vt'] = strtolower($name);
++    }
++}
++
++/**
++ * Character data handler for the XML parser
++ *
++ * @return void
++ */
++function XML_RPC_cd($parser_resource, $data)
++{
++    global $XML_RPC_xh, $XML_RPC_backslash;
++    $parser = (int) $parser_resource;
++
++    if ($XML_RPC_xh[$parser]['lv'] != 3) {
++        // "lookforvalue==3" means that we've found an entire value
++        // and should discard any further character data
++
++        if ($XML_RPC_xh[$parser]['lv'] == 1) {
++            // if we've found text and we're just in a  then
++            // turn quoting on, as this will be a string
++            $XML_RPC_xh[$parser]['qt'] = 1;
++            // and say we've found a value
++            $XML_RPC_xh[$parser]['lv'] = 2;
++        }
++
++        // replace characters that eval would
++        // do special things with
++        if (!isset($XML_RPC_xh[$parser]['ac'])) {
++            $XML_RPC_xh[$parser]['ac'] = '';
++        }
++        $XML_RPC_xh[$parser]['ac'] .= $data;
++    }
++}
++
++/**
++ * The common methods and properties for all of the XML_RPC classes
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Base {
++
++    /**
++     * PEAR Error handling
++     *
++     * @return object  PEAR_Error object
++     */
++    function raiseError($msg, $code)
++    {
++        include_once 'PEAR.php';
++        if (is_object(@$this)) {
++            return PEAR::raiseError(get_class($this) . ': ' . $msg, $code);
++        } else {
++            return PEAR::raiseError('XML_RPC: ' . $msg, $code);
++        }
++    }
++
++    /**
++     * Tell whether something is a PEAR_Error object
++     *
++     * @param mixed $value  the item to check
++     *
++     * @return bool  whether $value is a PEAR_Error object or not
++     *
++     * @access public
++     */
++    function isError($value)
++    {
++        return is_a($value, 'PEAR_Error');
++    }
++}
++
++/**
++ * The methods and properties for submitting XML RPC requests
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Client extends XML_RPC_Base {
++
++    /**
++     * The path and name of the RPC server script you want the request to go to
++     * @var string
++     */
++    var $path = '';
++
++    /**
++     * The name of the remote server to connect to
++     * @var string
++     */
++    var $server = '';
++
++    /**
++     * The protocol to use in contacting the remote server
++     * @var string
++     */
++    var $protocol = 'http://';
++
++    /**
++     * The port for connecting to the remote server
++     *
++     * The default is 80 for http:// connections
++     * and 443 for https:// and ssl:// connections.
++     *
++     * @var integer
++     */
++    var $port = 80;
++
++    /**
++     * A user name for accessing the RPC server
++     * @var string
++     * @see XML_RPC_Client::setCredentials()
++     */
++    var $username = '';
++
++    /**
++     * A password for accessing the RPC server
++     * @var string
++     * @see XML_RPC_Client::setCredentials()
++     */
++    var $password = '';
++
++    /**
++     * The name of the proxy server to use, if any
++     * @var string
++     */
++    var $proxy = '';
++
++    /**
++     * The protocol to use in contacting the proxy server, if any
++     * @var string
++     */
++    var $proxy_protocol = 'http://';
++
++    /**
++     * The port for connecting to the proxy server
++     *
++     * The default is 8080 for http:// connections
++     * and 443 for https:// and ssl:// connections.
++     *
++     * @var integer
++     */
++    var $proxy_port = 8080;
++
++    /**
++     * A user name for accessing the proxy server
++     * @var string
++     */
++    var $proxy_user = '';
++
++    /**
++     * A password for accessing the proxy server
++     * @var string
++     */
++    var $proxy_pass = '';
++
++    /**
++     * The error number, if any
++     * @var integer
++     */
++    var $errno = 0;
++
++    /**
++     * The error message, if any
++     * @var string
++     */
++    var $errstr = '';
++
++    /**
++     * The current debug mode (1 = on, 0 = off)
++     * @var integer
++     */
++    var $debug = 0;
++
++    /**
++     * The HTTP headers for the current request.
++     * @var string
++     */
++    var $headers = '';
++
++
++    /**
++     * Sets the object's properties
++     *
++     * @param string  $path        the path and name of the RPC server script
++     *                              you want the request to go to
++     * @param string  $server      the URL of the remote server to connect to.
++     *                              If this parameter doesn't specify a
++     *                              protocol and $port is 443, ssl:// is
++     *                              assumed.
++     * @param integer $port        a port for connecting to the remote server.
++     *                              Defaults to 80 for http:// connections and
++     *                              443 for https:// and ssl:// connections.
++     * @param string  $proxy       the URL of the proxy server to use, if any.
++     *                              If this parameter doesn't specify a
++     *                              protocol and $port is 443, ssl:// is
++     *                              assumed.
++     * @param integer $proxy_port  a port for connecting to the remote server.
++     *                              Defaults to 8080 for http:// connections and
++     *                              443 for https:// and ssl:// connections.
++     * @param string  $proxy_user  a user name for accessing the proxy server
++     * @param string  $proxy_pass  a password for accessing the proxy server
++     *
++     * @return void
++     */
++    function XML_RPC_Client($path, $server, $port = 0,
++                            $proxy = '', $proxy_port = 0,
++                            $proxy_user = '', $proxy_pass = '')
++    {
++        $this->path       = $path;
++        $this->proxy_user = $proxy_user;
++        $this->proxy_pass = $proxy_pass;
++
++        preg_match('@^(http://|https://|ssl://)?(.*)$@', $server, $match);
++        if ($match[1] == '') {
++            if ($port == 443) {
++                $this->server   = $match[2];
++                $this->protocol = 'ssl://';
++                $this->port     = 443;
++            } else {
++                $this->server = $match[2];
++                if ($port) {
++                    $this->port = $port;
++                }
++            }
++        } elseif ($match[1] == 'http://') {
++            $this->server = $match[2];
++            if ($port) {
++                $this->port = $port;
++            }
++        } else {
++            $this->server   = $match[2];
++            $this->protocol = 'ssl://';
++            if ($port) {
++                $this->port = $port;
++            } else {
++                $this->port = 443;
++            }
++        }
++
++        if ($proxy) {
++            preg_match('@^(http://|https://|ssl://)?(.*)$@', $proxy, $match);
++            if ($match[1] == '') {
++                if ($proxy_port == 443) {
++                    $this->proxy          = $match[2];
++                    $this->proxy_protocol = 'ssl://';
++                    $this->proxy_port     = 443;
++                } else {
++                    $this->proxy = $match[2];
++                    if ($proxy_port) {
++                        $this->proxy_port = $proxy_port;
++                    }
++                }
++            } elseif ($match[1] == 'http://') {
++                $this->proxy = $match[2];
++                if ($proxy_port) {
++                    $this->proxy_port = $proxy_port;
++                }
++            } else {
++                $this->proxy          = $match[2];
++                $this->proxy_protocol = 'ssl://';
++                if ($proxy_port) {
++                    $this->proxy_port = $proxy_port;
++                } else {
++                    $this->proxy_port = 443;
++                }
++            }
++        }
++    }
++
++    /**
++     * Change the current debug mode
++     *
++     * @param int $in  where 1 = on, 0 = off
++     *
++     * @return void
++     */
++    function setDebug($in)
++    {
++        if ($in) {
++            $this->debug = 1;
++        } else {
++            $this->debug = 0;
++        }
++    }
++
++    /**
++     * Set username and password properties for connecting to the RPC server
++     *
++     * @param string $u  the user name
++     * @param string $p  the password
++     *
++     * @return void
++     *
++     * @see XML_RPC_Client::$username, XML_RPC_Client::$password
++     */
++    function setCredentials($u, $p)
++    {
++        $this->username = $u;
++        $this->password = $p;
++    }
++
++    /**
++     * Transmit the RPC request via HTTP 1.0 protocol
++     *
++     * @param object $msg       the XML_RPC_Message object
++     * @param int    $timeout   how many seconds to wait for the request
++     *
++     * @return object  an XML_RPC_Response object.  0 is returned if any
++     *                  problems happen.
++     *
++     * @see XML_RPC_Message, XML_RPC_Client::XML_RPC_Client(),
++     *      XML_RPC_Client::setCredentials()
++     */
++    function send($msg, $timeout = 0)
++    {
++        if (strtolower(get_class($msg)) != 'xml_rpc_message') {
++            $this->errstr = 'send()\'s $msg parameter must be an'
++                          . ' XML_RPC_Message object.';
++            $this->raiseError($this->errstr, XML_RPC_ERROR_PROGRAMMING);
++            return 0;
++        }
++        $msg->debug = $this->debug;
++        return $this->sendPayloadHTTP10($msg, $this->server, $this->port,
++                                        $timeout, $this->username,
++                                        $this->password);
++    }
++
++    /**
++     * Transmit the RPC request via HTTP 1.0 protocol
++     *
++     * Requests should be sent using XML_RPC_Client send() rather than
++     * calling this method directly.
++     *
++     * @param object $msg       the XML_RPC_Message object
++     * @param string $server    the server to send the request to
++     * @param int    $port      the server port send the request to
++     * @param int    $timeout   how many seconds to wait for the request
++     *                           before giving up
++     * @param string $username  a user name for accessing the RPC server
++     * @param string $password  a password for accessing the RPC server
++     *
++     * @return object  an XML_RPC_Response object.  0 is returned if any
++     *                  problems happen.
++     *
++     * @access protected
++     * @see XML_RPC_Client::send()
++     */
++    function sendPayloadHTTP10($msg, $server, $port, $timeout = 0,
++                               $username = '', $password = '')
++    {
++        /*
++         * If we're using a proxy open a socket to the proxy server
++         * instead to the xml-rpc server
++         */
++        if ($this->proxy) {
++            if ($this->proxy_protocol == 'http://') {
++                $protocol = '';
++            } else {
++                $protocol = $this->proxy_protocol;
++            }
++            if ($timeout > 0) {
++                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
++                                 $this->errno, $this->errstr, $timeout);
++            } else {
++                $fp = @fsockopen($protocol . $this->proxy, $this->proxy_port,
++                                 $this->errno, $this->errstr);
++            }
++        } else {
++            if ($this->protocol == 'http://') {
++                $protocol = '';
++            } else {
++                $protocol = $this->protocol;
++            }
++            if ($timeout > 0) {
++                $fp = @fsockopen($protocol . $server, $port,
++                                 $this->errno, $this->errstr, $timeout);
++            } else {
++                $fp = @fsockopen($protocol . $server, $port,
++                                 $this->errno, $this->errstr);
++            }
++        }
++
++        /*
++         * Just raising the error without returning it is strange,
++         * but keep it here for backwards compatibility.
++         */
++        if (!$fp && $this->proxy) {
++            $this->raiseError('Connection to proxy server '
++                              . $this->proxy . ':' . $this->proxy_port
++                              . ' failed. ' . $this->errstr,
++                              XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        } elseif (!$fp) {
++            $this->raiseError('Connection to RPC server '
++                              . $server . ':' . $port
++                              . ' failed. ' . $this->errstr,
++                              XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        }
++
++        if ($timeout) {
++            /*
++             * Using socket_set_timeout() because stream_set_timeout()
++             * was introduced in 4.3.0, but we need to support 4.2.0.
++             */
++            socket_set_timeout($fp, $timeout);
++        }
++
++        // Pre-emptive BC hacks for fools calling sendPayloadHTTP10() directly
++        if ($username != $this->username) {
++            $this->setCredentials($username, $password);
++        }
++
++        // Only create the payload if it was not created previously
++        if (empty($msg->payload)) {
++            $msg->createPayload();
++        }
++        $this->createHeaders($msg);
++
++        $op  = $this->headers . "\r\n\r\n";
++        $op .= $msg->payload;
++
++        if (!fputs($fp, $op, strlen($op))) {
++            $this->errstr = 'Write error';
++            return 0;
++        }
++        $resp = $msg->parseResponseFile($fp);
++
++        $meta = socket_get_status($fp);
++        if ($meta['timed_out']) {
++            fclose($fp);
++            $this->errstr = 'RPC server did not send response before timeout.';
++            $this->raiseError($this->errstr, XML_RPC_ERROR_CONNECTION_FAILED);
++            return 0;
++        }
++
++        fclose($fp);
++        return $resp;
++    }
++
++    /**
++     * Determines the HTTP headers and puts it in the $headers property
++     *
++     * @param object $msg       the XML_RPC_Message object
++     *
++     * @return boolean  TRUE if okay, FALSE if the message payload isn't set.
++     *
++     * @access protected
++     */
++    function createHeaders($msg)
++    {
++        if (empty($msg->payload)) {
++            return false;
++        }
++        if ($this->proxy) {
++            $this->headers = 'POST ' . $this->protocol . $this->server;
++            if ($this->proxy_port) {
++                $this->headers .= ':' . $this->port;
++            }
++        } else {
++           $this->headers = 'POST ';
++        }
++        $this->headers .= $this->path. " HTTP/1.0\r\n";
++
++        $this->headers .= "User-Agent: PEAR XML_RPC\r\n";
++        $this->headers .= 'Host: ' . $this->server . "\r\n";
++
++        if ($this->proxy && $this->proxy_user) {
++            $this->headers .= 'Proxy-Authorization: Basic '
++                     . base64_encode("$this->proxy_user:$this->proxy_pass")
++                     . "\r\n";
++        }
++
++        // thanks to Grant Rauscher  for this
++        if ($this->username) {
++            $this->headers .= 'Authorization: Basic '
++                     . base64_encode("$this->username:$this->password")
++                     . "\r\n";
++        }
++
++        $this->headers .= "Content-Type: text/xml\r\n";
++        $this->headers .= 'Content-Length: ' . strlen($msg->payload);
++        return true;
++    }
++}
++
++/**
++ * The methods and properties for interpreting responses to XML RPC requests
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Response extends XML_RPC_Base
++{
++    var $xv;
++    var $fn;
++    var $fs;
++    var $hdrs;
++
++    /**
++     * @return void
++     */
++    function XML_RPC_Response($val, $fcode = 0, $fstr = '')
++    {
++        if ($fcode != 0) {
++            $this->fn = $fcode;
++            $this->fs = htmlspecialchars($fstr);
++        } else {
++            $this->xv = $val;
++        }
++    }
++
++    /**
++     * @return int  the error code
++     */
++    function faultCode()
++    {
++        if (isset($this->fn)) {
++            return $this->fn;
++        } else {
++            return 0;
++        }
++    }
++
++    /**
++     * @return string  the error string
++     */
++    function faultString()
++    {
++        return $this->fs;
++    }
++
++    /**
++     * @return mixed  the value
++     */
++    function value()
++    {
++        return $this->xv;
++    }
++
++    /**
++     * @return string  the error message in XML format
++     */
++    function serialize()
++    {
++        $rs = "\n";
++        if ($this->fn) {
++            $rs .= "
++  
++    
++      
++        faultCode
++        " . $this->fn . "
++      
++      
++        faultString
++        " . $this->fs . "
++      
++    
++  
++";
++        } else {
++            $rs .= "\n\n" . $this->xv->serialize() .
++        "\n";
++        }
++        $rs .= "\n";
++        return $rs;
++    }
++}
++
++/**
++ * The methods and properties for composing XML RPC messages
++ *
++ * @category   Web Services
++ * @package    XML_RPC
++ * @author     Edd Dumbill 
++ * @author     Stig Bakken 
++ * @author     Martin Jansen 
++ * @author     Daniel Convissor 
++ * @copyright  1999-2001 Edd Dumbill, 2001-2005 The PHP Group
++ * @version    Release: 1.4.0
++ * @link       http://pear.php.net/package/XML_RPC
++ */
++class XML_RPC_Message extends XML_RPC_Base
++{
++    /**
++     * The current debug mode (1 = on, 0 = off)
++     * @var integer
++     */
++    var $debug = 0;
++
++    /**
++     * The encoding to be used for outgoing messages
++     *
++     * Defaults to the value of $GLOBALS['XML_RPC_defencoding']
++     *
++     * @var string
++     * @see XML_RPC_Message::setSendEncoding(),
++     *      $GLOBALS['XML_RPC_defencoding'], XML_RPC_Message::xml_header()
++     */
++    var $send_encoding = '';
++
++    /**
++     * The method presently being evaluated
++     * @var string
++     */
++    var $methodname = '';
++
++    /**
++     * @var array
++     */
++    var $params = array();
++
++    /**
++     * The XML message being generated
++     * @var string
++     */
++    var $payload = '';
++
++    /**
++     * @return void
++     */
++    function XML_RPC_Message($meth, $pars = 0)
++    {
++        $this->methodname = $meth;
++        if (is_array($pars) && sizeof($pars) > 0) {
++            for ($i = 0; $i < sizeof($pars); $i++) {
++                $this->addParam($pars[$i]);
++            }
++        }
++    }
++
++    /**
++     * Produces the XML declaration including the encoding attribute
++     *
++     * The encoding is determined by this class' $send_encoding
++     * property.  If the $send_encoding property is not set, use
++     * $GLOBALS['XML_RPC_defencoding'].
++     *
++     * @return string  the XML declaration and  element
++     *
++     * @see XML_RPC_Message::setSendEncoding(),
++     *      XML_RPC_Message::$send_encoding, $GLOBALS['XML_RPC_defencoding']
++     */
++    function xml_header()
++    {
++        global $XML_RPC_defencoding;
++        if (!$this->send_encoding) {
++            $this->send_encoding = $XML_RPC_defencoding;
++        }
++        return 'send_encoding . '"?>'
++               . "\n\n";
++    }
++
++    /**
++     * @return string  the closing  tag
++     */
++    function xml_footer()
++    {
++        return "\n";
++    }
++
++    /**
++     * @return void
++     *
++     * @uses XML_RPC_Message::xml_header(), XML_RPC_Message::xml_footer()
++     */
++    function createPayload()
++    {
++        $this->payload = $this->xml_header();
++        $this->payload .= '' . $this->methodname . "\n";
++        $this->payload .= "\n";
++        for ($i = 0; $i < sizeof($this->params); $i++) {
++            $p = $this->params[$i];
++            $this->payload .= "\n" . $p->serialize() . "\n";
++        }
++        $this->payload .= "\n";
++        $this->payload .= $this->xml_footer();
++        $this->payload = ereg_replace("[\r\n]+", "\r\n", $this->payload);
++    }
++
++    /**
++     * @return string  the name of the method
++     */
++    function method($meth = '')
++    {
++        if ($meth != '') {
++            $this->methodname = $meth;
++        }
++        return $this->methodname;
++    }
++
++    /**
++     * @return string  the payload
++     */
++    function serialize()
++    {
++        $this->createPayload();
++        return $this->payload;
++    }
++
++    /**
++     * @return void
++     */
++    function addParam($par)
++    {
++        $this->params[] = $par;
++    }
++
++    /**
++     * Obtains an XML_RPC_Value object for the given parameter
++     *
++     * @param int $i  the index number of the parameter to obtain
++     *
++     * @return object  the XML_RPC_Value object.
++     *                  If the parameter doesn't exist, an XML_RPC_Response object.
++     *
++     * @since Returns XML_RPC_Response object on error since Release 1.3.0
++     */
++    function getParam($i)
++    {
++        global $XML_RPC_err, $XML_RPC_str;
++
++        if (isset($this->params[$i])) {
++            return $this->params[$i];
++        } else {
++            $this->raiseError('The submitted request did not contain this parameter',
++                              XML_RPC_ERROR_INCORRECT_PARAMS);
++            return new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'],
++                                        $XML_RPC_str['incorrect_params']);
++        }
++    }
++
++    /**
++     * @return int  the number of parameters
++     */
++    function getNumParams()
++    {
++        return sizeof($this->params);
++    }
++
++    /**
++     * Sets the XML declaration's encoding attribute
++     *
++     * @param string $type  the encoding type (ISO-8859-1, UTF-8 or US-ASCII)
++     *
++     * @return void
++     *
++     * @see XML_RPC_Message::$send_encoding, XML_RPC_Message::xml_header()
++     * @since Method available since Release 1.2.0
++     */
++    function setSendEncoding($type)
++    {
++        $this->send_encoding = $type;
++    }
++
++    /**
++     * Determine the XML's encoding via the encoding attribute
++     * in the XML declaration
++     *
++     * If the encoding parameter is not set or is not ISO-8859-1, UTF-8
++     * or US-ASCII, $XML_RPC_defencoding will be returned.
++     *
++     * @param string $data  the XML that will be parsed
++     *
++     * @return string  the encoding to be used
++     *
++     * @link   http://php.net/xml_parser_create
++     * @since  Method available since Release 1.2.0
++     */
++    function getEncoding($data)
++    {
++        global $XML_RPC_defencoding;
++
++        if (preg_match('/<\?xml[^>]*\s*encoding\s*=\s*[\'"]([^"\']*)[\'"]/i',
++                       $data, $match))
++        {
++            $match[1] = trim(strtoupper($match[1]));
++            switch ($match[1]) {
++                case 'ISO-8859-1':
++                case 'UTF-8':
++                case 'US-ASCII':
++                    return $match[1];
++                    break;
++
++                default:
++                    return $XML_RPC_defencoding;
++            }
++        } else {
++            return $XML_RPC_defencoding;
++        }
++    }
++
++    /**
++     * @return object  a new XML_RPC_Response object
++     */
++    function parseResponseFile($fp)
++    {
++        $ipd = '';
++        while ($data = @fread($fp, 8192)) {
++            $ipd .= $data;
++        }
++        return $this->parseResponse($ipd);
++    }
++
++    /**
++     * @return object  a new XML_RPC_Response object
++     */
++    function parseResponse($data = '')
++    {
++        global $XML_RPC_xh, $XML_RPC_err, $XML_RPC_str, $XML_RPC_defencoding;
++
++        $encoding = $this->getEncoding($data);
++        $parser_resource = xml_parser_create($encoding);
++        $parser = (int) $parser_resource;
++
++        $XML_RPC_xh = array();
++        $XML_RPC_xh[$parser] = array();
++
++        $XML_RPC_xh[$parser]['cm'] = 0;
++        $XML_RPC_xh[$parser]['isf'] = 0;
++        $XML_RPC_xh[$parser]['ac'] = '';
++        $XML_RPC_xh[$parser]['qt'] = '';
++        $XML_RPC_xh[$parser]['stack'] = array();
++        $XML_RPC_xh[$parser]['valuestack'] = array();
++
++        xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true);
++        xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee');
++        xml_set_character_data_handler($parser_resource, 'XML_RPC_cd');
++
++        $hdrfnd = 0;
++        if ($this->debug) {
++            print "\n
---GOT---\n";
++            print isset($_SERVER['SERVER_PROTOCOL']) ? htmlspecialchars($data) : $data;
++            print "\n---END---
\n"; ++ } ++ ++ // See if response is a 200 or a 100 then a 200, else raise error. ++ // But only do this if we're using the HTTP protocol. ++ if (ereg('^HTTP', $data) && ++ !ereg('^HTTP/[0-9\.]+ 200 ', $data) && ++ !preg_match('@^HTTP/[0-9\.]+ 10[0-9]([A-Za-z ]+)?[\r\n]+HTTP/[0-9\.]+ 200@', $data)) ++ { ++ $errstr = substr($data, 0, strpos($data, "\n") - 1); ++ error_log('HTTP error, got response: ' . $errstr); ++ $r = new XML_RPC_Response(0, $XML_RPC_err['http_error'], ++ $XML_RPC_str['http_error'] . ' (' . ++ $errstr . ')'); ++ xml_parser_free($parser_resource); ++ return $r; ++ } ++ ++ // gotta get rid of headers here ++ if (!$hdrfnd && ($brpos = strpos($data,"\r\n\r\n"))) { ++ $XML_RPC_xh[$parser]['ha'] = substr($data, 0, $brpos); ++ $data = substr($data, $brpos + 4); ++ $hdrfnd = 1; ++ } ++ ++ /* ++ * be tolerant of junk after methodResponse ++ * (e.g. javascript automatically inserted by free hosts) ++ * thanks to Luca Mariano ++ */ ++ $data = substr($data, 0, strpos($data, "") + 17); ++ ++ if (!xml_parse($parser_resource, $data, sizeof($data))) { ++ // thanks to Peter Kocks ++ if (xml_get_current_line_number($parser_resource) == 1) { ++ $errstr = 'XML error at line 1, check URL'; ++ } else { ++ $errstr = sprintf('XML error: %s at line %d', ++ xml_error_string(xml_get_error_code($parser_resource)), ++ xml_get_current_line_number($parser_resource)); ++ } ++ error_log($errstr); ++ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], ++ $XML_RPC_str['invalid_return']); ++ xml_parser_free($parser_resource); ++ return $r; ++ } ++ ++ xml_parser_free($parser_resource); ++ ++ if ($this->debug) { ++ print "\n
---PARSED---\n";
++            var_dump($XML_RPC_xh[$parser]['value']);
++            print "---END---
\n"; ++ } ++ ++ if ($XML_RPC_xh[$parser]['isf'] > 1) { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], ++ $XML_RPC_str['invalid_return'].' '.$XML_RPC_xh[$parser]['isf_reason']); ++ } elseif (!is_object($XML_RPC_xh[$parser]['value'])) { ++ // then something odd has happened ++ // and it's time to generate a client side error ++ // indicating something odd went on ++ $r = new XML_RPC_Response(0, $XML_RPC_err['invalid_return'], ++ $XML_RPC_str['invalid_return']); ++ } else { ++ $v = $XML_RPC_xh[$parser]['value']; ++ $allOK=1; ++ if ($XML_RPC_xh[$parser]['isf']) { ++ $f = $v->structmem('faultCode'); ++ $fs = $v->structmem('faultString'); ++ $r = new XML_RPC_Response($v, $f->scalarval(), ++ $fs->scalarval()); ++ } else { ++ $r = new XML_RPC_Response($v); ++ } ++ } ++ $r->hdrs = split("\r?\n", $XML_RPC_xh[$parser]['ha'][1]); ++ return $r; ++ } ++} ++ ++/** ++ * The methods and properties that represent data in XML RPC format ++ * ++ * @category Web Services ++ * @package XML_RPC ++ * @author Edd Dumbill ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version Release: 1.4.0 ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++class XML_RPC_Value extends XML_RPC_Base ++{ ++ var $me = array(); ++ var $mytype = 0; ++ ++ /** ++ * @return void ++ */ ++ function XML_RPC_Value($val = -1, $type = '') ++ { ++ global $XML_RPC_Types; ++ $this->me = array(); ++ $this->mytype = 0; ++ if ($val != -1 || $type != '') { ++ if ($type == '') { ++ $type = 'string'; ++ } ++ if (!array_key_exists($type, $XML_RPC_Types)) { ++ // XXX ++ // need some way to report this error ++ } elseif ($XML_RPC_Types[$type] == 1) { ++ $this->addScalar($val, $type); ++ } elseif ($XML_RPC_Types[$type] == 2) { ++ $this->addArray($val); ++ } elseif ($XML_RPC_Types[$type] == 3) { ++ $this->addStruct($val); ++ } ++ } ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addScalar($val, $type = 'string') ++ { ++ global $XML_RPC_Types, $XML_RPC_Boolean; ++ ++ if ($this->mytype == 1) { ++ $this->raiseError('Scalar can have only one value', ++ XML_RPC_ERROR_INVALID_TYPE); ++ return 0; ++ } ++ $typeof = $XML_RPC_Types[$type]; ++ if ($typeof != 1) { ++ $this->raiseError("Not a scalar type (${typeof})", ++ XML_RPC_ERROR_INVALID_TYPE); ++ return 0; ++ } ++ ++ if ($type == $XML_RPC_Boolean) { ++ if (strcasecmp($val, 'true') == 0 ++ || $val == 1 ++ || ($val == true && strcasecmp($val, 'false'))) ++ { ++ $val = 1; ++ } else { ++ $val = 0; ++ } ++ } ++ ++ if ($this->mytype == 2) { ++ // we're adding to an array here ++ $ar = $this->me['array']; ++ $ar[] = new XML_RPC_Value($val, $type); ++ $this->me['array'] = $ar; ++ } else { ++ // a scalar, so set the value and remember we're scalar ++ $this->me[$type] = $val; ++ $this->mytype = $typeof; ++ } ++ return 1; ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addArray($vals) ++ { ++ global $XML_RPC_Types; ++ if ($this->mytype != 0) { ++ $this->raiseError( ++ 'Already initialized as a [' . $this->kindOf() . ']', ++ XML_RPC_ERROR_ALREADY_INITIALIZED); ++ return 0; ++ } ++ $this->mytype = $XML_RPC_Types['array']; ++ $this->me['array'] = $vals; ++ return 1; ++ } ++ ++ /** ++ * @return int returns 1 if successful or 0 if there are problems ++ */ ++ function addStruct($vals) ++ { ++ global $XML_RPC_Types; ++ if ($this->mytype != 0) { ++ $this->raiseError( ++ 'Already initialized as a [' . $this->kindOf() . ']', ++ XML_RPC_ERROR_ALREADY_INITIALIZED); ++ return 0; ++ } ++ $this->mytype = $XML_RPC_Types['struct']; ++ $this->me['struct'] = $vals; ++ return 1; ++ } ++ ++ /** ++ * @return void ++ */ ++ function dump($ar) ++ { ++ reset($ar); ++ foreach ($ar as $key => $val) { ++ echo "$key => $val
"; ++ if ($key == 'array') { ++ foreach ($val as $key2 => $val2) { ++ echo "-- $key2 => $val2
"; ++ } ++ } ++ } ++ } ++ ++ /** ++ * @return string the data type of the current value ++ */ ++ function kindOf() ++ { ++ switch ($this->mytype) { ++ case 3: ++ return 'struct'; ++ ++ case 2: ++ return 'array'; ++ ++ case 1: ++ return 'scalar'; ++ ++ default: ++ return 'undef'; ++ } ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serializedata($typ, $val) ++ { ++ $rs = ''; ++ global $XML_RPC_Types, $XML_RPC_Base64, $XML_RPC_String, $XML_RPC_Boolean; ++ if (!array_key_exists($typ, $XML_RPC_Types)) { ++ // XXX ++ // need some way to report this error ++ return; ++ } ++ switch ($XML_RPC_Types[$typ]) { ++ case 3: ++ // struct ++ $rs .= "\n"; ++ reset($val); ++ foreach ($val as $key2 => $val2) { ++ $rs .= "${key2}\n"; ++ $rs .= $this->serializeval($val2); ++ $rs .= "\n"; ++ } ++ $rs .= ''; ++ break; ++ ++ case 2: ++ // array ++ $rs .= "\n\n"; ++ for ($i = 0; $i < sizeof($val); $i++) { ++ $rs .= $this->serializeval($val[$i]); ++ } ++ $rs .= "\n"; ++ break; ++ ++ case 1: ++ switch ($typ) { ++ case $XML_RPC_Base64: ++ $rs .= "<${typ}>" . base64_encode($val) . ""; ++ break; ++ case $XML_RPC_Boolean: ++ $rs .= "<${typ}>" . ($val ? '1' : '0') . ""; ++ break; ++ case $XML_RPC_String: ++ $rs .= "<${typ}>" . htmlspecialchars($val). ""; ++ break; ++ default: ++ $rs .= "<${typ}>${val}"; ++ } ++ } ++ return $rs; ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serialize() ++ { ++ return $this->serializeval($this); ++ } ++ ++ /** ++ * @return string the data in XML format ++ */ ++ function serializeval($o) ++ { ++ if (!is_object($o) || empty($o->me) || !is_array($o->me)) { ++ return ''; ++ } ++ $ar = $o->me; ++ reset($ar); ++ list($typ, $val) = each($ar); ++ return '' . $this->serializedata($typ, $val) . "\n"; ++ } ++ ++ /** ++ * @return mixed the contents of the element requested ++ */ ++ function structmem($m) ++ { ++ return $this->me['struct'][$m]; ++ } ++ ++ /** ++ * @return void ++ */ ++ function structreset() ++ { ++ reset($this->me['struct']); ++ } ++ ++ /** ++ * @return the key/value pair of the struct's current element ++ */ ++ function structeach() ++ { ++ return each($this->me['struct']); ++ } ++ ++ /** ++ * @return mixed the current value ++ */ ++ function getval() ++ { ++ // UNSTABLE ++ global $XML_RPC_BOOLEAN, $XML_RPC_Base64; ++ ++ reset($this->me); ++ $b = current($this->me); ++ ++ // contributed by I Sofer, 2001-03-24 ++ // add support for nested arrays to scalarval ++ // i've created a new method here, so as to ++ // preserve back compatibility ++ ++ if (is_array($b)) { ++ foreach ($b as $id => $cont) { ++ $b[$id] = $cont->scalarval(); ++ } ++ } ++ ++ // add support for structures directly encoding php objects ++ if (is_object($b)) { ++ $t = get_object_vars($b); ++ foreach ($t as $id => $cont) { ++ $t[$id] = $cont->scalarval(); ++ } ++ foreach ($t as $id => $cont) { ++ $b->$id = $cont; ++ } ++ } ++ ++ // end contrib ++ return $b; ++ } ++ ++ /** ++ * @return mixed ++ */ ++ function scalarval() ++ { ++ global $XML_RPC_Boolean, $XML_RPC_Base64; ++ reset($this->me); ++ return current($this->me); ++ } ++ ++ /** ++ * @return string ++ */ ++ function scalartyp() ++ { ++ global $XML_RPC_I4, $XML_RPC_Int; ++ reset($this->me); ++ $a = key($this->me); ++ if ($a == $XML_RPC_I4) { ++ $a = $XML_RPC_Int; ++ } ++ return $a; ++ } ++ ++ /** ++ * @return mixed the struct's current element ++ */ ++ function arraymem($m) ++ { ++ return $this->me['array'][$m]; ++ } ++ ++ /** ++ * @return int the number of elements in the array ++ */ ++ function arraysize() ++ { ++ reset($this->me); ++ list($a, $b) = each($this->me); ++ return sizeof($b); ++ } ++ ++ /** ++ * Determines if the item submitted is an XML_RPC_Value object ++ * ++ * @param mixed $val the variable to be evaluated ++ * ++ * @return bool TRUE if the item is an XML_RPC_Value object ++ * ++ * @static ++ * @since Method available since Release 1.3.0 ++ */ ++ function isValue($val) ++ { ++ return (strtolower(get_class($val)) == 'xml_rpc_value'); ++ } ++} ++ ++/** ++ * Return an ISO8601 encoded string ++ * ++ * While timezones ought to be supported, the XML-RPC spec says: ++ * ++ * "Don't assume a timezone. It should be specified by the server in its ++ * documentation what assumptions it makes about timezones." ++ * ++ * This routine always assumes localtime unless $utc is set to 1, in which ++ * case UTC is assumed and an adjustment for locale is made when encoding. ++ * ++ * @return string the formatted date ++ */ ++function XML_RPC_iso8601_encode($timet, $utc = 0) ++{ ++ if (!$utc) { ++ $t = strftime('%Y%m%dT%H:%M:%S', $timet); ++ } else { ++ if (function_exists('gmstrftime')) { ++ // gmstrftime doesn't exist in some versions ++ // of PHP ++ $t = gmstrftime('%Y%m%dT%H:%M:%S', $timet); ++ } else { ++ $t = strftime('%Y%m%dT%H:%M:%S', $timet - date('Z')); ++ } ++ } ++ return $t; ++} ++ ++/** ++ * Convert a datetime string into a Unix timestamp ++ * ++ * While timezones ought to be supported, the XML-RPC spec says: ++ * ++ * "Don't assume a timezone. It should be specified by the server in its ++ * documentation what assumptions it makes about timezones." ++ * ++ * This routine always assumes localtime unless $utc is set to 1, in which ++ * case UTC is assumed and an adjustment for locale is made when encoding. ++ * ++ * @return int the unix timestamp of the date submitted ++ */ ++function XML_RPC_iso8601_decode($idate, $utc = 0) ++{ ++ $t = 0; ++ if (ereg('([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})', $idate, $regs)) { ++ if ($utc) { ++ $t = gmmktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); ++ } else { ++ $t = mktime($regs[4], $regs[5], $regs[6], $regs[2], $regs[3], $regs[1]); ++ } ++ } ++ return $t; ++} ++ ++/** ++ * Converts an XML_RPC_Value object into native PHP types ++ * ++ * @param object $XML_RPC_val the XML_RPC_Value object to decode ++ * ++ * @return mixed the PHP values ++ */ ++function XML_RPC_decode($XML_RPC_val) ++{ ++ $kind = $XML_RPC_val->kindOf(); ++ ++ if ($kind == 'scalar') { ++ return $XML_RPC_val->scalarval(); ++ ++ } elseif ($kind == 'array') { ++ $size = $XML_RPC_val->arraysize(); ++ $arr = array(); ++ for ($i = 0; $i < $size; $i++) { ++ $arr[] = XML_RPC_decode($XML_RPC_val->arraymem($i)); ++ } ++ return $arr; ++ ++ } elseif ($kind == 'struct') { ++ $XML_RPC_val->structreset(); ++ $arr = array(); ++ while (list($key, $value) = $XML_RPC_val->structeach()) { ++ $arr[$key] = XML_RPC_decode($value); ++ } ++ return $arr; ++ } ++} ++ ++/** ++ * Converts native PHP types into an XML_RPC_Value object ++ * ++ * @param mixed $php_val the PHP value or variable you want encoded ++ * ++ * @return object the XML_RPC_Value object ++ */ ++function XML_RPC_encode($php_val) ++{ ++ global $XML_RPC_Boolean, $XML_RPC_Int, $XML_RPC_Double, $XML_RPC_String, ++ $XML_RPC_Array, $XML_RPC_Struct; ++ ++ $type = gettype($php_val); ++ $XML_RPC_val = new XML_RPC_Value; ++ ++ switch ($type) { ++ case 'array': ++ if (empty($php_val)) { ++ $XML_RPC_val->addArray($php_val); ++ break; ++ } ++ $tmp = array_diff(array_keys($php_val), range(0, count($php_val)-1)); ++ if (empty($tmp)) { ++ $arr = array(); ++ foreach ($php_val as $k => $v) { ++ $arr[$k] = XML_RPC_encode($v); ++ } ++ $XML_RPC_val->addArray($arr); ++ break; ++ } ++ // fall though if it's not an enumerated array ++ ++ case 'object': ++ $arr = array(); ++ foreach ($php_val as $k => $v) { ++ $arr[$k] = XML_RPC_encode($v); ++ } ++ $XML_RPC_val->addStruct($arr); ++ break; ++ ++ case 'integer': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Int); ++ break; ++ ++ case 'double': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Double); ++ break; ++ ++ case 'string': ++ case 'NULL': ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_String); ++ break; ++ ++ case 'boolean': ++ // Add support for encoding/decoding of booleans, since they ++ // are supported in PHP ++ // by ++ $XML_RPC_val->addScalar($php_val, $XML_RPC_Boolean); ++ break; ++ ++ case 'unknown type': ++ default: ++ $XML_RPC_val = false; ++ } ++ return $XML_RPC_val; ++} ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * c-hanging-comment-ender-p: nil ++ * End: ++ */ ++ ++?> ++XML_RPC-1.4.0/Server.php100666 0 0 51010 10277724745 7727 ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version CVS: $Id: Server.php,v 1.29 2005/08/14 20:25:35 danielc Exp $ ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++ ++ ++/** ++ * Pull in the XML_RPC class ++ */ ++require_once 'XML/RPC.php'; ++ ++ ++/** ++ * signature for system.listMethods: return = array, ++ * parameters = a string or nothing ++ * @global array $GLOBALS['XML_RPC_Server_listMethods_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_listMethods_sig'] = array( ++ array($GLOBALS['XML_RPC_Array'], ++ $GLOBALS['XML_RPC_String'] ++ ), ++ array($GLOBALS['XML_RPC_Array']) ++); ++ ++/** ++ * docstring for system.listMethods ++ * @global string $GLOBALS['XML_RPC_Server_listMethods_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_listMethods_doc'] = 'This method lists all the' ++ . ' methods that the XML-RPC server knows how to dispatch'; ++ ++/** ++ * signature for system.methodSignature: return = array, ++ * parameters = string ++ * @global array $GLOBALS['XML_RPC_Server_methodSignature_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_methodSignature_sig'] = array( ++ array($GLOBALS['XML_RPC_Array'], ++ $GLOBALS['XML_RPC_String'] ++ ) ++); ++ ++/** ++ * docstring for system.methodSignature ++ * @global string $GLOBALS['XML_RPC_Server_methodSignature_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_methodSignature_doc'] = 'Returns an array of known' ++ . ' signatures (an array of arrays) for the method name passed. If' ++ . ' no signatures are known, returns a none-array (test for type !=' ++ . ' array to detect missing signature)'; ++ ++/** ++ * signature for system.methodHelp: return = string, ++ * parameters = string ++ * @global array $GLOBALS['XML_RPC_Server_methodHelp_sig'] ++ */ ++$GLOBALS['XML_RPC_Server_methodHelp_sig'] = array( ++ array($GLOBALS['XML_RPC_String'], ++ $GLOBALS['XML_RPC_String'] ++ ) ++); ++ ++/** ++ * docstring for methodHelp ++ * @global string $GLOBALS['XML_RPC_Server_methodHelp_doc'] ++ */ ++$GLOBALS['XML_RPC_Server_methodHelp_doc'] = 'Returns help text if defined' ++ . ' for the method passed, otherwise returns an empty string'; ++ ++/** ++ * dispatch map for the automatically declared XML-RPC methods. ++ * @global array $GLOBALS['XML_RPC_Server_dmap'] ++ */ ++$GLOBALS['XML_RPC_Server_dmap'] = array( ++ 'system.listMethods' => array( ++ 'function' => 'XML_RPC_Server_listMethods', ++ 'signature' => $GLOBALS['XML_RPC_Server_listMethods_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_listMethods_doc'] ++ ), ++ 'system.methodHelp' => array( ++ 'function' => 'XML_RPC_Server_methodHelp', ++ 'signature' => $GLOBALS['XML_RPC_Server_methodHelp_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_methodHelp_doc'] ++ ), ++ 'system.methodSignature' => array( ++ 'function' => 'XML_RPC_Server_methodSignature', ++ 'signature' => $GLOBALS['XML_RPC_Server_methodSignature_sig'], ++ 'docstring' => $GLOBALS['XML_RPC_Server_methodSignature_doc'] ++ ) ++); ++ ++/** ++ * @global string $GLOBALS['XML_RPC_Server_debuginfo'] ++ */ ++$GLOBALS['XML_RPC_Server_debuginfo'] = ''; ++ ++ ++/** ++ * Lists all the methods that the XML-RPC server knows how to dispatch ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_listMethods($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $v = new XML_RPC_Value(); ++ $outAr = array(); ++ foreach ($server->dmap as $key => $val) { ++ $outAr[] = new XML_RPC_Value($key, 'string'); ++ } ++ foreach ($XML_RPC_Server_dmap as $key => $val) { ++ $outAr[] = new XML_RPC_Value($key, 'string'); ++ } ++ $v->addArray($outAr); ++ return new XML_RPC_Response($v); ++} ++ ++/** ++ * Returns an array of known signatures (an array of arrays) ++ * for the given method ++ * ++ * If no signatures are known, returns a none-array ++ * (test for type != array to detect missing signature) ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_methodSignature($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $methName = $m->getParam(0); ++ $methName = $methName->scalarval(); ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $server->dmap; ++ $sysCall = 0; ++ } ++ // print "\n"; ++ if (isset($dmap[$methName])) { ++ if ($dmap[$methName]['signature']) { ++ $sigs = array(); ++ $thesigs = $dmap[$methName]['signature']; ++ for ($i = 0; $i < sizeof($thesigs); $i++) { ++ $cursig = array(); ++ $inSig = $thesigs[$i]; ++ for ($j = 0; $j < sizeof($inSig); $j++) { ++ $cursig[] = new XML_RPC_Value($inSig[$j], 'string'); ++ } ++ $sigs[] = new XML_RPC_Value($cursig, 'array'); ++ } ++ $r = new XML_RPC_Response(new XML_RPC_Value($sigs, 'array')); ++ } else { ++ $r = new XML_RPC_Response(new XML_RPC_Value('undef', 'string')); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], ++ $XML_RPC_str['introspect_unknown']); ++ } ++ return $r; ++} ++ ++/** ++ * Returns help text if defined for the method passed, otherwise returns ++ * an empty string ++ * ++ * @return object a new XML_RPC_Response object ++ */ ++function XML_RPC_Server_methodHelp($server, $m) ++{ ++ global $XML_RPC_err, $XML_RPC_str, $XML_RPC_Server_dmap; ++ ++ $methName = $m->getParam(0); ++ $methName = $methName->scalarval(); ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $server->dmap; ++ $sysCall = 0; ++ } ++ ++ if (isset($dmap[$methName])) { ++ if ($dmap[$methName]['docstring']) { ++ $r = new XML_RPC_Response(new XML_RPC_Value($dmap[$methName]['docstring']), ++ 'string'); ++ } else { ++ $r = new XML_RPC_Response(new XML_RPC_Value('', 'string')); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['introspect_unknown'], ++ $XML_RPC_str['introspect_unknown']); ++ } ++ return $r; ++} ++ ++/** ++ * @return void ++ */ ++function XML_RPC_Server_debugmsg($m) ++{ ++ global $XML_RPC_Server_debuginfo; ++ $XML_RPC_Server_debuginfo = $XML_RPC_Server_debuginfo . $m . "\n"; ++} ++ ++ ++/** ++ * A server for receiving and replying to XML RPC requests ++ * ++ * ++ * $server = new XML_RPC_Server( ++ * array( ++ * 'isan8' => ++ * array( ++ * 'function' => 'is_8', ++ * 'signature' => ++ * array( ++ * array('boolean', 'int'), ++ * array('boolean', 'int', 'boolean'), ++ * array('boolean', 'string'), ++ * array('boolean', 'string', 'boolean'), ++ * ), ++ * 'docstring' => 'Is the value an 8?' ++ * ), ++ * ), ++ * 1, ++ * 0 ++ * ); ++ * ++ * ++ * @category Web Services ++ * @package XML_RPC ++ * @author Edd Dumbill ++ * @author Stig Bakken ++ * @author Martin Jansen ++ * @author Daniel Convissor ++ * @copyright 1999-2001 Edd Dumbill, 2001-2005 The PHP Group ++ * @version Release: 1.4.0 ++ * @link http://pear.php.net/package/XML_RPC ++ */ ++class XML_RPC_Server ++{ ++ /** ++ * The dispatch map, listing the methods this server provides. ++ * @var array ++ */ ++ var $dmap = array(); ++ ++ /** ++ * The present response's encoding ++ * @var string ++ * @see XML_RPC_Message::getEncoding() ++ */ ++ var $encoding = ''; ++ ++ /** ++ * Debug mode (0 = off, 1 = on) ++ * @var integer ++ */ ++ var $debug = 0; ++ ++ /** ++ * The response's HTTP headers ++ * @var string ++ */ ++ var $server_headers = ''; ++ ++ /** ++ * The response's XML payload ++ * @var string ++ */ ++ var $server_payload = ''; ++ ++ ++ /** ++ * Constructor for the XML_RPC_Server class ++ * ++ * @param array $dispMap the dispatch map. An associative array ++ * explaining each function. The keys of the main ++ * array are the procedure names used by the ++ * clients. The value is another associative array ++ * that contains up to three elements: ++ * + The 'function' element's value is the name ++ * of the function or method that gets called. ++ * To define a class' method: 'class::method'. ++ * + The 'signature' element (optional) is an ++ * array describing the return values and ++ * parameters ++ * + The 'docstring' element (optional) is a ++ * string describing what the method does ++ * @param int $serviceNow should the HTTP response be sent now? ++ * (1 = yes, 0 = no) ++ * @param int $debug should debug output be displayed? ++ * (1 = yes, 0 = no) ++ * ++ * @return void ++ */ ++ function XML_RPC_Server($dispMap, $serviceNow = 1, $debug = 0) ++ { ++ global $HTTP_RAW_POST_DATA; ++ ++ if ($debug) { ++ $this->debug = 1; ++ } else { ++ $this->debug = 0; ++ } ++ ++ $this->dmap = $dispMap; ++ ++ if ($serviceNow) { ++ $this->service(); ++ } else { ++ $this->createServerPayload(); ++ $this->createServerHeaders(); ++ } ++ } ++ ++ /** ++ * @return string the debug information if debug debug mode is on ++ */ ++ function serializeDebug() ++ { ++ global $XML_RPC_Server_debuginfo, $HTTP_RAW_POST_DATA; ++ ++ if ($this->debug) { ++ XML_RPC_Server_debugmsg('vvv POST DATA RECEIVED BY SERVER vvv' . "\n" ++ . $HTTP_RAW_POST_DATA ++ . "\n" . '^^^ END POST DATA ^^^'); ++ } ++ ++ if ($XML_RPC_Server_debuginfo != '') { ++ return "\n"; ++ } else { ++ return ''; ++ } ++ } ++ ++ /** ++ * Sends the response ++ * ++ * The encoding and content-type are determined by ++ * XML_RPC_Message::getEncoding() ++ * ++ * @return void ++ * ++ * @uses XML_RPC_Server::createServerPayload(), ++ * XML_RPC_Server::createServerHeaders() ++ */ ++ function service() ++ { ++ if (!$this->server_payload) { ++ $this->createServerPayload(); ++ } ++ if (!$this->server_headers) { ++ $this->createServerHeaders(); ++ } ++ header($this->server_headers); ++ print $this->server_payload; ++ } ++ ++ /** ++ * Generates the payload and puts it in the $server_payload property ++ * ++ * @return void ++ * ++ * @uses XML_RPC_Server::parseRequest(), XML_RPC_Server::$encoding, ++ * XML_RPC_Response::serialize(), XML_RPC_Server::serializeDebug() ++ */ ++ function createServerPayload() ++ { ++ $r = $this->parseRequest(); ++ $this->server_payload = 'encoding . '"?>' . "\n" ++ . $this->serializeDebug() ++ . $r->serialize(); ++ } ++ ++ /** ++ * Determines the HTTP headers and puts them in the $server_headers ++ * property ++ * ++ * @return boolean TRUE if okay, FALSE if $server_payload isn't set. ++ * ++ * @uses XML_RPC_Server::createServerPayload(), ++ * XML_RPC_Server::$server_headers ++ */ ++ function createServerHeaders() ++ { ++ if (!$this->server_payload) { ++ return false; ++ } ++ $this->server_headers = 'Content-Length: ' ++ . strlen($this->server_payload) . "\r\n" ++ . 'Content-Type: text/xml;' ++ . ' charset=' . $this->encoding; ++ return true; ++ } ++ ++ /** ++ * @return array ++ */ ++ function verifySignature($in, $sig) ++ { ++ for ($i = 0; $i < sizeof($sig); $i++) { ++ // check each possible signature in turn ++ $cursig = $sig[$i]; ++ if (sizeof($cursig) == $in->getNumParams() + 1) { ++ $itsOK = 1; ++ for ($n = 0; $n < $in->getNumParams(); $n++) { ++ $p = $in->getParam($n); ++ // print "\n"; ++ if ($p->kindOf() == 'scalar') { ++ $pt = $p->scalartyp(); ++ } else { ++ $pt = $p->kindOf(); ++ } ++ // $n+1 as first type of sig is return type ++ if ($pt != $cursig[$n+1]) { ++ $itsOK = 0; ++ $pno = $n+1; ++ $wanted = $cursig[$n+1]; ++ $got = $pt; ++ break; ++ } ++ } ++ if ($itsOK) { ++ return array(1); ++ } ++ } ++ } ++ if (isset($wanted)) { ++ return array(0, "Wanted ${wanted}, got ${got} at param ${pno}"); ++ } else { ++ $allowed = array(); ++ foreach ($sig as $val) { ++ end($val); ++ $allowed[] = key($val); ++ } ++ $allowed = array_unique($allowed); ++ $last = count($allowed) - 1; ++ if ($last > 0) { ++ $allowed[$last] = 'or ' . $allowed[$last]; ++ } ++ return array(0, ++ 'Signature permits ' . implode(', ', $allowed) ++ . ' parameters but the request had ' ++ . $in->getNumParams()); ++ } ++ } ++ ++ /** ++ * @return object a new XML_RPC_Response object ++ * ++ * @uses XML_RPC_Message::getEncoding(), XML_RPC_Server::$encoding ++ */ ++ function parseRequest($data = '') ++ { ++ global $XML_RPC_xh, $HTTP_RAW_POST_DATA, ++ $XML_RPC_err, $XML_RPC_str, $XML_RPC_errxml, ++ $XML_RPC_defencoding, $XML_RPC_Server_dmap; ++ ++ if ($data == '') { ++ $data = $HTTP_RAW_POST_DATA; ++ } ++ ++ $this->encoding = XML_RPC_Message::getEncoding($data); ++ $parser_resource = xml_parser_create($this->encoding); ++ $parser = (int) $parser_resource; ++ ++ $XML_RPC_xh[$parser] = array(); ++ $XML_RPC_xh[$parser]['cm'] = 0; ++ $XML_RPC_xh[$parser]['isf'] = 0; ++ $XML_RPC_xh[$parser]['params'] = array(); ++ $XML_RPC_xh[$parser]['method'] = ''; ++ $XML_RPC_xh[$parser]['stack'] = array(); ++ $XML_RPC_xh[$parser]['valuestack'] = array(); ++ ++ $plist = ''; ++ ++ // decompose incoming XML into request structure ++ ++ xml_parser_set_option($parser_resource, XML_OPTION_CASE_FOLDING, true); ++ xml_set_element_handler($parser_resource, 'XML_RPC_se', 'XML_RPC_ee'); ++ xml_set_character_data_handler($parser_resource, 'XML_RPC_cd'); ++ if (!xml_parse($parser_resource, $data, 1)) { ++ // return XML error as a faultCode ++ $r = new XML_RPC_Response(0, ++ $XML_RPC_errxml+xml_get_error_code($parser_resource), ++ sprintf('XML error: %s at line %d', ++ xml_error_string(xml_get_error_code($parser_resource)), ++ xml_get_current_line_number($parser_resource))); ++ xml_parser_free($parser_resource); ++ } elseif ($XML_RPC_xh[$parser]['isf']>1) { ++ $r = new XML_RPC_Response(0, ++ $XML_RPC_err['invalid_request'], ++ $XML_RPC_str['invalid_request'] ++ . ': ' ++ . $XML_RPC_xh[$parser]['isf_reason']); ++ xml_parser_free($parser_resource); ++ } else { ++ xml_parser_free($parser_resource); ++ $m = new XML_RPC_Message($XML_RPC_xh[$parser]['method']); ++ // now add parameters in ++ for ($i = 0; $i < sizeof($XML_RPC_xh[$parser]['params']); $i++) { ++ // print '\n"; ++ $plist .= "$i - " . var_export($XML_RPC_xh[$parser]['params'][$i], true) . " \n"; ++ $m->addParam($XML_RPC_xh[$parser]['params'][$i]); ++ } ++ XML_RPC_Server_debugmsg($plist); ++ ++ // now to deal with the method ++ $methName = $XML_RPC_xh[$parser]['method']; ++ if (strpos($methName, 'system.') === 0) { ++ $dmap = $XML_RPC_Server_dmap; ++ $sysCall = 1; ++ } else { ++ $dmap = $this->dmap; ++ $sysCall = 0; ++ } ++ ++ if (isset($dmap[$methName]['function']) ++ && is_string($dmap[$methName]['function']) ++ && strpos($dmap[$methName]['function'], '::') !== false) ++ { ++ $dmap[$methName]['function'] = ++ explode('::', $dmap[$methName]['function']); ++ } ++ ++ if (isset($dmap[$methName]['function']) ++ && is_callable($dmap[$methName]['function'])) ++ { ++ // dispatch if exists ++ if (isset($dmap[$methName]['signature'])) { ++ $sr = $this->verifySignature($m, ++ $dmap[$methName]['signature'] ); ++ } ++ if (!isset($dmap[$methName]['signature']) || $sr[0]) { ++ // if no signature or correct signature ++ if ($sysCall) { ++ $r = call_user_func($dmap[$methName]['function'], $this, $m); ++ } else { ++ $r = call_user_func($dmap[$methName]['function'], $m); ++ } ++ if (!is_a($r, 'XML_RPC_Response')) { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['not_response_object'], ++ $XML_RPC_str['not_response_object']); ++ } ++ } else { ++ $r = new XML_RPC_Response(0, $XML_RPC_err['incorrect_params'], ++ $XML_RPC_str['incorrect_params'] ++ . ': ' . $sr[1]); ++ } ++ } else { ++ // else prepare error response ++ $r = new XML_RPC_Response(0, $XML_RPC_err['unknown_method'], ++ $XML_RPC_str['unknown_method']); ++ } ++ } ++ return $r; ++ } ++ ++ /** ++ * Echos back the input packet as a string value ++ * ++ * @return void ++ * ++ * Useful for debugging. ++ */ ++ function echoInput() ++ { ++ global $HTTP_RAW_POST_DATA; ++ ++ $r = new XML_RPC_Response(0); ++ $r->xv = new XML_RPC_Value("'Aha said I: '" . $HTTP_RAW_POST_DATA, 'string'); ++ print $r->serialize(); ++ } ++} ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * c-hanging-comment-ender-p: nil ++ * End: ++ */ ++ ++?> ++package.xml100666 0 0 25606 10277724746 6300 ++ ++ ++ XML_RPC ++ PHP implementation of the XML-RPC protocol ++ A PEAR-ified version of Useful Inc's XML-RPC for PHP. ++ ++It has support for HTTP/HTTPS transport, proxies and authentication. ++ ++ ++ ++ ssb ++ Stig Bakken ++ stig@php.net ++ lead ++ ++ ++ danielc ++ Daniel Convissor ++ danielc@php.net ++ lead ++ ++ ++ ++ 1.4.0 ++ 2005-08-14 ++ PHP License ++ stable ++ * MAJOR SECURITY FIX: eliminate use of eval(). ++* Using socket_get_status() because stream_get_meta_data() was introduced in 4.3.0, but we need to support 4.2.0. Bug 4805. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 1.3.3 ++ 2005-07-15 ++ stable ++ * Eliminate memory leak by resetting $XML_RPC_xh each time parseResponse() is called. Bug 4780. ++* Using socket_set_timeout() because stream_set_timeout() was introduced in 4.3.0, but we need to support 4.2.0. Bug 4805. ++ ++ ++ ++ 1.3.2 ++ 2005-07-07 ++ stable ++ * Eliminate path disclosure vulnerabilities by suppressing error messages when eval()'ing. ++* Eliminate path disclosure vulnerability by catching bogus parameters submitted to XML_RPC_Value::serializeval(). ++* In XML_RPC_Server::service(), only call createServerPayload() and createServerHeaders() if necessary. Fixes compatibility issue introduced in Release 1.3.0RC1 for users who set the $serviceNow parameter of XML_RPC_Server() to 0. Bug 4757. ++* Change "var $errstring" to "var $errstr". Bug 4582. Was put into CVS version 1.75 of RPC.php but didn't make it into RELEASE_1_3_1. ++ ++ ++ ++ 1.3.1 ++ 2005-06-29 ++ stable ++ * Security fix. Update highly recommended! ++ ++ ++ ++ 1.3.0 ++ 2005-06-13 ++ stable ++ * Stable release. See earlier releases for changes since 1.2.2. ++ ++ ++ ++ 1.3.0RC3 ++ 2005-05-10 ++ beta ++ * When verifying requests against function signatures, if the number of parameters don't match, provide an appropriate message. NOTE: this resolves a path disclosure vulnerability. (Refines the changes made in the last commit.) Bug 4231. ++* XML_RPC_Message::getParam() now returns an XML_RPC_Response object upon error. Changed from Release 1.3.0RC2. ++* Add the XML_RPC_Value::isValue() method. For testing if an item is an XML_RPC_Value object. ++* If XML_RPC_Client::send() is given an incorrect $msg parameter, raise an error with the new XML_RPC_ERROR_PROGRAMMING code and return 0. ++* Improve cross-platform operation by using PEAR::loadExtension() instead of dl(). ++* Use <br /> instead of <br> in XML_RPC_Value::dump(). ++ ++ ++ ++ 1.3.0RC2 ++ 2005-05-05 ++ beta ++ * If XML_RPC_Message::getParam() is given an incorrect parameter, raise an error with the new XML_RPC_ERROR_INCORRECT_PARAMS code and return FALSE. ++* Handle improper requests to XML_RPC_Server::verifySignature(). Bug 4231. ++* Try to allow HTTP 100 responses if followed by a 200 response. Bug 4116. ++* Help Delphi users by making RPCMETHODNAME an alias for METHODNAME. Request 4205. ++ ++ ++ ++ 1.3.0RC1 ++ 2005-04-07 ++ beta ++ * Improve timeout handling for situations where connection to server is made but no response is not received in time. Accomplished via stream_set_timeout(). Request 3963. ++* Add Fault Code 6: "The requested method didn't return an XML_RPC_Response object." Request 4032. ++* Add the createServerPayload() and createServerHeaders() methods and the $server_payload and $server_headers properties. Request 3121. ++* As in earlier versions, if the $serviceNow parameter to XML_RPC_Server() is 0, no data will be returned, but now the new $server_payload and $server_headers properties will be set. ++* Convert the parser handle to an integer before using it as an index for $XML_RPC_xh[$parser]. Reduces E_STRICT notices. Bug 3782. ++* Add createHeaders() method and $headers property to XML_RPC_Client to make testing easier. ++ ++ ++ ++ 1.2.2 ++ 2005-03-07 ++ stable ++ * When using a proxy, add the protocol to the Request-URI, making it an "absoluteURI" as per the HTTP 1.0 spec. Bug 3679. ++ ++ ++ ++ 1.2.1 ++ 2005-03-01 ++ stable ++ * Add isset() check before examining the dispatch map. Bug 3658. ++ ++ ++ ++ 1.2.0 ++ 2005-02-27 ++ stable ++ * Provide the "stable" release. ++* Add package2.xml for compatibility with PEAR 1.4.0. ++* For changes since 1.1.0, see the changelogs for the various RC releases. ++ ++ ++ ++ 1.2.0RC7 ++ 2005-02-22 ++ beta ++ * Add the setSendEncoding() method and $send_encoding ++ property to XML_RPC_Message. Request 3537. ++* Allow class methods to be mapped using either syntax: ++ 'function' => 'hello::sayHello', ++ or ++ 'function' => array('hello', 'sayhello'), ++ Bug 3363. ++* Use 8192 instead of 32768 for bytes in fread() ++ in parseResponseFile(). Bug 3340. ++ ++ ++ ++ 1.2.0RC6 ++ 2005-01-25 ++ beta ++ * Don't put the protocol in the Host field of the POST data. (danielc) ++ ++ ++ ++ 1.2.0RC5 ++ 2005-01-24 ++ beta ++ * If $port is 443 but a protocol isn't specified in $server, assume ssl:// is the protocol. ++ ++ ++ ++ 1.2.0RC4 ++ 2005-01-24 ++ beta ++ * When a connection attempt fails, have the method return 0. (danielc) ++* Move the protocol/port checking/switching and the property settings from sendPayloadHTTP10() to the XML_RPC_Client constructor. (danielc) ++* Add tests for setting the client properties. (danielc) ++* Remove $GLOBALS['XML_RPC_twoslash'] since it's not used. (danielc) ++* Bundle the tests with the package. (danielc) ++ ++ ++ ++ 1.2.0RC3 ++ 2005-01-19 ++ beta ++ * ssl uses port 443, not 445. ++ ++ ++ ++ 1.2.0RC2 ++ 2005-01-11 ++ beta ++ * Handle ssl:// in the $server string. (danielc) ++* Also default to port 445 for ssl:// requests as well. (danielc) ++* Enhance debugging in the server. (danielc) ++ ++ ++ ++ 1.2.0RC1 ++ 2004-12-30 ++ beta ++ * Make things work with SSL. Bug 2489. (nkukard lbsd net) ++* Allow array function callbacks (Matt Kane) ++* Some minor speed-ups (Matt Kane) ++* Add Dump.php to the package (Christian Weiske) ++* Replace all line endings with \r\n. Had only done replacements on \n. Bug 2521. (danielc) ++* Silence fsockopen() errors. Bug 1714. (danielc) ++* Encode empty arrays as an array. Bug 1493. (danielc) ++* Eliminate undefined index notice when submitting empty arrays to XML_RPC_Encode(). Bug 1819. (danielc) ++* Speed up check for enumerated arrays in XML_RPC_Encode(). (danielc) ++* Prepend "XML_RPC_" to ERROR_NON_NUMERIC_FOUND, eliminating problem when eval()'ing error messages. (danielc) ++* Use XML_RPC_Base::raiseError() instead of PEAR::raiseError() in XML_RPC_ee() because PEAR.php is lazy loaded. (danielc) ++* Allow raiseError() to be called statically. (danielc) ++* Stop double escaping of character entities. Bug 987. (danielc) ++ NOTICE: the following have been removed: ++ * XML_RPC_dh() ++ * $GLOBALS['XML_RPC_entities'] ++ * XML_RPC_entity_decode() ++ * XML_RPC_lookup_entity() ++* Determine the XML's encoding via the encoding attribute in the XML declaration. Bug 52. (danielc) ++ ++ ++ ++ 1.1.0 ++ 2004-03-15 ++ stable ++ * Added support for sequential arrays to XML_RPC_encode() (mroch) ++* Cleaned up new XML_RPC_encode() changes a bit (mroch, pierre) ++* Remove "require_once 'PEAR.php'", include only when needed to raise an error ++* Replace echo and error_log() with raiseError() (mroch) ++* Make all classes extend XML_RPC_Base, which will handle common functions (mroch) ++* be tolerant of junk after methodResponse (Luca Mariano, mroch) ++* Silent notice even in the error log (pierre) ++* fix include of shared xml extension on win32 (pierre) ++ ++ ++ ++ 1.0.4 ++ 2002-10-02 ++ stable ++ * added HTTP proxy authorization support (thanks to Arnaud Limbourg) ++ ++ ++ ++ 1.0.3 ++ 2002-05-19 ++ stable ++ * fix bug when parsing responses with boolean types ++ ++ ++ ++ 1.0.2 ++ 2002-04-16 ++ stable ++ * E_ALL fixes ++* fix HTTP response header parsing ++ ++ ++ ++ 1.0.1 ++ 2001-09-25 ++ stable ++ This is a PEAR-ified version of Useful Inc's 1.0.1 release. ++Includes an urgent security fix identified by Dan Libby <dan@libby.com>. ++ ++ ++ ++ ++ +\ Kein Zeilenumbruch am Dateiende. +diff -Nura php-4.4.0/php.ini-dist hardening-patch-4.4.0-0.4.3/php.ini-dist +--- php-4.4.0/php.ini-dist 2005-04-28 15:14:45.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/php.ini-dist 2005-09-12 23:44:36.000000000 +0200 +@@ -1112,6 +1112,197 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's Executor options ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++; White-/blacklist for function calls during normal execution ++;hphp.executor.func.whitelist = ord,chr ++;hphp.executor.func.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for function calls during eval() execution ++;hphp.executor.eval.whitelist = ord,chr ++;hphp.executor.eval.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for URLs allowes in include filenames ++; ++; - When both options are not set all URLs are forbidden ++; ++; - When both options are set whitelist is taken and blacklist ignored ++; ++; - An entry in the lists is either a URL sheme like: http, https ++; or the beginning of an URL like: php://input ++; ++;hphp.executor.include.whitelist = cookietest ++;hphp.executor.include.blacklist = http, https, ftp, ftps, php://input, file ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nura php-4.4.0/php.ini-recommended hardening-patch-4.4.0-0.4.3/php.ini-recommended +--- php-4.4.0/php.ini-recommended 2005-04-28 15:14:46.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/php.ini-recommended 2005-09-12 23:45:36.000000000 +0200 +@@ -1110,6 +1110,197 @@ + ;exif.decode_jis_motorola = JIS + ;exif.decode_jis_intel = JIS + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's Executor options ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++; White-/blacklist for function calls during normal execution ++;hphp.executor.func.whitelist = ord,chr ++;hphp.executor.func.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for function calls during eval() execution ++;hphp.executor.eval.whitelist = ord,chr ++;hphp.executor.eval.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for URLs allowes in include filenames ++; ++; - When both options are not set all URLs are forbidden ++; ++; - When both options are set whitelist is taken and blacklist ignored ++; ++; - An entry in the lists is either a URL sheme like: http, https ++; or the beginning of an URL like: php://input ++; ++;hphp.executor.include.whitelist = cookietest ++;hphp.executor.include.blacklist = http, https, ftp, ftps, php://input, file ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nura php-4.4.0/README.input_filter hardening-patch-4.4.0-0.4.3/README.input_filter +--- php-4.4.0/README.input_filter 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/README.input_filter 2005-09-11 23:31:08.000000000 +0200 +@@ -0,0 +1,193 @@ ++Input Filter Support ported from PHP 5 ++-------------------------------------- ++ ++XSS (Cross Site Scripting) hacks are becoming more and more prevalent, ++and can be quite difficult to prevent. Whenever you accept user data ++and somehow display this data back to users, you are likely vulnerable ++to XSS hacks. ++ ++The Input Filter support in PHP 5 is aimed at providing the framework ++through which a company-wide or site-wide security policy can be ++enforced. It is implemented as a SAPI hook and is called from the ++treat_data and post handler functions. To implement your own security ++policy you will need to write a standard PHP extension. ++ ++A simple implementation might look like the following. This stores the ++original raw user data and adds a my_get_raw() function while the normal ++$_POST, $_GET and $_COOKIE arrays are only populated with stripped ++data. In this simple example all I am doing is calling strip_tags() on ++the data. If register_globals is turned on, the default globals that ++are created will be stripped ($foo) while a $RAW_foo is created with the ++original user input. ++ ++ZEND_BEGIN_MODULE_GLOBALS(my_input_filter) ++ zval *post_array; ++ zval *get_array; ++ zval *cookie_array; ++ZEND_END_MODULE_GLOBALS(my_input_filter) ++ ++#ifdef ZTS ++#define IF_G(v) TSRMG(my_input_filter_globals_id, zend_my_input_filter_globals *, v) ++#else ++#define IF_G(v) (my_input_filter_globals.v) ++#endif ++ ++ZEND_DECLARE_MODULE_GLOBALS(my_input_filter) ++ ++function_entry my_input_filter_functions[] = { ++ PHP_FE(my_get_raw, NULL) ++ {NULL, NULL, NULL} ++}; ++ ++zend_module_entry my_input_filter_module_entry = { ++ STANDARD_MODULE_HEADER, ++ "my_input_filter", ++ my_input_filter_functions, ++ PHP_MINIT(my_input_filter), ++ PHP_MSHUTDOWN(my_input_filter), ++ NULL, ++ PHP_RSHUTDOWN(my_input_filter), ++ PHP_MINFO(my_input_filter), ++ "0.1", ++ STANDARD_MODULE_PROPERTIES ++}; ++ ++PHP_MINIT_FUNCTION(my_input_filter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(my_input_filter, php_my_input_filter_init_globals, NULL); ++ ++ REGISTER_LONG_CONSTANT("POST", PARSE_POST, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("GET", PARSE_GET, CONST_CS | CONST_PERSISTENT); ++ REGISTER_LONG_CONSTANT("COOKIE", PARSE_COOKIE, CONST_CS | CONST_PERSISTENT); ++ ++ sapi_register_input_filter(my_sapi_input_filter); ++ return SUCCESS; ++} ++ ++PHP_RSHUTDOWN_FUNCTION(my_input_filter) ++{ ++ if(IF_G(get_array)) { ++ zval_ptr_dtor(&IF_G(get_array)); ++ IF_G(get_array) = NULL; ++ } ++ if(IF_G(post_array)) { ++ zval_ptr_dtor(&IF_G(post_array)); ++ IF_G(post_array) = NULL; ++ } ++ if(IF_G(cookie_array)) { ++ zval_ptr_dtor(&IF_G(cookie_array)); ++ IF_G(cookie_array) = NULL; ++ } ++ return SUCCESS; ++} ++ ++PHP_MINFO_FUNCTION(my_input_filter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_row( 2, "My Input Filter Support", "enabled" ); ++ php_info_print_table_row( 2, "Revision", "$Revision: 1.1 $"); ++ php_info_print_table_end(); ++} ++ ++/* The filter handler. If you return 1 from it, then PHP also registers the ++ * (modified) variable. Returning 0 prevents PHP from registering the variable; ++ * you can use this if your filter already registers the variable under a ++ * different name, or if you just don't want the variable registered at all. */ ++SAPI_INPUT_FILTER_FUNC(my_sapi_input_filter) ++{ ++ zval new_var; ++ zval *array_ptr = NULL; ++ char *raw_var; ++ int var_len; ++ ++ assert(*val != NULL); ++ ++ switch(arg) { ++ case PARSE_GET: ++ if(!IF_G(get_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(get_array) = array_ptr; ++ break; ++ case PARSE_POST: ++ if(!IF_G(post_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(post_array) = array_ptr; ++ break; ++ case PARSE_COOKIE: ++ if(!IF_G(cookie_array)) { ++ ALLOC_ZVAL(array_ptr); ++ array_init(array_ptr); ++ INIT_PZVAL(array_ptr); ++ } ++ IF_G(cookie_array) = array_ptr; ++ break; ++ } ++ Z_STRLEN(new_var) = val_len; ++ Z_STRVAL(new_var) = estrndup(*val, val_len); ++ Z_TYPE(new_var) = IS_STRING; ++ ++ var_len = strlen(var); ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ ++ php_register_variable_ex(raw_var, &new_var, array_ptr TSRMLS_DC); ++ ++ php_strip_tags(*val, val_len, NULL, NULL, 0); ++ ++ *new_val_len = strlen(*val); ++ return 1; ++} ++ ++PHP_FUNCTION(my_get_raw) ++{ ++ long arg; ++ char *var; ++ int var_len; ++ zval **tmp; ++ zval *array_ptr = NULL; ++ HashTable *hash_ptr; ++ char *raw_var; ++ ++ if(zend_parse_parameters(2 TSRMLS_CC, "ls", &arg, &var, &var_len) == FAILURE) { ++ return; ++ } ++ ++ switch(arg) { ++ case PARSE_GET: ++ array_ptr = IF_G(get_array); ++ break; ++ case PARSE_POST: ++ array_ptr = IF_G(post_array); ++ break; ++ case PARSE_COOKIE: ++ array_ptr = IF_G(post_array); ++ break; ++ } ++ ++ if(!array_ptr) RETURN_FALSE; ++ ++ /* ++ * I'm changing the variable name here because when running with register_globals on, ++ * the variable will end up in the global symbol table ++ */ ++ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */ ++ strcpy(raw_var, "RAW_"); ++ strlcat(raw_var,var,var_len+5); ++ hash_ptr = HASH_OF(array_ptr); ++ ++ if(zend_hash_find(hash_ptr, raw_var, var_len+5, (void **)&tmp) == SUCCESS) { ++ *return_value = **tmp; ++ zval_copy_ctor(return_value); ++ } else { ++ RETVAL_FALSE; ++ } ++ efree(raw_var); ++} ++ +diff -Nura php-4.4.0/sapi/apache/mod_php4.c hardening-patch-4.4.0-0.4.3/sapi/apache/mod_php4.c +--- php-4.4.0/sapi/apache/mod_php4.c 2005-05-19 18:14:46.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/sapi/apache/mod_php4.c 2005-09-11 23:31:08.000000000 +0200 +@@ -452,7 +452,7 @@ + sapi_apache_get_fd, + sapi_apache_force_http_10, + sapi_apache_get_target_uid, +- sapi_apache_get_target_gid ++ sapi_apache_get_target_gid, + }; + /* }}} */ + +@@ -898,7 +898,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component("PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component("PHP/" PHP_VERSION); ++#endif + } + } + #endif +diff -Nura php-4.4.0/sapi/apache2filter/sapi_apache2.c hardening-patch-4.4.0-0.4.3/sapi/apache2filter/sapi_apache2.c +--- php-4.4.0/sapi/apache2filter/sapi_apache2.c 2005-04-08 22:35:02.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/sapi/apache2filter/sapi_apache2.c 2005-09-11 23:31:08.000000000 +0200 +@@ -556,7 +556,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nura php-4.4.0/sapi/apache2handler/sapi_apache2.c hardening-patch-4.4.0-0.4.3/sapi/apache2handler/sapi_apache2.c +--- php-4.4.0/sapi/apache2handler/sapi_apache2.c 2005-04-08 22:35:02.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/sapi/apache2handler/sapi_apache2.c 2005-09-11 23:31:08.000000000 +0200 +@@ -340,7 +340,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nura php-4.4.0/sapi/cgi/cgi_main.c hardening-patch-4.4.0-0.4.3/sapi/cgi/cgi_main.c +--- php-4.4.0/sapi/cgi/cgi_main.c 2005-04-28 16:24:47.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/sapi/cgi/cgi_main.c 2005-09-11 23:31:08.000000000 +0200 +@@ -1440,11 +1440,19 @@ + SG(headers_sent) = 1; + SG(request_info).no_headers = 1; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit(1); + break; +diff -Nura php-4.4.0/sapi/cli/php_cli.c hardening-patch-4.4.0-0.4.3/sapi/cli/php_cli.c +--- php-4.4.0/sapi/cli/php_cli.c 2005-03-22 16:09:36.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/sapi/cli/php_cli.c 2005-09-11 23:31:08.000000000 +0200 +@@ -652,11 +652,19 @@ + if (php_request_startup(TSRMLS_C)==FAILURE) { + goto err; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit_status=1; + goto out; +diff -Nura php-4.4.0/TSRM/TSRM.h hardening-patch-4.4.0-0.4.3/TSRM/TSRM.h +--- php-4.4.0/TSRM/TSRM.h 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/TSRM/TSRM.h 2005-09-11 23:31:08.000000000 +0200 +@@ -33,6 +33,13 @@ + # define TSRM_API + #endif + ++#if HARDENING_PATCH ++# if HAVE_REALPATH ++# undef realpath ++# define realpath php_realpath ++# endif ++#endif ++ + /* Only compile multi-threading functions if we're in ZTS mode */ + #ifdef ZTS + +@@ -90,6 +97,7 @@ + + #define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts + ++ + #ifdef __cplusplus + extern "C" { + #endif +diff -Nura php-4.4.0/TSRM/tsrm_virtual_cwd.c hardening-patch-4.4.0-0.4.3/TSRM/tsrm_virtual_cwd.c +--- php-4.4.0/TSRM/tsrm_virtual_cwd.c 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/TSRM/tsrm_virtual_cwd.c 2005-09-11 23:31:08.000000000 +0200 +@@ -192,6 +192,165 @@ + return p; + } + ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved) ++{ ++ struct stat sb; ++ char *p, *q, *s; ++ size_t left_len, resolved_len; ++ unsigned symlinks; ++ int serrno, slen; ++ int is_dir = 1; ++ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; ++ ++ serrno = errno; ++ symlinks = 0; ++ if (path[0] == '/') { ++ resolved[0] = '/'; ++ resolved[1] = '\0'; ++ if (path[1] == '\0') ++ return (resolved); ++ resolved_len = 1; ++ left_len = strlcpy(left, path + 1, sizeof(left)); ++ } else { ++ if (getcwd(resolved, PATH_MAX) == NULL) { ++ strlcpy(resolved, ".", PATH_MAX); ++ return (NULL); ++ } ++ resolved_len = strlen(resolved); ++ left_len = strlcpy(left, path, sizeof(left)); ++ } ++ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ ++ /* ++ * Iterate over path components in `left'. ++ */ ++ while (left_len != 0) { ++ /* ++ * Extract the next path component and adjust `left' ++ * and its length. ++ */ ++ p = strchr(left, '/'); ++ s = p ? p : left + left_len; ++ if (s - left >= sizeof(next_token)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ memcpy(next_token, left, s - left); ++ next_token[s - left] = '\0'; ++ left_len -= s - left; ++ if (p != NULL) ++ memmove(left, s + 1, left_len + 1); ++ if (resolved[resolved_len - 1] != '/') { ++ if (resolved_len + 1 >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ resolved[resolved_len++] = '/'; ++ resolved[resolved_len] = '\0'; ++ } ++ if (next_token[0] == '\0') ++ continue; ++ else if (strcmp(next_token, ".") == 0) ++ continue; ++ else if (strcmp(next_token, "..") == 0) { ++ /* ++ * Strip the last path component except when we have ++ * single "/" ++ */ ++ if (!is_dir) { ++ errno = ENOENT; ++ return (NULL); ++ } ++ if (resolved_len > 1) { ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ continue; ++ } ++ ++ /* ++ * Append the next path component and lstat() it. If ++ * lstat() fails we still can return successfully if ++ * there are no more path components left. ++ */ ++ resolved_len = strlcat(resolved, next_token, PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ if (lstat(resolved, &sb) != 0) { ++ if (errno == ENOENT && p == NULL) { ++ errno = serrno; ++ return (resolved); ++ } ++ return (NULL); ++ } ++ if (S_ISLNK(sb.st_mode)) { ++ if (symlinks++ > MAXSYMLINKS) { ++ errno = ELOOP; ++ return (NULL); ++ } ++ slen = readlink(resolved, symlink, sizeof(symlink) - 1); ++ if (slen < 0) ++ return (NULL); ++ symlink[slen] = '\0'; ++ if (symlink[0] == '/') { ++ resolved[1] = 0; ++ resolved_len = 1; ++ } else if (resolved_len > 1) { ++ /* Strip the last path component. */ ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ ++ /* ++ * If there are any path components left, then ++ * append them to symlink. The result is placed ++ * in `left'. ++ */ ++ if (p != NULL) { ++ if (symlink[slen - 1] != '/') { ++ if (slen + 1 >= sizeof(symlink)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ symlink[slen] = '/'; ++ symlink[slen + 1] = 0; ++ } ++ left_len = strlcat(symlink, left, sizeof(left)); ++ if (left_len >= sizeof(left)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ } ++ left_len = strlcpy(left, symlink, sizeof(left)); ++ } else { ++ if (S_ISDIR(sb.st_mode)) { ++ is_dir = 1; ++ } else { ++ is_dir = 0; ++ } ++ } ++ } ++ ++ /* ++ * Remove trailing slash except when the resolved pathname ++ * is a single "/". ++ */ ++ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') ++ resolved[resolved_len - 1] = '\0'; ++ return (resolved); ++} ++#endif ++ + CWD_API void virtual_cwd_startup(void) + { + char cwd[MAXPATHLEN]; +@@ -314,8 +473,7 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now +- return 1; */ ++ return 1; + } + } + } else { /* Concat current directory with relative path and then run realpath() on it */ +@@ -341,9 +499,8 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now + free(tmp); +- return 1; */ ++ return 1; + } + } + free(tmp); +diff -Nura php-4.4.0/TSRM/tsrm_virtual_cwd.h hardening-patch-4.4.0-0.4.3/TSRM/tsrm_virtual_cwd.h +--- php-4.4.0/TSRM/tsrm_virtual_cwd.h 2005-02-11 04:34:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/TSRM/tsrm_virtual_cwd.h 2005-09-11 23:31:08.000000000 +0200 +@@ -128,6 +128,22 @@ + + typedef int (*verify_path_func)(const cwd_state *); + ++#ifndef HAVE_STRLCPY ++CWD_API size_t php_strlcpy(char *dst, const char *src, size_t siz); ++#undef strlcpy ++#define strlcpy php_strlcpy ++#endif ++ ++#ifndef HAVE_STRLCAT ++CWD_API size_t php_strlcat(char *dst, const char *src, size_t siz); ++#undef strlcat ++#define strlcat php_strlcat ++#endif ++ ++ ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved); ++#endif + CWD_API void virtual_cwd_startup(void); + CWD_API void virtual_cwd_shutdown(void); + CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC); +diff -Nura php-4.4.0/Zend/zend_alloc.c hardening-patch-4.4.0-0.4.3/Zend/zend_alloc.c +--- php-4.4.0/Zend/zend_alloc.c 2005-04-07 22:54:33.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_alloc.c 2005-09-11 23:31:08.000000000 +0200 +@@ -56,6 +56,11 @@ + # define END_MAGIC_SIZE 0 + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++# define CANARY_SIZE sizeof(unsigned int) ++#else ++# define CANARY_SIZE 0 ++#endif + + # if MEMORY_LIMIT + # if ZEND_DEBUG +@@ -95,9 +100,17 @@ + if (p==AG(head)) { \ + AG(head) = p->pNext; \ + } else { \ ++ if (p != p->pLast->pNext) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pLast->pNext = p->pNext; \ + } \ + if (p->pNext) { \ ++ if (p != p->pNext->pLast) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pNext->pLast = p->pLast; \ + } + +@@ -129,6 +142,12 @@ + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (size > LONG_MAX - sizeof(zend_mem_header) - MEM_HEADER_PADDING - END_MAGIC_SIZE - CANARY_SIZE) { ++ zend_security_log(S_MEMORY, "emalloc() - requested size would result in integer overflow"); ++ exit(1); ++ } ++#endif + CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size); + + if (!ZEND_DISABLE_MEMORY_CACHE && (CACHE_INDEX < MAX_CACHED_MEMORY) && (AG(cache_count)[CACHE_INDEX] > 0)) { +@@ -146,6 +165,10 @@ + AG(cache_stats)[CACHE_INDEX][1]++; + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->cached = 0; + p->size = size; + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); +@@ -161,7 +184,7 @@ + AG(allocated_memory_peak) = AG(allocated_memory); + } + #endif +- p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE + CANARY_SIZE); + } + + HANDLE_BLOCK_INTERRUPTIONS(); +@@ -191,7 +214,10 @@ + # endif + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif +- ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); + } +@@ -218,17 +244,36 @@ + return emalloc_rel(lval + offset); + } + } +- ++ ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by safe_emalloc()"); ++#endif + zend_error(E_ERROR, "Possible integer overflow in memory allocation (%ld * %ld + %ld)", nmemb, size, offset); + return 0; + } + + ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p = (zend_mem_header *) ((char *)ptr - sizeof(zend_mem_header) - MEM_HEADER_PADDING); + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (p->canary != HG(canary_1)) goto efree_canary_mismatch; ++ memcpy(&canary_2, (((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), CANARY_SIZE); ++ if (canary_2 != HG(canary_2)) { ++efree_canary_mismatch: ++ zend_security_log(S_MEMORY, "canary mismatch on efree() - heap overflow or double efree detected"); ++ exit(1); ++ } ++ /* to catch double efree()s */ ++ memset((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), 0, CANARY_SIZE); ++ p->canary = 0; ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + tsrm_error(TSRM_ERROR_LEVEL_ERROR, "Memory block allocated at %s:(%d) on thread %x freed at %s:(%d) on thread %x, ignoring", +@@ -273,6 +318,9 @@ + size_t _size = nmemb * size; + + if (nmemb && (_size/nmemb!=size)) { ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by ecalloc()"); ++#endif + fprintf(stderr,"FATAL: ecalloc(): Unable to allocate %ld * %ld bytes\n", (long) nmemb, (long) size); + #if ZEND_DEBUG && HAVE_KILL && HAVE_GETPID + kill(getpid(), SIGSEGV); +@@ -292,6 +340,9 @@ + + ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p; + zend_mem_header *orig; + DECLARE_CACHE_VARS(); +@@ -303,6 +354,16 @@ + + p = orig = (zend_mem_header *) ((char *)ptr-sizeof(zend_mem_header)-MEM_HEADER_PADDING); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (p->canary != HG(canary_1)) goto erealloc_canary_mismatch; ++ memcpy(&canary_2, (((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), CANARY_SIZE); ++ if (canary_2 != HG(canary_2)) { ++erealloc_canary_mismatch: ++ zend_security_log(S_MEMORY, "canary mismatch on erealloc() - heap overflow detected"); ++ exit(1); ++ } ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + void *new_p; +@@ -326,7 +387,7 @@ + } + #endif + REMOVE_POINTER_FROM_LIST(p); +- p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE+CANARY_SIZE); + if (!p) { + if (!allow_failure) { + fprintf(stderr,"FATAL: erealloc(): Unable to allocate %ld bytes\n", (long) size); +@@ -348,6 +409,9 @@ + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->size = size; + + HANDLE_UNBLOCK_INTERRUPTIONS(); +@@ -422,6 +486,10 @@ + { + AG(head) = NULL; + ++#if HARDENING_PATCH_MM_PROTECT ++ HG(canary_1) = zend_canary(); ++ HG(canary_2) = zend_canary(); ++#endif + #if MEMORY_LIMIT + AG(memory_limit) = 1<<30; /* ridiculous limit, effectively no limit */ + AG(allocated_memory) = 0; +diff -Nura php-4.4.0/Zend/zend_alloc.h hardening-patch-4.4.0-0.4.3/Zend/zend_alloc.h +--- php-4.4.0/Zend/zend_alloc.h 2005-06-07 15:37:33.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_alloc.h 2005-09-11 23:31:08.000000000 +0200 +@@ -32,6 +32,9 @@ + #define MEM_BLOCK_CACHED_MAGIC 0xFB8277DCL + + typedef struct _zend_mem_header { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary; ++#endif + #if ZEND_DEBUG + long magic; + char *filename; +diff -Nura php-4.4.0/Zend/zend_builtin_functions.c hardening-patch-4.4.0-0.4.3/Zend/zend_builtin_functions.c +--- php-4.4.0/Zend/zend_builtin_functions.c 2005-06-23 14:20:47.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_builtin_functions.c 2005-09-11 23:31:08.000000000 +0200 +@@ -49,6 +49,9 @@ + static ZEND_FUNCTION(crash); + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++static ZEND_FUNCTION(heap_overflow); ++#endif + static ZEND_FUNCTION(get_included_files); + static ZEND_FUNCTION(is_subclass_of); + static ZEND_FUNCTION(is_a); +@@ -101,6 +104,9 @@ + ZEND_FE(crash, NULL) + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ ZEND_FE(heap_overflow, NULL) ++#endif + ZEND_FE(get_included_files, NULL) + ZEND_FALIAS(get_required_files, get_included_files, NULL) + ZEND_FE(is_subclass_of, NULL) +@@ -805,6 +811,19 @@ + + #endif /* ZEND_DEBUG */ + ++ ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ZEND_FUNCTION(heap_overflow) ++{ ++ char *nowhere = emalloc(10); ++ ++ memcpy(nowhere, "something1234567890", sizeof("something1234567890")); ++ ++ efree(nowhere); ++} ++#endif ++ ++ + /* {{{ proto array get_included_files(void) + Returns an array with the file names that were include_once()'d */ + ZEND_FUNCTION(get_included_files) +diff -Nura php-4.4.0/Zend/zend.c hardening-patch-4.4.0-0.4.3/Zend/zend.c +--- php-4.4.0/Zend/zend.c 2005-06-09 12:14:25.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend.c 2005-09-12 18:15:08.000000000 +0200 +@@ -53,6 +53,12 @@ + ZEND_API void (*zend_unblock_interruptions)(void); + ZEND_API void (*zend_ticks_function)(int ticks); + ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); ++#if HARDENING_PATCH ++ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + + void (*zend_on_timeout)(int seconds TSRMLS_DC); + +@@ -70,9 +76,391 @@ + return SUCCESS; + } + ++#if HARDENING_PATCH ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog) = S_ALL & ~S_SQL | S_MEMORY | S_INTERNAL; ++ } else { ++ EG(hphp_log_syslog) = atoi(new_value) | S_MEMORY | S_INTERNAL; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_facility) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_facility) = LOG_USER; ++ } else { ++ EG(hphp_log_syslog_facility) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_priority) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_priority) = LOG_ALERT; ++ } else { ++ EG(hphp_log_syslog_priority) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_sapi) ++{ ++ if (!new_value) { ++ EG(hphp_log_sapi) = S_ALL & ~S_SQL | S_INTERNAL; ++ } else { ++ EG(hphp_log_sapi) = atoi(new_value) | S_INTERNAL; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_script) ++{ ++ if (!new_value) { ++ EG(hphp_log_script) = S_ALL & (~S_MEMORY) & (~S_INTERNAL); ++ } else { ++ EG(hphp_log_script) = atoi(new_value) & (~S_MEMORY) & (~S_INTERNAL); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_scriptname) ++{ ++ if (!new_value) { ++ EG(hphp_log_scriptname) = NULL; ++ } else { ++ if (EG(hphp_log_scriptname)) { ++ pefree(EG(hphp_log_scriptname),1); ++ } ++ EG(hphp_log_scriptname) = pestrdup(new_value,1); ++ } ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_include_whitelist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++include_whitelist_destroy: ++ if (HG(include_whitelist)) { ++ zend_hash_destroy(HG(include_whitelist)); ++ efree(HG(include_whitelist)); ++ } ++ HG(include_whitelist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto include_whitelist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(include_whitelist)); ++ zend_hash_init(HG(include_whitelist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(include_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(include_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_include_blacklist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++include_blacklist_destroy: ++ if (HG(include_blacklist)) { ++ zend_hash_destroy(HG(include_blacklist)); ++ efree(HG(include_blacklist)); ++ } ++ HG(include_blacklist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto include_blacklist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(include_blacklist)); ++ zend_hash_init(HG(include_blacklist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(include_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(include_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_eval_whitelist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++eval_whitelist_destroy: ++ if (HG(eval_whitelist)) { ++ zend_hash_destroy(HG(eval_whitelist)); ++ efree(HG(eval_whitelist)); ++ } ++ HG(eval_whitelist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto eval_whitelist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(eval_whitelist)); ++ zend_hash_init(HG(eval_whitelist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(eval_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(eval_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_eval_blacklist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++eval_blacklist_destroy: ++ if (HG(eval_blacklist)) { ++ zend_hash_destroy(HG(eval_blacklist)); ++ efree(HG(eval_blacklist)); ++ } ++ HG(eval_blacklist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto eval_blacklist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(eval_blacklist)); ++ zend_hash_init(HG(eval_blacklist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(eval_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(eval_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_func_whitelist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++func_whitelist_destroy: ++ if (HG(func_whitelist)) { ++ zend_hash_destroy(HG(func_whitelist)); ++ efree(HG(func_whitelist)); ++ } ++ HG(func_whitelist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto func_whitelist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(func_whitelist)); ++ zend_hash_init(HG(func_whitelist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(func_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(func_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_func_blacklist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++func_blacklist_destroy: ++ if (HG(func_blacklist)) { ++ zend_hash_destroy(HG(func_blacklist)); ++ efree(HG(func_blacklist)); ++ } ++ HG(func_blacklist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto func_blacklist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(func_blacklist)); ++ zend_hash_init(HG(func_blacklist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(func_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(func_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ ++ return SUCCESS; ++} ++ ++#endif + + ZEND_INI_BEGIN() + ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) ++#if HARDENING_PATCH ++ ZEND_INI_ENTRY("hphp.log.syslog", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog) ++ ZEND_INI_ENTRY("hphp.log.syslog.facility", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_facility) ++ ZEND_INI_ENTRY("hphp.log.syslog.priority", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_priority) ++ ZEND_INI_ENTRY("hphp.log.sapi", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_sapi) ++ ZEND_INI_ENTRY("hphp.log.script", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_script) ++ ZEND_INI_ENTRY("hphp.log.script.name", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_scriptname) ++ STD_ZEND_INI_BOOLEAN("hphp.log.use-x-forwarded-for", "0", ZEND_INI_SYSTEM, OnUpdateBool, hphp_log_use_x_forwarded_for, zend_executor_globals, executor_globals) ++ ++ ZEND_INI_ENTRY("hphp.executor.include.whitelist", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_include_whitelist) ++ ZEND_INI_ENTRY("hphp.executor.include.blacklist", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_include_blacklist) ++ ZEND_INI_ENTRY("hphp.executor.eval.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_eval_whitelist) ++ ZEND_INI_ENTRY("hphp.executor.eval.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_eval_blacklist) ++ ZEND_INI_ENTRY("hphp.executor.func.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_func_whitelist) ++ ZEND_INI_ENTRY("hphp.executor.func.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_func_blacklist) ++ ++ STD_ZEND_INI_ENTRY("hphp.executor.max_depth", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateLong, hphp_executor_max_depth, zend_executor_globals, executor_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.sql.bailout_on_error", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, hphp_sql_bailout_on_error, hardened_globals_struct, hardened_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.multiheader", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, hphp_multiheader, hardened_globals_struct, hardened_globals) ++#endif + ZEND_INI_END() + + +@@ -354,6 +742,7 @@ + zend_init_rsrc_plist(TSRMLS_C); + EG(lambda_count)=0; + EG(user_error_handler) = NULL; ++ EG(in_code_type) = 0; + EG(in_execution) = 0; + EG(current_execute_data) = NULL; + } +@@ -420,6 +809,14 @@ + extern zend_scanner_globals language_scanner_globals; + #endif + ++ /* Set up Hardening-Patch utility functions first */ ++#if HARDENING_PATCH ++ zend_security_log = utility_functions->security_log_function; ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ zend_is_valid_include = utility_functions->is_valid_include; ++#endif ++ + #ifdef ZTS + ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); + #else +@@ -623,6 +1020,7 @@ + } + CG(unclean_shutdown) = 1; + CG(in_compilation) = EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(current_execute_data) = NULL; + longjmp(EG(bailout), FAILURE); + } +diff -Nura php-4.4.0/Zend/zend_canary.c hardening-patch-4.4.0-0.4.3/Zend/zend_canary.c +--- php-4.4.0/Zend/zend_canary.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_canary.c 2005-09-11 23:31:08.000000000 +0200 +@@ -0,0 +1,58 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: zend_canary.c,v 1.1 2004/11/26 12:45:41 ionic Exp $ */ ++ ++#include "zend.h" ++ ++#include ++#include ++ ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++ZEND_API unsigned int zend_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-4.4.0/Zend/zend_compile.c hardening-patch-4.4.0-0.4.3/Zend/zend_compile.c +--- php-4.4.0/Zend/zend_compile.c 2005-06-24 13:48:30.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_compile.c 2005-09-11 23:31:08.000000000 +0200 +@@ -763,6 +763,13 @@ + op_array.function_name = name; + op_array.arg_types = NULL; + op_array.return_reference = return_reference; ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array.created_by_eval = 1; ++ } else { ++ op_array.created_by_eval = 0; ++ } ++#endif + + if (is_method) { + if (zend_hash_add(&CG(active_class_entry)->function_table, name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)) == FAILURE) { +diff -Nura php-4.4.0/Zend/zend_compile.h hardening-patch-4.4.0-0.4.3/Zend/zend_compile.h +--- php-4.4.0/Zend/zend_compile.h 2005-06-06 11:30:09.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_compile.h 2005-09-11 23:31:08.000000000 +0200 +@@ -106,6 +106,9 @@ + char *filename; + + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; ++#if HARDENING_PATCH ++ zend_bool created_by_eval; ++#endif + }; + + +@@ -549,6 +552,7 @@ + #define ZEND_USER_FUNCTION 2 + #define ZEND_OVERLOADED_FUNCTION 3 + #define ZEND_EVAL_CODE 4 ++#define ZEND_SANDBOX_CODE 6 + + #define ZEND_INTERNAL_CLASS 1 + #define ZEND_USER_CLASS 2 +diff -Nura php-4.4.0/Zend/zend_constants.c hardening-patch-4.4.0-0.4.3/Zend/zend_constants.c +--- php-4.4.0/Zend/zend_constants.c 2004-07-13 21:29:45.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_constants.c 2005-09-11 23:31:08.000000000 +0200 +@@ -111,6 +111,73 @@ + REGISTER_MAIN_LONG_CONSTANT("E_USER_NOTICE", E_USER_NOTICE, CONST_PERSISTENT | CONST_CS); + + REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("S_MEMORY", S_MEMORY, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_VARS", S_VARS, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_FILES", S_FILES, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INCLUDE", S_INCLUDE, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_SQL", S_SQL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_EXECUTOR", S_EXECUTOR, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_MISC", S_MISC, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INTERNAL", S_INTERNAL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_ALL", S_ALL, CONST_PERSISTENT | CONST_CS); ++ ++ /* error levels */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRIT", LOG_CRIT, CONST_CS | CONST_PERSISTENT); /* critical conditions */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ERR", LOG_ERR, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_WARNING", LOG_WARNING, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOTICE", LOG_NOTICE, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_INFO", LOG_INFO, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DEBUG", LOG_DEBUG, CONST_CS | CONST_PERSISTENT); ++ /* facility: type of program logging the message */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_KERN", LOG_KERN, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_USER", LOG_USER, CONST_CS | CONST_PERSISTENT); /* generic user level */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_MAIL", LOG_MAIL, CONST_CS | CONST_PERSISTENT); /* log to email */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DAEMON", LOG_DAEMON, CONST_CS | CONST_PERSISTENT); /* other system daemons */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTH", LOG_AUTH, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_SYSLOG", LOG_SYSLOG, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LPR", LOG_LPR, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NEWS ++ /* No LOG_NEWS on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NEWS", LOG_NEWS, CONST_CS | CONST_PERSISTENT); /* usenet new */ ++#endif ++#ifdef LOG_UUCP ++ /* No LOG_UUCP on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_UUCP", LOG_UUCP, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_CRON ++ /* apparently some systems don't have this one */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRON", LOG_CRON, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_AUTHPRIV ++ /* AIX doesn't have LOG_AUTHPRIV */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTHPRIV", LOG_AUTHPRIV, CONST_CS | CONST_PERSISTENT); ++#endif ++#if !defined(PHP_WIN32) && !defined(NETWARE) ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL0", LOG_LOCAL0, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL1", LOG_LOCAL1, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL2", LOG_LOCAL2, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL3", LOG_LOCAL3, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL4", LOG_LOCAL4, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL5", LOG_LOCAL5, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL6", LOG_LOCAL6, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL7", LOG_LOCAL7, CONST_CS | CONST_PERSISTENT); ++#endif ++ /* options */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PID", LOG_PID, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CONS", LOG_CONS, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ODELAY", LOG_ODELAY, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NDELAY", LOG_NDELAY, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NOWAIT ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOWAIT", LOG_NOWAIT, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_PERROR ++ /* AIX doesn't have LOG_PERROR */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ ++#endif ++#endif + + /* true/false constants */ + { +diff -Nura php-4.4.0/Zend/zend_errors.h hardening-patch-4.4.0-0.4.3/Zend/zend_errors.h +--- php-4.4.0/Zend/zend_errors.h 2002-12-31 17:22:59.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_errors.h 2005-09-11 23:31:08.000000000 +0200 +@@ -36,5 +36,17 @@ + #define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE) + #define E_CORE (E_CORE_ERROR | E_CORE_WARNING) + ++#if HARDENING_PATCH ++#define S_MEMORY (1<<0L) ++#define S_VARS (1<<1L) ++#define S_FILES (1<<2L) ++#define S_INCLUDE (1<<3L) ++#define S_SQL (1<<4L) ++#define S_EXECUTOR (1<<5L) ++#define S_MISC (1<<30L) ++#define S_INTERNAL (1<<29L) ++#define S_ALL (S_MEMORY | S_VARS | S_INCLUDE | S_FILES | S_MISC | S_SQL | S_EXECUTOR) ++#endif ++ + #endif /* ZEND_ERRORS_H */ + +diff -Nura php-4.4.0/Zend/zend_execute_API.c hardening-patch-4.4.0-0.4.3/Zend/zend_execute_API.c +--- php-4.4.0/Zend/zend_execute_API.c 2005-05-18 19:58:09.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_execute_API.c 2005-09-11 23:31:08.000000000 +0200 +@@ -142,6 +142,7 @@ + EG(class_table) = CG(class_table); + + EG(in_execution) = 0; ++ EG(in_code_type) = 0; + + zend_ptr_stack_init(&EG(argument_stack)); + +@@ -431,12 +432,14 @@ + zend_execute_data execute_data; + + /* Initialize execute_data */ ++ memset(&execute_data, 0, sizeof(execute_data)); + EX(fbc) = NULL; + EX(object).ptr = NULL; + EX(ce) = NULL; + EX(Ts) = NULL; + EX(op_array) = NULL; + EX(opline) = NULL; ++ EX(execute_depth) = 0; + + *retval_ptr_ptr = NULL; + +@@ -494,6 +497,39 @@ + zval_dtor(&function_name_copy); + return FAILURE; + } ++#if HARDENING_PATCH ++ if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) { ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), function_name_copy.value.str.val, function_name_copy.value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", function_name_copy.value.str.val); ++ zval_dtor(&function_name_copy); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), function_name_copy.value.str.val, function_name_copy.value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", function_name_copy.value.str.val); ++ zval_dtor(&function_name_copy); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), function_name_copy.value.str.val, function_name_copy.value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", function_name_copy.value.str.val); ++ zval_dtor(&function_name_copy); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), function_name_copy.value.str.val, function_name_copy.value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", function_name_copy.value.str.val); ++ zval_dtor(&function_name_copy); ++ zend_bailout(); ++ } ++ } ++ } ++#endif + zval_dtor(&function_name_copy); + + for (i=0; itype = type; + EG(return_value_ptr_ptr) = &local_retval_ptr; + EG(active_op_array) = new_op_array; + EG(no_extensions)=1; +@@ -673,6 +709,10 @@ + return retval; + } + ++ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) ++{ ++ return (zend_eval_string_ex(str, retval_ptr, string_name, ZEND_EVAL_CODE TSRMLS_CC)); ++} + + void execute_new_code(TSRMLS_D) + { +diff -Nura php-4.4.0/Zend/zend_execute.c hardening-patch-4.4.0-0.4.3/Zend/zend_execute.c +--- php-4.4.0/Zend/zend_execute.c 2005-06-27 08:15:48.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_execute.c 2005-09-11 23:31:08.000000000 +0200 +@@ -1042,6 +1042,7 @@ + zend_execute_data execute_data; + + /* Initialize execute_data */ ++ memset(&execute_data, 0, sizeof(execute_data)); + EX(fbc) = NULL; + EX(ce) = NULL; + EX(object).ptr = NULL; +@@ -1053,9 +1054,21 @@ + } + EX(prev_execute_data) = EG(current_execute_data); + EX(original_in_execution)=EG(in_execution); ++ EX(original_in_code_type)=EG(in_code_type); + + EG(current_execute_data) = &execute_data; + ++#if HARDENING_PATCH ++ EX(execute_depth) = 0; ++ ++ if ((op_array->type == ZEND_EVAL_CODE || op_array->created_by_eval) && EG(in_code_type) != ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } else if (op_array->type == ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_SANDBOX_CODE; ++ op_array->type = ZEND_EVAL_CODE; ++ } ++#endif ++ + EG(in_execution) = 1; + if (op_array->start_op) { + EX(opline) = op_array->start_op; +@@ -1087,6 +1100,19 @@ + } + } + ++#if HARDENING_PATCH ++ if (EX(prev_execute_data) == NULL) { ++ EX(execute_depth) = 0; ++ } else { ++ EX(execute_depth) = EX(prev_execute_data)->execute_depth + 1; ++ } ++ ++ if (EG(hphp_executor_max_depth) > 0 && EX(execute_depth) > EG(hphp_executor_max_depth)) { ++ zend_security_log(S_EXECUTOR, "Maximum execution depth of %u violated", EG(hphp_executor_max_depth)); ++ zend_bailout(); ++ } ++#endif ++ + while (1) { + #ifdef ZEND_WIN32 + if (EG(timed_out)) { +@@ -1631,6 +1657,36 @@ + if (zend_hash_find(active_function_table, function_name->value.str.val, function_name->value.str.len+1, (void **) &function)==FAILURE) { + zend_error(E_ERROR, "Call to undefined function: %s()", function_name->value.str.val); + } ++#if HARDENING_PATCH ++ if (active_function_table == EG(function_table)) { ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), function_name->value.str.val, function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", function_name->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), function_name->value.str.val, function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", function_name->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), function_name->value.str.val, function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", function_name->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), function_name->value.str.val, function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", function_name->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++#endif ++ + zval_dtor(&tmp); + EX(fbc) = function; + overloaded_function_call_cont: +@@ -1646,6 +1702,35 @@ + if (zend_hash_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { + zend_error(E_ERROR, "Unknown function: %s()", fname->value.str.val); + } ++#if HARDENING_PATCH ++ if (EX(function_state).function->type==ZEND_INTERNAL_FUNCTION) { ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++#endif + FREE_OP(EX(Ts), &EX(opline)->op1, EG(free_op1)); + zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(object).ptr, EX(ce)); + EX(object).ptr = NULL; +@@ -1816,6 +1901,7 @@ + efree(EX(Ts)); + } + EG(in_execution) = EX(original_in_execution); ++ EG(in_code_type) = EX(original_in_code_type); + EG(current_execute_data) = EX(prev_execute_data); + return; + } +@@ -2195,7 +2281,12 @@ + int dummy = 1; + zend_file_handle file_handle = {0}; + ++#if HARDENING_PATCH_INC_PROTECT ++ if (zend_is_valid_include(inc_filename) ++ && zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#else + if (zend_open(inc_filename->value.str.val, &file_handle) == SUCCESS ++#endif + && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) { + + file_handle.filename = inc_filename->value.str.val; +@@ -2224,6 +2315,11 @@ + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: ++#if HARDENING_PATCH_INC_PROTECT ++ if (!zend_is_valid_include(inc_filename)) { ++ break; ++ } ++#endif + new_op_array = compile_filename(EX(opline)->op2.u.constant.value.lval, inc_filename TSRMLS_CC); + break; + case ZEND_EVAL: { +diff -Nura php-4.4.0/Zend/zend_execute_globals.h hardening-patch-4.4.0-0.4.3/Zend/zend_execute_globals.h +--- php-4.4.0/Zend/zend_execute_globals.h 2005-06-06 11:30:09.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_execute_globals.h 2005-09-11 23:31:08.000000000 +0200 +@@ -60,6 +60,8 @@ + object_info object; + temp_variable *Ts; + zend_bool original_in_execution; ++ zend_uint original_in_code_type; ++ zend_uint execute_depth; + zend_op_array *op_array; + struct _zend_execute_data *prev_execute_data; + } zend_execute_data; +diff -Nura php-4.4.0/Zend/zend_extensions.c hardening-patch-4.4.0-0.4.3/Zend/zend_extensions.c +--- php-4.4.0/Zend/zend_extensions.c 2003-03-19 19:00:57.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_extensions.c 2005-09-11 23:31:08.000000000 +0200 +@@ -54,23 +54,44 @@ + return FAILURE; + } + ++ /* check if module is compiled against Hardening-Patch */ ++ if (extension_version_info->zend_extension_api_no < 1000000000) { ++ fprintf(stderr, "%s is not compiled with Hardening-Patch.\n" ++ "The Hardening-Patch version %d is installed.\n\n", ++ new_extension->name, ++ HARDENING_PATCH_ZEND_EXTENSION_API_NO); ++ DL_UNLOAD(handle); ++ return FAILURE; ++ } ++ ++ ++ /* check if module is compiled against correct Hardening-Patch version */ ++ if (extension_version_info->zend_extension_api_no != HARDENING_PATCH_ZEND_EXTENSION_API_NO) { ++ fprintf(stderr, "%s requires Hardening-Patch version %d.\n" ++ "The Hardening-Patch version %d is installed.\n\n", ++ new_extension->name, ++ extension_version_info->zend_extension_api_no, ++ HARDENING_PATCH_ZEND_EXTENSION_API_NO); ++ DL_UNLOAD(handle); ++ return FAILURE; ++ } + + /* allow extension to proclaim compatibility with any Zend version */ +- if (extension_version_info->zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) { +- if (extension_version_info->zend_extension_api_no > ZEND_EXTENSION_API_NO) { ++ if (extension_version_info->real_zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) { ++ if (extension_version_info->real_zend_extension_api_no > ZEND_EXTENSION_API_NO) { + fprintf(stderr, "%s requires Zend Engine API version %d.\n" + "The Zend Engine API version %d which is installed, is outdated.\n\n", + new_extension->name, +- extension_version_info->zend_extension_api_no, ++ extension_version_info->real_zend_extension_api_no, + ZEND_EXTENSION_API_NO); + DL_UNLOAD(handle); + return FAILURE; +- } else if (extension_version_info->zend_extension_api_no < ZEND_EXTENSION_API_NO) { ++ } else if (extension_version_info->real_zend_extension_api_no < ZEND_EXTENSION_API_NO) { + fprintf(stderr, "%s requires Zend Engine API version %d.\n" + "The Zend Engine API version %d which is installed, is newer.\n" + "Contact %s at %s for a later version of %s.\n\n", + new_extension->name, +- extension_version_info->zend_extension_api_no, ++ extension_version_info->real_zend_extension_api_no, + ZEND_EXTENSION_API_NO, + new_extension->author, + new_extension->URL, +diff -Nura php-4.4.0/Zend/zend_extensions.h hardening-patch-4.4.0-0.4.3/Zend/zend_extensions.h +--- php-4.4.0/Zend/zend_extensions.h 2005-06-06 11:44:59.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_extensions.h 2005-09-11 23:31:08.000000000 +0200 +@@ -23,6 +23,9 @@ + + #include "zend_compile.h" + ++/* Create own API version number for Hardening-Patch */ ++ ++#define HARDENING_PATCH_ZEND_EXTENSION_API_NO 1001050805 + #define ZEND_EXTENSION_API_NO 20050606 + + typedef struct _zend_extension_version_info { +@@ -30,6 +33,7 @@ + char *required_zend_version; + unsigned char thread_safe; + unsigned char debug; ++ int real_zend_extension_api_no; + } zend_extension_version_info; + + +@@ -96,7 +100,7 @@ + + + #define ZEND_EXTENSION() \ +- ZEND_EXT_API zend_extension_version_info extension_version_info = { ZEND_EXTENSION_API_NO, ZEND_VERSION, ZTS_V, ZEND_DEBUG } ++ ZEND_EXT_API zend_extension_version_info extension_version_info = { HARDENING_PATCH_ZEND_EXTENSION_API_NO, ZEND_VERSION, ZTS_V, ZEND_DEBUG, ZEND_EXTENSION_API_NO } + + #define STANDARD_ZEND_EXTENSION_PROPERTIES NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1 + #define COMPAT_ZEND_EXTENSION_PROPERTIES NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1 +diff -Nura php-4.4.0/Zend/zend_globals.h hardening-patch-4.4.0-0.4.3/Zend/zend_globals.h +--- php-4.4.0/Zend/zend_globals.h 2004-11-04 00:15:05.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_globals.h 2005-09-11 23:31:08.000000000 +0200 +@@ -163,6 +163,16 @@ + + int error_reporting; + int orig_error_reporting; ++#if HARDENING_PATCH ++ int hphp_log_syslog; ++ int hphp_log_syslog_facility; ++ int hphp_log_syslog_priority; ++ int hphp_log_sapi; ++ int hphp_log_script; ++ char *hphp_log_scriptname; ++ zend_bool hphp_log_use_x_forwarded_for; ++ long hphp_executor_max_depth; ++#endif + int exit_status; + + zend_op_array *active_op_array; +@@ -176,6 +186,7 @@ + int ticks_count; + + zend_bool in_execution; ++ zend_uint in_code_type; + zend_bool bailout_set; + zend_bool full_tables_cleanup; + +diff -Nura php-4.4.0/Zend/zend.h hardening-patch-4.4.0-0.4.3/Zend/zend.h +--- php-4.4.0/Zend/zend.h 2005-01-25 14:08:41.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend.h 2005-09-11 23:31:08.000000000 +0200 +@@ -275,9 +275,10 @@ + struct _zval_struct { + /* Variable information */ + zvalue_value value; /* value */ ++ zend_uint refcount; ++ zend_ushort flags; + zend_uchar type; /* active type */ + zend_uchar is_ref; +- zend_ushort refcount; + }; + + +@@ -338,6 +339,12 @@ + void (*ticks_function)(int ticks); + void (*on_timeout)(int seconds TSRMLS_DC); + zend_bool (*open_function)(const char *filename, struct _zend_file_handle *); ++#if HARDENING_PATCH ++ void (*security_log_function)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ int (*is_valid_include)(zval *z); ++#endif + } zend_utility_functions; + + +@@ -469,7 +476,16 @@ + extern ZEND_API void (*zend_ticks_function)(int ticks); + extern ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 4, 0); + extern void (*zend_on_timeout)(int seconds TSRMLS_DC); ++#if HARDENING_PATCH ++extern ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++extern ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ZEND_API unsigned int zend_canary(void); ++#endif + + ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_PTR_FORMAT(printf, 2, 3); + +@@ -576,6 +592,11 @@ + + #define ZEND_MAX_RESERVED_RESOURCES 4 + ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#include "php_syslog.h" ++#endif ++ + #endif /* ZEND_H */ + + /* +diff -Nura php-4.4.0/Zend/zend_hash.c hardening-patch-4.4.0-0.4.3/Zend/zend_hash.c +--- php-4.4.0/Zend/zend_hash.c 2005-04-28 09:34:32.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_hash.c 2005-09-11 23:31:08.000000000 +0200 +@@ -26,6 +26,17 @@ + # include + #endif + ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int zend_hash_canary = 0x1234567; ++ zend_bool zend_hash_canary_inited = 0; ++#endif ++ ++#define CHECK_HASH_CANARY(hash) \ ++ if (zend_hash_canary != (hash)->canary) { \ ++ zend_security_log(S_MEMORY, "Zend HashTable canary was overwritten"); \ ++ exit(1); \ ++ } ++ + #define HANDLE_NUMERIC(key, length, func) { \ + register char *tmp=key; \ + \ +@@ -175,6 +186,9 @@ + { + uint i = 3; + Bucket **tmp; ++#if HARDENING_PATCH_HASH_PROTECT ++ TSRMLS_FETCH(); ++#endif + + SET_INCONSISTENT(HT_OK); + +@@ -184,6 +198,13 @@ + + ht->nTableSize = 1 << i; + ht->nTableMask = ht->nTableSize - 1; ++#if HARDENING_PATCH_HASH_PROTECT ++ if (zend_hash_canary_inited==0) { ++ zend_hash_canary = zend_canary(); ++ zend_hash_canary_inited = 1; ++ } ++ ht->canary = zend_hash_canary; ++#endif + ht->pDestructor = pDestructor; + ht->pListHead = NULL; + ht->pListTail = NULL; +@@ -259,6 +280,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -327,6 +351,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -402,6 +429,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -450,7 +480,7 @@ + IS_CONSISTENT(ht); + + if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */ +- t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); ++ t = (Bucket **) perealloc(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); + if (t) { + HANDLE_BLOCK_INTERRUPTIONS(); + ht->arBuckets = t; +@@ -460,6 +490,7 @@ + HANDLE_UNBLOCK_INTERRUPTIONS(); + return SUCCESS; + } ++ zend_error(E_ERROR, "zend_hash_do_resize - out of memory"); + return FAILURE; + } + return SUCCESS; +@@ -524,6 +555,9 @@ + ht->pInternalPointer = p->pListNext; + } + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +@@ -553,6 +587,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -579,6 +616,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -608,6 +648,9 @@ + HANDLE_BLOCK_INTERRUPTIONS(); + + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +diff -Nura php-4.4.0/Zend/zend_hash.h hardening-patch-4.4.0-0.4.3/Zend/zend_hash.h +--- php-4.4.0/Zend/zend_hash.h 2002-12-31 17:23:03.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_hash.h 2005-09-11 23:31:08.000000000 +0200 +@@ -54,6 +54,9 @@ + } Bucket; + + typedef struct _hashtable { ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int canary; ++#endif + uint nTableSize; + uint nTableMask; + uint nNumOfElements; +diff -Nura php-4.4.0/Zend/zend_ini.h hardening-patch-4.4.0-0.4.3/Zend/zend_ini.h +--- php-4.4.0/Zend/zend_ini.h 2005-01-09 18:00:16.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_ini.h 2005-09-11 23:31:08.000000000 +0200 +@@ -174,6 +174,7 @@ + /* Standard message handlers */ + BEGIN_EXTERN_C() + ZEND_API ZEND_INI_MH(OnUpdateBool); ++#define OnUpdateLong OnUpdateInt + ZEND_API ZEND_INI_MH(OnUpdateInt); + ZEND_API ZEND_INI_MH(OnUpdateReal); + ZEND_API ZEND_INI_MH(OnUpdateString); +diff -Nura php-4.4.0/Zend/zend_language_scanner.l hardening-patch-4.4.0-0.4.3/Zend/zend_language_scanner.l +--- php-4.4.0/Zend/zend_language_scanner.l 2005-03-09 16:07:19.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_language_scanner.l 2005-09-11 23:31:08.000000000 +0200 +@@ -393,6 +393,13 @@ + compilation_successful=0; + } else { + init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array->created_by_eval = 1; ++ } else { ++ op_array->created_by_eval = 0; ++ } ++#endif + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + compiler_result = zendparse(TSRMLS_C); +diff -Nura php-4.4.0/Zend/zend_language_scanner.c hardening-patch-4.4.0-0.4.3/Zend/zend_language_scanner.c +--- php-4.4.0/Zend/zend_language_scanner.c 2005-07-11 12:07:41.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_language_scanner.c 2005-09-11 23:31:08.000000000 +0200 +@@ -3121,6 +3121,13 @@ + compilation_successful=0; + } else { + init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array->created_by_eval = 1; ++ } else { ++ op_array->created_by_eval = 0; ++ } ++#endif + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + compiler_result = zendparse(TSRMLS_C); +diff -Nura php-4.4.0/Zend/zend_llist.c hardening-patch-4.4.0-0.4.3/Zend/zend_llist.c +--- php-4.4.0/Zend/zend_llist.c 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_llist.c 2005-09-11 23:31:08.000000000 +0200 +@@ -21,9 +21,34 @@ + #include "zend.h" + #include "zend_llist.h" + #include "zend_qsort.h" ++#include "zend_globals.h" ++ ++#define CHECK_LIST_CANARY(list) \ ++ if (HG(canary_3) != (list)->canary_h || HG(canary_4) != (list)->canary_t) { \ ++ zend_security_log(S_MEMORY, "linked list canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++#define CHECK_LISTELEMENT_CANARY(elem) \ ++ if (HG(canary_3) != (elem)->canary) { \ ++ zend_security_log(S_MEMORY, "linked list element canary was overwritten"); \ ++ exit(1); \ ++ } ++ + + ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ ++ if (!HG(ll_canary_inited)) { ++ HG(canary_3) = zend_canary(); ++ HG(canary_4) = zend_canary(); ++ HG(ll_canary_inited) = 1; ++ } ++ l->canary_h = HG(canary_3); ++ l->canary_t = HG(canary_4); ++#endif + l->head = NULL; + l->tail = NULL; + l->count = 0; +@@ -37,6 +62,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->prev = l->tail; + tmp->next = NULL; + if (l->tail) { +@@ -55,6 +85,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->next = l->head; + tmp->prev = NULL; + if (l->head) { +@@ -91,10 +126,20 @@ + zend_llist_element *current=l->head; + zend_llist_element *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (compare(current->data, element)) { + DEL_LLIST_ELEMENT(current, l); ++#if HARDENING_PATCH_LL_PROTECT ++ current->canary = 0; ++#endif + break; + } + current = next; +@@ -106,7 +151,14 @@ + { + zend_llist_element *current=l->head, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (l->dtor) { + l->dtor(current->data); +@@ -131,7 +183,14 @@ + zend_llist_element *old_tail; + void *data; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if ((old_tail = l->tail)) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(old_tail) ++#endif + if (l->tail->prev) { + l->tail->prev->next = NULL; + } +@@ -157,9 +216,16 @@ + { + zend_llist_element *ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(src) ++#endif + zend_llist_init(dst, src->size, src->dtor, src->persistent); + ptr = src->head; + while (ptr) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(ptr) ++#endif + zend_llist_add_element(dst, ptr->data); + ptr = ptr->next; + } +@@ -170,11 +236,21 @@ + { + zend_llist_element *element, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + element=l->head; + while (element) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + next = element->next; + if (func(element->data)) { + DEL_LLIST_ELEMENT(element, l); ++#if HARDENING_PATCH_LL_PROTECT ++ element->canary = 0; ++#endif + } + element = next; + } +@@ -185,7 +261,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data TSRMLS_CC); + } + } +@@ -197,6 +279,9 @@ + zend_llist_element **elements; + zend_llist_element *element, **ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + if (l->count <= 0) { + return; + } +@@ -206,6 +291,9 @@ + ptr = &elements[0]; + + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + *ptr++ = element; + } + +@@ -228,7 +316,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, arg TSRMLS_CC); + } + } +@@ -239,8 +333,14 @@ + zend_llist_element *element; + va_list args; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + va_start(args, num_args); + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, num_args, args TSRMLS_CC); + } + va_end(args); +@@ -249,6 +349,10 @@ + + ZEND_API int zend_llist_count(zend_llist *l) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + return l->count; + } + +@@ -256,8 +360,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->head; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -269,8 +380,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->tail; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -282,9 +400,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->next; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +@@ -296,9 +424,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->prev; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +diff -Nura php-4.4.0/Zend/zend_llist.h hardening-patch-4.4.0-0.4.3/Zend/zend_llist.h +--- php-4.4.0/Zend/zend_llist.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_llist.h 2005-09-11 23:31:08.000000000 +0200 +@@ -24,6 +24,9 @@ + #include + + typedef struct _zend_llist_element { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary; ++#endif + struct _zend_llist_element *next; + struct _zend_llist_element *prev; + char data[1]; /* Needs to always be last in the struct */ +@@ -36,6 +39,9 @@ + typedef void (*llist_apply_func_t)(void * TSRMLS_DC); + + typedef struct _zend_llist { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_h; /* head */ ++#endif + zend_llist_element *head; + zend_llist_element *tail; + size_t size; +@@ -43,6 +49,9 @@ + llist_dtor_func_t dtor; + unsigned char persistent; + zend_llist_element *traverse_ptr; ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_t; /* tail */ ++#endif + } zend_llist; + + typedef zend_llist_element* zend_llist_position; +diff -Nura php-4.4.0/Zend/zend_modules.h hardening-patch-4.4.0-0.4.3/Zend/zend_modules.h +--- php-4.4.0/Zend/zend_modules.h 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_modules.h 2005-09-12 22:59:33.000000000 +0200 +@@ -34,6 +34,7 @@ + ZEND_API extern unsigned char second_arg_force_ref[]; + ZEND_API extern unsigned char third_arg_force_ref[]; + ++#define HARDENING_PATCH_ZEND_MODULE_API_NO 1001050912 + #define ZEND_MODULE_API_NO 20020429 + #ifdef ZTS + #define USING_ZTS 1 +@@ -41,9 +42,9 @@ + #define USING_ZTS 0 + #endif + +-#define STANDARD_MODULE_HEADER sizeof(zend_module_entry), ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS ++#define STANDARD_MODULE_HEADER sizeof(zend_module_entry), HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS + +-#define STANDARD_MODULE_PROPERTIES_EX 0, 0, 0, NULL, 0 ++#define STANDARD_MODULE_PROPERTIES_EX 0, 0, 0, NULL, 0, ZEND_MODULE_API_NO + + #define STANDARD_MODULE_PROPERTIES \ + NULL, NULL, STANDARD_MODULE_PROPERTIES_EX +@@ -75,6 +76,7 @@ + unsigned char type; + void *handle; + int module_number; ++ unsigned int real_zend_api; + }; + + +diff -Nura php-4.4.0/Zend/zend_opcode.c hardening-patch-4.4.0-0.4.3/Zend/zend_opcode.c +--- php-4.4.0/Zend/zend_opcode.c 2002-12-31 17:23:04.000000000 +0100 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_opcode.c 2005-09-11 23:31:08.000000000 +0200 +@@ -88,6 +88,9 @@ + op_array->done_pass_two = 0; + + op_array->start_op = NULL; ++#if HARDENING_PATCH ++ op_array->created_by_eval = 0; ++#endif + + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC); + } +diff -Nura php-4.4.0/Zend/zend_operators.c hardening-patch-4.4.0-0.4.3/Zend/zend_operators.c +--- php-4.4.0/Zend/zend_operators.c 2005-03-31 10:18:39.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_operators.c 2005-09-11 23:31:08.000000000 +0200 +@@ -1604,6 +1604,20 @@ + return (op->value.lval ? 1 : 0); + } + ++ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length) ++{ ++ register unsigned char *str = (unsigned char*)source; ++ register unsigned char *result = (unsigned char*)dest; ++ register unsigned char *end = str + length; ++ ++ while (str < end) { ++ *result++ = tolower((int)*str++); ++ } ++ *result = *end; ++ ++ return dest; ++} ++ + ZEND_API void zend_str_tolower(char *str, unsigned int length) + { + register char *p=str, *end=p+length; +diff -Nura php-4.4.0/Zend/zend_operators.h hardening-patch-4.4.0-0.4.3/Zend/zend_operators.h +--- php-4.4.0/Zend/zend_operators.h 2005-03-31 10:18:40.000000000 +0200 ++++ hardening-patch-4.4.0-0.4.3/Zend/zend_operators.h 2005-09-11 23:31:08.000000000 +0200 +@@ -174,6 +174,14 @@ + #endif + + ZEND_API void zend_str_tolower(char *str, unsigned int length); ++ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length); ++ ++static inline char * ++zend_str_tolower_dup(const char *source, unsigned int length) ++{ ++ return zend_str_tolower_copy((char *)emalloc(length+1), source, length); ++} ++ + ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2); + ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3); + ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2); diff --git a/0.4.3/hardening-patch-5.0.5-0.4.3.patch b/0.4.3/hardening-patch-5.0.5-0.4.3.patch new file mode 100644 index 0000000..70c37a6 --- /dev/null +++ b/0.4.3/hardening-patch-5.0.5-0.4.3.patch @@ -0,0 +1,7046 @@ +diff -Nura php-5.0.5/acinclude.m4 hardening-patch-5.0.5-0.4.3/acinclude.m4 +--- php-5.0.5/acinclude.m4 2005-07-26 00:31:07.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/acinclude.m4 2005-09-11 23:30:52.000000000 +0200 +@@ -1182,6 +1182,36 @@ + fi + ]) + ++dnl ++dnl Check for broken realpath() ++dnl ++dnl realpath("/etc/hosts/../passwd",XXX) should not return ++dnl "/etc/passwd" ++dnl ++AC_DEFUN([PHP_AC_BROKEN_REALPATH],[ ++ AC_CACHE_CHECK(whether realpath is broken, ac_cv_broken_realpath,[ ++ AC_TRY_RUN([ ++main() { ++ char buf[4096+1]; ++ buf[0] = 0; ++ realpath("/etc/hosts/../passwd", buf); ++ exit(strcmp(buf, "/etc/passwd")==0); ++} ++ ],[ ++ ac_cv_broken_realpath=no ++ ],[ ++ ac_cv_broken_realpath=yes ++ ],[ ++ ac_cv_broken_realpath=no ++ ]) ++ ]) ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ AC_DEFINE(PHP_BROKEN_REALPATH, 1, [Whether realpath is broken]) ++ else ++ AC_DEFINE(PHP_BROKEN_REALPATH, 0, [Whether realpath is broken]) ++ fi ++]) ++ + dnl PHP_SHARED_MODULE(module-name, object-var, build-dir, cxx) + dnl + dnl Basically sets up the link-stage for building module-name +diff -Nura php-5.0.5/configure hardening-patch-5.0.5-0.4.3/configure +--- php-5.0.5/configure 2005-09-05 13:16:17.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/configure 2005-09-11 23:30:52.000000000 +0200 +@@ -404,6 +404,16 @@ + ac_default_prefix=/usr/local + # Any additions from configure.in: + ac_help="$ac_help ++ --disable-hardening-patch-mm-protect Disable the Memory Manager protection." ++ac_help="$ac_help ++ --disable-hardening-patch-ll-protect Disable the Linked List protection." ++ac_help="$ac_help ++ --disable-hardening-patch-inc-protect Disable include/require protection." ++ac_help="$ac_help ++ --disable-hardening-patch-fmt-protect Disable format string protection." ++ac_help="$ac_help ++ --disable-hardening-patch-hash-protect Disable Zend HashTable DTOR protection." ++ac_help="$ac_help + + SAPI modules: + " +@@ -860,6 +870,8 @@ + ac_help="$ac_help + --disable-tokenizer Disable tokenizer support" + ac_help="$ac_help ++ --disable-varfilter Disable Hardening-Patch's variable filter" ++ac_help="$ac_help + --enable-wddx Enable WDDX support." + ac_help="$ac_help + --disable-xml Disable XML support." +@@ -2834,6 +2846,157 @@ + + + ++# Check whether --enable-hardening-patch-mm-protect or --disable-hardening-patch-mm-protect was given. ++if test "${enable_hardening_patch_mm_protect+set}" = set; then ++ enableval="$enable_hardening_patch_mm_protect" ++ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-ll-protect or --disable-hardening-patch-ll-protect was given. ++if test "${enable_hardening_patch_ll_protect+set}" = set; then ++ enableval="$enable_hardening_patch_ll_protect" ++ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-inc-protect or --disable-hardening-patch-inc-protect was given. ++if test "${enable_hardening_patch_inc_protect+set}" = set; then ++ enableval="$enable_hardening_patch_inc_protect" ++ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-fmt-protect or --disable-hardening-patch-fmt-protect was given. ++if test "${enable_hardening_patch_fmt_protect+set}" = set; then ++ enableval="$enable_hardening_patch_fmt_protect" ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++ ++fi ++ ++ ++# Check whether --enable-hardening-patch-hash-protect or --disable-hardening-patch-hash-protect was given. ++if test "${enable_hardening_patch_hash_protect+set}" = set; then ++ enableval="$enable_hardening_patch_hash_protect" ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++ ++else ++ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++ ++fi ++ ++ ++echo $ac_n "checking whether to protect the Zend Memory Manager""... $ac_c" 1>&6 ++echo "configure:2725: checking whether to protect the Zend Memory Manager" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_MM_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend Linked Lists""... $ac_c" 1>&6 ++echo "configure:2729: checking whether to protect the Zend Linked Lists" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_LL_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect include/require statements""... $ac_c" 1>&6 ++echo "configure:2733: checking whether to protect include/require statements" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_INC_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect PHP Format String functions""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect PHP Format String functions" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_FMT_PROTECT" 1>&6 ++ ++echo $ac_n "checking whether to protect the Zend HashTable Destructors""... $ac_c" 1>&6 ++echo "configure:2737: checking whether to protect the Zend HashTable Destructors" >&5 ++echo "$ac_t""$DO_HARDENING_PATCH_HASH_PROTECT" 1>&6 ++ ++ ++cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH 1 ++EOF ++ ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_MM_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_LL_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_INC_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_FMT_PROTECT 0 ++EOF ++ ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 1 ++EOF ++ ++else ++ cat >> confdefs.h <<\EOF ++#define HARDENING_PATCH_HASH_PROTECT 0 ++EOF ++ ++fi + + + +@@ -17473,6 +17636,62 @@ + fi + + ++ echo $ac_n "checking whether realpath is broken""... $ac_c" 1>&6 ++echo "configure:14928: checking whether realpath is broken" >&5 ++if eval "test \"`echo '$''{'ac_cv_broken_realpath'+set}'`\" = set"; then ++ echo $ac_n "(cached) $ac_c" 1>&6 ++else ++ ++ if test "$cross_compiling" = yes; then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null ++then ++ ++ ac_cv_broken_realpath=no ++ ++else ++ echo "configure: failed program was:" >&5 ++ cat conftest.$ac_ext >&5 ++ rm -fr conftest* ++ ++ ac_cv_broken_realpath=yes ++ ++fi ++rm -fr conftest* ++fi ++ ++ ++fi ++ ++echo "$ac_t""$ac_cv_broken_realpath" 1>&6 ++ if test "$ac_cv_broken_realpath" = "yes"; then ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 1 ++EOF ++ ++ else ++ cat >> confdefs.h <<\EOF ++#define PHP_BROKEN_REALPATH 0 ++EOF ++ ++ fi ++ ++ + echo $ac_n "checking for declared timezone""... $ac_c" 1>&6 + echo "configure:17478: checking for declared timezone" >&5 + if eval "test \"`echo '$''{'ac_cv_declared_timezone'+set}'`\" = set"; then +@@ -88634,7 +88853,7 @@ + if test "$ac_cv_crypt_blowfish" = "yes"; then + ac_result=1 + else +- ac_result=0 ++ ac_result=1 + fi + cat >> confdefs.h <&6 ++echo "configure:82041: checking whether to enable Hardening-Patch's variable filter" >&5 ++# Check whether --enable-varfilter or --disable-varfilter was given. ++if test "${enable_varfilter+set}" = set; then ++ enableval="$enable_varfilter" ++ PHP_VARFILTER=$enableval ++else ++ ++ PHP_VARFILTER=yes ++ ++ if test "$PHP_ENABLE_ALL" && test "yes" = "yes"; then ++ PHP_VARFILTER=$PHP_ENABLE_ALL ++ fi ++ ++fi ++ ++ ++ ++ext_output="yes, shared" ++ext_shared=yes ++case $PHP_VARFILTER in ++shared,*) ++ PHP_VARFILTER=`echo "$PHP_VARFILTER"|sed 's/^shared,//'` ++ ;; ++shared) ++ PHP_VARFILTER=yes ++ ;; ++no) ++ ext_output=no ++ ext_shared=no ++ ;; ++*) ++ ext_output=yes ++ ext_shared=no ++ ;; ++esac ++ ++ ++ ++echo "$ac_t""$ext_output" 1>&6 ++ ++ ++ ++ ++if test "$PHP_VARFILTER" != "no"; then ++ cat >> confdefs.h <<\EOF ++#define HAVE_VARFILTER 1 ++EOF ++ ++ ++ ext_builddir=ext/varfilter ++ ext_srcdir=$abs_srcdir/ext/varfilter ++ ++ ac_extra= ++ ++ if test "$ext_shared" != "shared" && test "$ext_shared" != "yes" && test "" != "cli"; then ++ ++ ++ ++ case ext/varfilter in ++ "") ac_srcdir="$abs_srcdir/"; unset ac_bdir; ac_inc="-I. -I$abs_srcdir" ;; ++ /*) ac_srcdir=`echo "ext/varfilter"|cut -c 2-`"/"; ac_bdir=$ac_srcdir; ac_inc="-I$ac_bdir -I$abs_srcdir/$ac_bdir" ;; ++ *) ac_srcdir="$abs_srcdir/ext/varfilter/"; ac_bdir="ext/varfilter/"; ac_inc="-I$ac_bdir -I$ac_srcdir" ;; ++ esac ++ ++ ++ ++ b_c_pre=$php_c_pre ++ b_cxx_pre=$php_cxx_pre ++ b_c_meta=$php_c_meta ++ b_cxx_meta=$php_cxx_meta ++ b_c_post=$php_c_post ++ b_cxx_post=$php_cxx_post ++ b_lo=$php_lo ++ ++ ++ old_IFS=$IFS ++ for ac_src in varfilter.c; do ++ ++ IFS=. ++ set $ac_src ++ ac_obj=$1 ++ IFS=$old_IFS ++ ++ PHP_GLOBAL_OBJS="$PHP_GLOBAL_OBJS $ac_bdir$ac_obj.lo" ++ ++ case $ac_src in ++ *.c) ac_comp="$b_c_pre $ac_extra $ac_inc $b_c_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_c_post" ;; ++ *.cpp) ac_comp="$b_cxx_pre $ac_extra $ac_inc $b_cxx_meta -c $ac_srcdir$ac_src -o $ac_bdir$ac_obj.$b_lo $b_cxx_post" ;; ++ esac ++ ++ cat >>Makefile.objects<>Makefile.objects<>Makefile.objects<> confdefs.h <>Makefile.objects<>Makefile.objects<&6 +@@ -106554,7 +107032,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + network.c php_open_temporary_file.c php_logos.c \ +- output.c ; do ++ output.c hardening_patch.c ; do + + IFS=. + set $ac_src +@@ -106795,7 +107273,7 @@ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ + zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ +- zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c; do ++ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_canary.c; do + + IFS=. + set $ac_src +diff -Nura php-5.0.5/configure.in hardening-patch-5.0.5-0.4.3/configure.in +--- php-5.0.5/configure.in 2005-09-05 12:41:12.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/configure.in 2005-09-11 23:30:52.000000000 +0200 +@@ -247,7 +247,7 @@ + sinclude(Zend/acinclude.m4) + sinclude(Zend/Zend.m4) + sinclude(TSRM/tsrm.m4) +- ++sinclude(main/hardening_patch.m4) + + + divert(2) +@@ -631,6 +631,7 @@ + AC_FUNC_ALLOCA + dnl PHP_AC_BROKEN_SPRINTF + dnl PHP_AC_BROKEN_SNPRINTF ++PHP_AC_BROKEN_REALPATH + PHP_DECLARED_TIMEZONE + PHP_TIME_R_TYPE + PHP_READDIR_R_TYPE +@@ -1284,7 +1285,7 @@ + php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ + strlcat.c mergesort.c reentrancy.c php_variables.c php_ticks.c \ + network.c php_open_temporary_file.c php_logos.c \ +- output.c ) ++ output.c hardening_patch.c ) + + PHP_ADD_SOURCES(main/streams, streams.c cast.c memory.c filter.c \ + plain_wrapper.c userspace.c transports.c xp_socket.c mmap.c) +@@ -1311,7 +1312,7 @@ + zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \ + zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \ + zend_ini.c zend_qsort.c zend_multibyte.c zend_ts_hash.c zend_stream.c \ +- zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c) ++ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_canary.c ) + + if test -r "$abs_srcdir/Zend/zend_objects.c"; then + PHP_ADD_SOURCES(Zend, zend_objects.c zend_object_handlers.c zend_objects_API.c zend_mm.c \ +diff -Nura php-5.0.5/ext/fbsql/php_fbsql.c hardening-patch-5.0.5-0.4.3/ext/fbsql/php_fbsql.c +--- php-5.0.5/ext/fbsql/php_fbsql.c 2005-02-09 20:32:45.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/ext/fbsql/php_fbsql.c 2005-09-11 23:30:52.000000000 +0200 +@@ -1852,8 +1852,24 @@ + } + else if (fbcmdErrorsFound(md)) + { ++#if HARDENING_PATCH ++ char* query_copy; ++ int i; ++#endif + FBCErrorMetaData* emd = fbcdcErrorMetaData(c, md); + char* emg = fbcemdAllErrorMessages(emd); ++#if HARDENING_PATCH ++ query_copy=estrdup(query_copy); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "fbsql error: %s - query: %s", emg, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ free(emg); ++ fbcemdRelease(emd); ++ result = 0; ++ zend_bailout(); ++ } ++#endif + if (FB_SQL_G(generateWarnings)) + { + if (emg) +diff -Nura php-5.0.5/ext/mysql/php_mysql.c hardening-patch-5.0.5-0.4.3/ext/mysql/php_mysql.c +--- php-5.0.5/ext/mysql/php_mysql.c 2005-04-08 00:23:28.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/ext/mysql/php_mysql.c 2005-09-11 23:30:52.000000000 +0200 +@@ -1224,6 +1224,8 @@ + { + php_mysql_conn *mysql; + MYSQL_RES *mysql_result; ++ char *copy_query; ++ int i; + + ZEND_FETCH_RESOURCE2(mysql, php_mysql_conn *, mysql_link, link_id, "MySQL-Link", le_link, le_plink); + +@@ -1274,6 +1276,13 @@ + php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #else +@@ -1284,6 +1293,13 @@ + php_error_docref("http://www.mysql.com/doc" TSRMLS_CC, E_WARNING, "%s", mysql_error(&mysql->conn)); + } + } ++ copy_query = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; copy_query[i]; i++) if (copy_query[i] < 32) copy_query[i]='.'; ++ php_security_log(S_SQL, "MySQL error: %s - query: %s", mysql_error(&mysql->conn), copy_query); ++ efree(copy_query); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } + RETURN_FALSE; + } + #endif +diff -Nura php-5.0.5/ext/mysqli/mysqli_nonapi.c hardening-patch-5.0.5-0.4.3/ext/mysqli/mysqli_nonapi.c +--- php-5.0.5/ext/mysqli/mysqli_nonapi.c 2005-08-06 18:56:06.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/ext/mysqli/mysqli_nonapi.c 2005-09-11 23:30:52.000000000 +0200 +@@ -229,6 +229,17 @@ + if (mysql_real_query(mysql->mysql, query, query_len)) { + char s_error[MYSQL_ERRMSG_SIZE], s_sqlstate[SQLSTATE_LENGTH+1]; + unsigned int s_errno; ++#if HARDENING_PATCH ++ char *query_copy = estrdup(query); ++ int i; ++ ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "MySQLi error: %s - query: %s", mysql->mysql->net.last_errno, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } ++#endif + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); + + /* we have to save error information, cause +@@ -278,6 +289,17 @@ + MYSQLI_DISABLE_MQ; + + if (mysql_real_query(mysql->mysql, query, query_len)) { ++#if HARDENING_PATCH ++ char *query_copy = estrdup(query); ++ int i; ++ ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "MySQLi error: %s - query: %s", mysql->mysql->net.last_errno, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ zend_bailout(); ++ } ++#endif + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); + RETURN_FALSE; + } +diff -Nura php-5.0.5/ext/pgsql/pgsql.c hardening-patch-5.0.5-0.4.3/ext/pgsql/pgsql.c +--- php-5.0.5/ext/pgsql/pgsql.c 2005-07-05 14:47:06.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/ext/pgsql/pgsql.c 2005-09-11 23:30:52.000000000 +0200 +@@ -1080,10 +1080,28 @@ + case PGRES_EMPTY_QUERY: + case PGRES_BAD_RESPONSE: + case PGRES_NONFATAL_ERROR: +- case PGRES_FATAL_ERROR: +- PHP_PQ_ERROR("Query failed: %s", pgsql); +- PQclear(pgsql_result); +- RETURN_FALSE; ++ case PGRES_FATAL_ERROR: ++ { ++#if HARDENING_PATCH ++ int i; ++ char *query_copy; ++#endif ++ char *msgbuf = _php_pgsql_trim_message(PQerrorMessage(pgsql), NULL); ++ PQclear(pgsql_result); ++#if HARDENING_PATCH ++ query_copy = estrdup(Z_STRVAL_PP(query)); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "PgSQL error: %s - query: %s", msgbuf, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ efree(msgbuf); ++ zend_bailout(); ++ } ++#endif ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Query failed: %s", msgbuf); ++ efree(msgbuf); ++ RETURN_FALSE; ++ } + break; + case PGRES_COMMAND_OK: /* successful command that did not return rows */ + default: +diff -Nura php-5.0.5/ext/sqlite/sqlite.c hardening-patch-5.0.5-0.4.3/ext/sqlite/sqlite.c +--- php-5.0.5/ext/sqlite/sqlite.c 2005-06-07 17:38:37.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/ext/sqlite/sqlite.c 2005-09-11 23:30:52.000000000 +0200 +@@ -1481,6 +1481,19 @@ + db->last_err_code = ret; + + if (ret != SQLITE_OK) { ++#if HARDENING_PATCH ++ char *query_copy; ++ int i; ++ ++ query_copy = estrdup(sql); ++ for (i=0; query_copy[i]; i++) if (query_copy[i]<32) query_copy[i]='.'; ++ php_security_log(S_SQL, "SQLite error: %s - query: %s", errtext, query_copy); ++ efree(query_copy); ++ if (HG(hphp_sql_bailout_on_error)) { ++ sqlite_freemem(errtext); ++ zend_bailout(); ++ } ++#endif + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errtext); + sqlite_freemem(errtext); + goto terminate; +diff -Nura php-5.0.5/ext/standard/array.c hardening-patch-5.0.5-0.4.3/ext/standard/array.c +--- php-5.0.5/ext/standard/array.c 2005-09-01 14:01:01.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/array.c 2005-09-11 23:30:52.000000000 +0200 +@@ -1283,6 +1283,32 @@ + } + } + } ++ ++ if (var_name[0] == 'H') { ++ if ((strcmp(var_name, "HTTP_GET_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_VARS")==0)|| ++ (strcmp(var_name, "HTTP_POST_FILES")==0)|| ++ (strcmp(var_name, "HTTP_ENV_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(var_name, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(var_name, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(var_name, "HTTP_RAW_POST_DATA")==0)) { ++ return 0; ++ } ++ } else if (var_name[0] == '_') { ++ if ((strcmp(var_name, "_COOKIE")==0)|| ++ (strcmp(var_name, "_ENV")==0)|| ++ (strcmp(var_name, "_FILES")==0)|| ++ (strcmp(var_name, "_GET")==0)|| ++ (strcmp(var_name, "_POST")==0)|| ++ (strcmp(var_name, "_REQUEST")==0)|| ++ (strcmp(var_name, "_SESSION")==0)|| ++ (strcmp(var_name, "_SERVER")==0)) { ++ return 0; ++ } ++ } else if (strcmp(var_name, "GLOBALS")==0) { ++ return 0; ++ } + + return 1; + } +diff -Nura php-5.0.5/ext/standard/basic_functions.c hardening-patch-5.0.5-0.4.3/ext/standard/basic_functions.c +--- php-5.0.5/ext/standard/basic_functions.c 2005-08-21 20:36:33.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/basic_functions.c 2005-09-11 23:30:52.000000000 +0200 +@@ -142,12 +142,14 @@ + typedef struct _php_shutdown_function_entry { + zval **arguments; + int arg_count; ++ zend_bool created_by_eval; + } php_shutdown_function_entry; + + typedef struct _user_tick_function_entry { + zval **arguments; + int arg_count; + int calling; ++ zend_bool created_by_eval; + } user_tick_function_entry; + + /* some prototypes for local functions */ +@@ -189,6 +191,8 @@ + PHP_FE(get_html_translation_table, NULL) + PHP_FE(sha1, NULL) + PHP_FE(sha1_file, NULL) ++ PHP_FE(sha256, NULL) ++ PHP_FE(sha256_file, NULL) + PHP_NAMED_FE(md5,php_if_md5, NULL) + PHP_NAMED_FE(md5_file,php_if_md5_file, NULL) + PHP_NAMED_FE(crc32,php_if_crc32, NULL) +@@ -616,7 +620,7 @@ + PHP_FALIAS(socket_get_status, stream_get_meta_data, NULL) + + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) +- PHP_FE(realpath, NULL) ++ PHP_STATIC_FE("realpath", zif_real_path, NULL) + #endif + + #ifdef HAVE_FNMATCH +@@ -2095,6 +2099,13 @@ + { + zval retval; + char *function_name = NULL; ++#if HARDENING_PATCH ++ zend_uint orig_code_type = EG(in_code_type); ++ ++ if (shutdown_function_entry->created_by_eval) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } ++#endif + + if (!zend_is_callable(shutdown_function_entry->arguments[0], 0, &function_name)) { + php_error(E_WARNING, "(Registered shutdown functions) Unable to call %s() - function does not exist", function_name); +@@ -2110,6 +2121,9 @@ + if (function_name) { + efree(function_name); + } ++#if HARDENING_PATCH ++ EG(in_code_type) = orig_code_type; ++#endif + return 0; + } + +@@ -2117,6 +2131,13 @@ + { + zval retval; + zval *function = tick_fe->arguments[0]; ++#if HARDENING_PATCH ++ zend_uint orig_code_type = EG(in_code_type); ++ ++ if (tick_fe->created_by_eval) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } ++#endif + + /* Prevent reentrant calls to the same user ticks function */ + if (! tick_fe->calling) { +@@ -2148,6 +2169,9 @@ + + tick_fe->calling = 0; + } ++#if HARDENING_PATCH ++ EG(in_code_type) = orig_code_type; ++#endif + } + + static void run_user_tick_functions(int tick_count) +@@ -2211,6 +2235,13 @@ + } + + shutdown_function_entry.arguments = (zval **) safe_emalloc(sizeof(zval *), shutdown_function_entry.arg_count, 0); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ shutdown_function_entry.created_by_eval = 1; ++ } else { ++ shutdown_function_entry.created_by_eval = 0; ++ } ++#endif + + if (zend_get_parameters_array(ht, shutdown_function_entry.arg_count, shutdown_function_entry.arguments) == FAILURE) { + RETURN_FALSE; +@@ -2794,6 +2825,13 @@ + } + + tick_fe.arguments = (zval **) safe_emalloc(sizeof(zval *), tick_fe.arg_count, 0); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ tick_fe.created_by_eval = 1; ++ } else { ++ tick_fe.created_by_eval = 0; ++ } ++#endif + + if (zend_get_parameters_array(ht, tick_fe.arg_count, tick_fe.arguments) == FAILURE) { + RETURN_FALSE; +@@ -3082,6 +3120,35 @@ + memcpy(new_key, prefix, prefix_len); + memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + ++ if (new_key[0] == 'H') { ++ if ((strcmp(new_key, "HTTP_GET_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_VARS")==0)|| ++ (strcmp(new_key, "HTTP_POST_FILES")==0)|| ++ (strcmp(new_key, "HTTP_ENV_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SERVER_VARS")==0)|| ++ (strcmp(new_key, "HTTP_SESSION_VARS")==0)|| ++ (strcmp(new_key, "HTTP_COOKIE_VARS")==0)|| ++ (strcmp(new_key, "HTTP_RAW_POST_DATA")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (new_key[0] == '_') { ++ if ((strcmp(new_key, "_COOKIE")==0)|| ++ (strcmp(new_key, "_ENV")==0)|| ++ (strcmp(new_key, "_FILES")==0)|| ++ (strcmp(new_key, "_GET")==0)|| ++ (strcmp(new_key, "_POST")==0)|| ++ (strcmp(new_key, "_REQUEST")==0)|| ++ (strcmp(new_key, "_SESSION")==0)|| ++ (strcmp(new_key, "_SERVER")==0)) { ++ efree(new_key); ++ return 0; ++ } ++ } else if (strcmp(new_key, "GLOBALS")==0) { ++ efree(new_key); ++ return 0; ++ } ++ + zend_hash_del(&EG(symbol_table), new_key, new_key_len); + ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, (*var)->refcount+1, 0); + +diff -Nura php-5.0.5/ext/standard/config.m4 hardening-patch-5.0.5-0.4.3/ext/standard/config.m4 +--- php-5.0.5/ext/standard/config.m4 2004-12-30 08:04:11.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/config.m4 2005-09-11 23:30:52.000000000 +0200 +@@ -187,7 +187,7 @@ + if test "$ac_cv_crypt_blowfish" = "yes"; then + ac_result=1 + else +- ac_result=0 ++ ac_result=1 + fi + AC_DEFINE_UNQUOTED(PHP_BLOWFISH_CRYPT, $ac_result, [Whether the system supports BlowFish salt]) + ]) +@@ -469,6 +469,6 @@ + incomplete_class.c url_scanner_ex.c ftp_fopen_wrapper.c \ + http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \ + var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c \ +- filters.c proc_open.c sunfuncs.c streamsfuncs.c http.c) ++ filters.c proc_open.c sunfuncs.c streamsfuncs.c http.c sha256.c crypt_blowfish.c ) + + PHP_ADD_MAKEFILE_FRAGMENT +diff -Nura php-5.0.5/ext/standard/config.w32 hardening-patch-5.0.5-0.4.3/ext/standard/config.w32 +--- php-5.0.5/ext/standard/config.w32 2003-12-06 17:04:33.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/config.w32 2005-09-11 23:30:52.000000000 +0200 +@@ -14,5 +14,5 @@ + url_scanner_ex.c ftp_fopen_wrapper.c http_fopen_wrapper.c \ + php_fopen_wrapper.c credits.c css.c var_unserializer.c ftok.c sha1.c \ + user_filters.c uuencode.c filters.c proc_open.c sunfuncs.c \ +- streamsfuncs.c http.c", false /* never shared */); ++ streamsfuncs.c http.c sha256.c crypt_blowfish.c", false /* never shared */); + +diff -Nura php-5.0.5/ext/standard/crypt_blowfish.c hardening-patch-5.0.5-0.4.3/ext/standard/crypt_blowfish.c +--- php-5.0.5/ext/standard/crypt_blowfish.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/crypt_blowfish.c 2005-09-11 23:30:52.000000000 +0200 +@@ -0,0 +1,748 @@ ++/* ++ * This code comes from John the Ripper password cracker, with reentrant ++ * and crypt(3) interfaces added, but optimizations specific to password ++ * cracking removed. ++ * ++ * Written by Solar Designer in 1998-2002 and ++ * placed in the public domain. ++ * ++ * There's absolutely no warranty. ++ * ++ * It is my intent that you should be able to use this on your system, ++ * as a part of a software package, or anywhere else to improve security, ++ * ensure compatibility, or for any other purpose. I would appreciate ++ * it if you give credit where it is due and keep your modifications in ++ * the public domain as well, but I don't require that in order to let ++ * you place this code and any modifications you make under a license ++ * of your choice. ++ * ++ * This implementation is compatible with OpenBSD bcrypt.c (version 2a) ++ * by Niels Provos , and uses some of his ++ * ideas. The password hashing algorithm was designed by David Mazieres ++ * . ++ * ++ * There's a paper on the algorithm that explains its design decisions: ++ * ++ * http://www.usenix.org/events/usenix99/provos.html ++ * ++ * Some of the tricks in BF_ROUND might be inspired by Eric Young's ++ * Blowfish library (I can't be sure if I would think of something if I ++ * hadn't seen his code). ++ */ ++ ++#include ++ ++#include ++#ifndef __set_errno ++#define __set_errno(val) errno = (val) ++#endif ++ ++#undef __CONST ++#ifdef __GNUC__ ++#define __CONST __const ++#else ++#define __CONST ++#endif ++ ++#ifdef __i386__ ++#define BF_ASM 0 ++#define BF_SCALE 1 ++#elif defined(__alpha__) || defined(__hppa__) ++#define BF_ASM 0 ++#define BF_SCALE 1 ++#else ++#define BF_ASM 0 ++#define BF_SCALE 0 ++#endif ++ ++typedef unsigned int BF_word; ++ ++/* Number of Blowfish rounds, this is also hardcoded into a few places */ ++#define BF_N 16 ++ ++typedef BF_word BF_key[BF_N + 2]; ++ ++typedef struct { ++ BF_word S[4][0x100]; ++ BF_key P; ++} BF_ctx; ++ ++/* ++ * Magic IV for 64 Blowfish encryptions that we do at the end. ++ * The string is "OrpheanBeholderScryDoubt" on big-endian. ++ */ ++static BF_word BF_magic_w[6] = { ++ 0x4F727068, 0x65616E42, 0x65686F6C, ++ 0x64657253, 0x63727944, 0x6F756274 ++}; ++ ++/* ++ * P-box and S-box tables initialized with digits of Pi. ++ */ ++static BF_ctx BF_init_state = { ++ { ++ { ++ 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, ++ 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, ++ 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, ++ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, ++ 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, ++ 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, ++ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, ++ 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, ++ 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, ++ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, ++ 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, ++ 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, ++ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, ++ 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, ++ 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, ++ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, ++ 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, ++ 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, ++ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, ++ 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, ++ 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, ++ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, ++ 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, ++ 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, ++ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, ++ 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, ++ 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, ++ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, ++ 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, ++ 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, ++ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, ++ 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, ++ 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, ++ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, ++ 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, ++ 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, ++ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, ++ 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, ++ 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, ++ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, ++ 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, ++ 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, ++ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, ++ 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, ++ 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, ++ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, ++ 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, ++ 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, ++ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, ++ 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, ++ 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, ++ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, ++ 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, ++ 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, ++ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, ++ 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, ++ 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, ++ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, ++ 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, ++ 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, ++ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, ++ 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, ++ 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, ++ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a ++ }, { ++ 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, ++ 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, ++ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, ++ 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, ++ 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, ++ 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, ++ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, ++ 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, ++ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, ++ 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, ++ 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, ++ 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, ++ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, ++ 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, ++ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, ++ 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, ++ 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, ++ 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, ++ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, ++ 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, ++ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, ++ 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, ++ 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, ++ 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, ++ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, ++ 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, ++ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, ++ 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, ++ 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, ++ 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, ++ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, ++ 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, ++ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, ++ 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, ++ 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, ++ 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, ++ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, ++ 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, ++ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, ++ 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, ++ 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, ++ 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, ++ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, ++ 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, ++ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, ++ 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, ++ 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, ++ 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, ++ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, ++ 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, ++ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, ++ 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, ++ 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, ++ 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, ++ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, ++ 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, ++ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, ++ 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, ++ 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, ++ 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, ++ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, ++ 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, ++ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, ++ 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 ++ }, { ++ 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, ++ 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, ++ 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, ++ 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, ++ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, ++ 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, ++ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, ++ 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, ++ 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, ++ 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, ++ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, ++ 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, ++ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, ++ 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, ++ 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, ++ 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, ++ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, ++ 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, ++ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, ++ 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, ++ 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, ++ 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, ++ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, ++ 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, ++ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, ++ 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, ++ 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, ++ 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, ++ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, ++ 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, ++ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, ++ 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, ++ 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, ++ 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, ++ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, ++ 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, ++ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, ++ 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, ++ 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, ++ 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, ++ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, ++ 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, ++ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, ++ 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, ++ 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, ++ 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, ++ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, ++ 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, ++ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, ++ 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, ++ 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, ++ 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, ++ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, ++ 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, ++ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, ++ 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, ++ 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, ++ 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, ++ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, ++ 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, ++ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, ++ 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, ++ 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, ++ 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 ++ }, { ++ 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, ++ 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, ++ 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, ++ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, ++ 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, ++ 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, ++ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, ++ 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, ++ 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, ++ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, ++ 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, ++ 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, ++ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, ++ 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, ++ 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, ++ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, ++ 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, ++ 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, ++ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, ++ 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, ++ 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, ++ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, ++ 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, ++ 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, ++ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, ++ 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, ++ 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, ++ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, ++ 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, ++ 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, ++ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, ++ 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, ++ 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, ++ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, ++ 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, ++ 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, ++ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, ++ 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, ++ 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, ++ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, ++ 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, ++ 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, ++ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, ++ 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, ++ 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, ++ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, ++ 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, ++ 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, ++ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, ++ 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, ++ 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, ++ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, ++ 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, ++ 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, ++ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, ++ 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, ++ 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, ++ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, ++ 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, ++ 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, ++ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, ++ 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, ++ 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, ++ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 ++ } ++ }, { ++ 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, ++ 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, ++ 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, ++ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, ++ 0x9216d5d9, 0x8979fb1b ++ } ++}; ++ ++static unsigned char BF_itoa64[64 + 1] = ++ "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; ++ ++static unsigned char BF_atoi64[0x60] = { ++ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, ++ 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 64, 64, 64, 64, 64, ++ 64, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ++ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 64, 64, 64, 64, 64, ++ 64, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, ++ 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64 ++}; ++ ++/* ++ * This may be optimized out if built with function inlining and no BF_ASM. ++ */ ++static void clean(void *data, int size) ++{ ++#if BF_ASM ++ extern void _BF_clean(void *data); ++#endif ++ memset(data, 0, size); ++#if BF_ASM ++ _BF_clean(data); ++#endif ++} ++ ++#define BF_safe_atoi64(dst, src) \ ++{ \ ++ tmp = (unsigned char)(src); \ ++ if (tmp == '$') break; \ ++ if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \ ++ tmp = BF_atoi64[tmp]; \ ++ if (tmp > 63) return -1; \ ++ (dst) = tmp; \ ++} ++ ++static int BF_decode(BF_word *dst, __CONST char *src, int size) ++{ ++ unsigned char *dptr = (unsigned char *)dst; ++ unsigned char *end = dptr + size; ++ unsigned char *sptr = (unsigned char *)src; ++ unsigned int tmp, c1, c2, c3, c4; ++ ++ do { ++ BF_safe_atoi64(c1, *sptr++); ++ BF_safe_atoi64(c2, *sptr++); ++ *dptr++ = (c1 << 2) | ((c2 & 0x30) >> 4); ++ if (dptr >= end) break; ++ ++ BF_safe_atoi64(c3, *sptr++); ++ *dptr++ = ((c2 & 0x0F) << 4) | ((c3 & 0x3C) >> 2); ++ if (dptr >= end) break; ++ ++ BF_safe_atoi64(c4, *sptr++); ++ *dptr++ = ((c3 & 0x03) << 6) | c4; ++ } while (dptr < end); ++ ++ while (dptr < end) ++ *dptr++ = 0; ++ ++ return 0; ++} ++ ++static void BF_encode(char *dst, __CONST BF_word *src, int size) ++{ ++ unsigned char *sptr = (unsigned char *)src; ++ unsigned char *end = sptr + size; ++ unsigned char *dptr = (unsigned char *)dst; ++ unsigned int c1, c2; ++ ++ do { ++ c1 = *sptr++; ++ *dptr++ = BF_itoa64[c1 >> 2]; ++ c1 = (c1 & 0x03) << 4; ++ if (sptr >= end) { ++ *dptr++ = BF_itoa64[c1]; ++ break; ++ } ++ ++ c2 = *sptr++; ++ c1 |= c2 >> 4; ++ *dptr++ = BF_itoa64[c1]; ++ c1 = (c2 & 0x0f) << 2; ++ if (sptr >= end) { ++ *dptr++ = BF_itoa64[c1]; ++ break; ++ } ++ ++ c2 = *sptr++; ++ c1 |= c2 >> 6; ++ *dptr++ = BF_itoa64[c1]; ++ *dptr++ = BF_itoa64[c2 & 0x3f]; ++ } while (sptr < end); ++} ++ ++static void BF_swap(BF_word *x, int count) ++{ ++ static int endianness_check = 1; ++ char *is_little_endian = (char *)&endianness_check; ++ BF_word tmp; ++ ++ if (*is_little_endian) ++ do { ++ tmp = *x; ++ tmp = (tmp << 16) | (tmp >> 16); ++ *x++ = ((tmp & 0x00FF00FF) << 8) | ((tmp >> 8) & 0x00FF00FF); ++ } while (--count); ++} ++ ++#if BF_SCALE ++/* Architectures which can shift addresses left by 2 bits with no extra cost */ ++#define BF_ROUND(L, R, N) \ ++ tmp1 = L & 0xFF; \ ++ tmp2 = L >> 8; \ ++ tmp2 &= 0xFF; \ ++ tmp3 = L >> 16; \ ++ tmp3 &= 0xFF; \ ++ tmp4 = L >> 24; \ ++ tmp1 = data.ctx.S[3][tmp1]; \ ++ tmp2 = data.ctx.S[2][tmp2]; \ ++ tmp3 = data.ctx.S[1][tmp3]; \ ++ tmp3 += data.ctx.S[0][tmp4]; \ ++ tmp3 ^= tmp2; \ ++ R ^= data.ctx.P[N + 1]; \ ++ tmp3 += tmp1; \ ++ R ^= tmp3; ++#else ++/* Architectures with no complicated addressing modes supported */ ++#define BF_INDEX(S, i) \ ++ (*((BF_word *)(((unsigned char *)S) + (i)))) ++#define BF_ROUND(L, R, N) \ ++ tmp1 = L & 0xFF; \ ++ tmp1 <<= 2; \ ++ tmp2 = L >> 6; \ ++ tmp2 &= 0x3FC; \ ++ tmp3 = L >> 14; \ ++ tmp3 &= 0x3FC; \ ++ tmp4 = L >> 22; \ ++ tmp4 &= 0x3FC; \ ++ tmp1 = BF_INDEX(data.ctx.S[3], tmp1); \ ++ tmp2 = BF_INDEX(data.ctx.S[2], tmp2); \ ++ tmp3 = BF_INDEX(data.ctx.S[1], tmp3); \ ++ tmp3 += BF_INDEX(data.ctx.S[0], tmp4); \ ++ tmp3 ^= tmp2; \ ++ R ^= data.ctx.P[N + 1]; \ ++ tmp3 += tmp1; \ ++ R ^= tmp3; ++#endif ++ ++/* ++ * Encrypt one block, BF_N is hardcoded here. ++ */ ++#define BF_ENCRYPT \ ++ L ^= data.ctx.P[0]; \ ++ BF_ROUND(L, R, 0); \ ++ BF_ROUND(R, L, 1); \ ++ BF_ROUND(L, R, 2); \ ++ BF_ROUND(R, L, 3); \ ++ BF_ROUND(L, R, 4); \ ++ BF_ROUND(R, L, 5); \ ++ BF_ROUND(L, R, 6); \ ++ BF_ROUND(R, L, 7); \ ++ BF_ROUND(L, R, 8); \ ++ BF_ROUND(R, L, 9); \ ++ BF_ROUND(L, R, 10); \ ++ BF_ROUND(R, L, 11); \ ++ BF_ROUND(L, R, 12); \ ++ BF_ROUND(R, L, 13); \ ++ BF_ROUND(L, R, 14); \ ++ BF_ROUND(R, L, 15); \ ++ tmp4 = R; \ ++ R = L; \ ++ L = tmp4 ^ data.ctx.P[BF_N + 1]; ++ ++#if BF_ASM ++#define BF_body() \ ++ _BF_body_r(&data.ctx); ++#else ++#define BF_body() \ ++ L = R = 0; \ ++ ptr = data.ctx.P; \ ++ do { \ ++ ptr += 2; \ ++ BF_ENCRYPT; \ ++ *(ptr - 2) = L; \ ++ *(ptr - 1) = R; \ ++ } while (ptr < &data.ctx.P[BF_N + 2]); \ ++\ ++ ptr = data.ctx.S[0]; \ ++ do { \ ++ ptr += 2; \ ++ BF_ENCRYPT; \ ++ *(ptr - 2) = L; \ ++ *(ptr - 1) = R; \ ++ } while (ptr < &data.ctx.S[3][0xFF]); ++#endif ++ ++static void BF_set_key(__CONST char *key, BF_key expanded, BF_key initial) ++{ ++ __CONST char *ptr = key; ++ int i, j; ++ BF_word tmp; ++ ++ for (i = 0; i < BF_N + 2; i++) { ++ tmp = 0; ++ for (j = 0; j < 4; j++) { ++ tmp <<= 8; ++ tmp |= *ptr; ++ ++ if (!*ptr) ptr = key; else ptr++; ++ } ++ ++ expanded[i] = tmp; ++ initial[i] = BF_init_state.P[i] ^ tmp; ++ } ++} ++ ++char *_crypt_blowfish_rn(__CONST char *key, __CONST char *setting, ++ char *output, int size) ++{ ++#if BF_ASM ++ extern void _BF_body_r(BF_ctx *ctx); ++#endif ++ struct { ++ BF_ctx ctx; ++ BF_key expanded_key; ++ union { ++ BF_word salt[4]; ++ BF_word output[6]; ++ } binary; ++ } data; ++ BF_word L, R; ++ BF_word tmp1, tmp2, tmp3, tmp4; ++ BF_word *ptr; ++ BF_word count; ++ int i; ++ ++ if (size < 7 + 22 + 31 + 1) { ++ __set_errno(ERANGE); ++ return NULL; ++ } ++ ++ if (setting[0] != '$' || ++ setting[1] != '2' || ++ setting[2] != 'a' || ++ setting[3] != '$' || ++ setting[4] < '0' || setting[4] > '3' || ++ setting[5] < '0' || setting[5] > '9' || ++ setting[6] != '$') { ++ __set_errno(EINVAL); ++ return NULL; ++ } ++ ++ count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0')); ++ if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16)) { ++ clean(data.binary.salt, sizeof(data.binary.salt)); ++ __set_errno(EINVAL); ++ return NULL; ++ } ++ ++ BF_swap(data.binary.salt, 4); ++ ++ BF_set_key(key, data.expanded_key, data.ctx.P); ++ ++ memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S)); ++ ++ L = R = 0; ++ for (i = 0; i < BF_N + 2; i += 2) { ++ L ^= data.binary.salt[i & 2]; ++ R ^= data.binary.salt[(i & 2) + 1]; ++ BF_ENCRYPT; ++ data.ctx.P[i] = L; ++ data.ctx.P[i + 1] = R; ++ } ++ ++ ptr = data.ctx.S[0]; ++ do { ++ ptr += 4; ++ L ^= data.binary.salt[(BF_N + 2) & 3]; ++ R ^= data.binary.salt[(BF_N + 3) & 3]; ++ BF_ENCRYPT; ++ *(ptr - 4) = L; ++ *(ptr - 3) = R; ++ ++ L ^= data.binary.salt[(BF_N + 4) & 3]; ++ R ^= data.binary.salt[(BF_N + 5) & 3]; ++ BF_ENCRYPT; ++ *(ptr - 2) = L; ++ *(ptr - 1) = R; ++ } while (ptr < &data.ctx.S[3][0xFF]); ++ ++ do { ++ data.ctx.P[0] ^= data.expanded_key[0]; ++ data.ctx.P[1] ^= data.expanded_key[1]; ++ data.ctx.P[2] ^= data.expanded_key[2]; ++ data.ctx.P[3] ^= data.expanded_key[3]; ++ data.ctx.P[4] ^= data.expanded_key[4]; ++ data.ctx.P[5] ^= data.expanded_key[5]; ++ data.ctx.P[6] ^= data.expanded_key[6]; ++ data.ctx.P[7] ^= data.expanded_key[7]; ++ data.ctx.P[8] ^= data.expanded_key[8]; ++ data.ctx.P[9] ^= data.expanded_key[9]; ++ data.ctx.P[10] ^= data.expanded_key[10]; ++ data.ctx.P[11] ^= data.expanded_key[11]; ++ data.ctx.P[12] ^= data.expanded_key[12]; ++ data.ctx.P[13] ^= data.expanded_key[13]; ++ data.ctx.P[14] ^= data.expanded_key[14]; ++ data.ctx.P[15] ^= data.expanded_key[15]; ++ data.ctx.P[16] ^= data.expanded_key[16]; ++ data.ctx.P[17] ^= data.expanded_key[17]; ++ ++ BF_body(); ++ ++ tmp1 = data.binary.salt[0]; ++ tmp2 = data.binary.salt[1]; ++ tmp3 = data.binary.salt[2]; ++ tmp4 = data.binary.salt[3]; ++ data.ctx.P[0] ^= tmp1; ++ data.ctx.P[1] ^= tmp2; ++ data.ctx.P[2] ^= tmp3; ++ data.ctx.P[3] ^= tmp4; ++ data.ctx.P[4] ^= tmp1; ++ data.ctx.P[5] ^= tmp2; ++ data.ctx.P[6] ^= tmp3; ++ data.ctx.P[7] ^= tmp4; ++ data.ctx.P[8] ^= tmp1; ++ data.ctx.P[9] ^= tmp2; ++ data.ctx.P[10] ^= tmp3; ++ data.ctx.P[11] ^= tmp4; ++ data.ctx.P[12] ^= tmp1; ++ data.ctx.P[13] ^= tmp2; ++ data.ctx.P[14] ^= tmp3; ++ data.ctx.P[15] ^= tmp4; ++ data.ctx.P[16] ^= tmp1; ++ data.ctx.P[17] ^= tmp2; ++ ++ BF_body(); ++ } while (--count); ++ ++ for (i = 0; i < 6; i += 2) { ++ L = BF_magic_w[i]; ++ R = BF_magic_w[i + 1]; ++ ++ count = 64; ++ do { ++ BF_ENCRYPT; ++ } while (--count); ++ ++ data.binary.output[i] = L; ++ data.binary.output[i + 1] = R; ++ } ++ ++ memcpy(output, setting, 7 + 22 - 1); ++ output[7 + 22 - 1] = BF_itoa64[(int) ++ BF_atoi64[(int)setting[7 + 22 - 1] - 0x20] & 0x30]; ++ ++/* This has to be bug-compatible with the original implementation, so ++ * only encode 23 of the 24 bytes. :-) */ ++ BF_swap(data.binary.output, 6); ++ BF_encode(&output[7 + 22], data.binary.output, 23); ++ output[7 + 22 + 31] = '\0'; ++ ++/* Overwrite the most obvious sensitive data we have on the stack. Note ++ * that this does not guarantee there's no sensitive data left on the ++ * stack and/or in registers; I'm not aware of portable code that does. */ ++ clean(&data, sizeof(data)); ++ ++ return output; ++} ++ ++char *_crypt_gensalt_blowfish_rn(unsigned long count, ++ __CONST char *input, int size, char *output, int output_size) ++{ ++ if (size < 16 || output_size < 7 + 22 + 1 || ++ (count && (count < 4 || count > 31))) { ++ if (output_size > 0) output[0] = '\0'; ++ __set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL); ++ return NULL; ++ } ++ ++ if (!count) count = 5; ++ ++ output[0] = '$'; ++ output[1] = '2'; ++ output[2] = 'a'; ++ output[3] = '$'; ++ output[4] = '0' + count / 10; ++ output[5] = '0' + count % 10; ++ output[6] = '$'; ++ ++ BF_encode(&output[7], (BF_word *)input, 16); ++ output[7 + 22] = '\0'; ++ ++ return output; ++} +diff -Nura php-5.0.5/ext/standard/crypt.c hardening-patch-5.0.5-0.4.3/ext/standard/crypt.c +--- php-5.0.5/ext/standard/crypt.c 2004-02-12 20:05:41.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/crypt.c 2005-09-12 18:13:10.000000000 +0200 +@@ -100,6 +100,8 @@ + return SUCCESS; + } + ++char *_crypt_blowfish_rn(char *key, char *setting, char *output, int size); ++char *_crypt_gensalt_blowfish_rn(unsigned long count, char *input, int size, char *output, int output_size); + + static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +@@ -135,7 +137,14 @@ + + /* The automatic salt generation only covers standard DES and md5-crypt */ + if(!*salt) { +-#if PHP_MD5_CRYPT ++#if PHP_BLOWFISH_CRYPT ++ char randat[16]; ++ int i; ++ ++ for (i=0; i<16; i++) randat[i] = PHP_CRYPT_RAND; ++ ++ _crypt_gensalt_blowfish_rn(5, randat, sizeof(randat), salt, sizeof(salt)); ++#elif PHP_MD5_CRYPT + strcpy(salt, "$1$"); + php_to64(&salt[3], PHP_CRYPT_RAND, 4); + php_to64(&salt[7], PHP_CRYPT_RAND, 4); +@@ -145,8 +154,24 @@ + salt[2] = '\0'; + #endif + } +- +- RETVAL_STRING(crypt(str, salt), 1); ++ ++ if (salt[0] == '$' && ++ salt[1] == '2' && ++ salt[2] == 'a' && ++ salt[3] == '$' && ++ salt[4] >= '0' && salt[4] <= '3' && ++ salt[5] >= '0' && salt[5] <= '9' && ++ salt[6] == '$') { ++ ++ char output[PHP_MAX_SALT_LEN+1]; ++ ++ output[0] = 0; ++ _crypt_blowfish_rn(str, salt, output, sizeof(output)); ++ RETVAL_STRING(output, 1); ++ ++ } else { ++ RETVAL_STRING(crypt(str, salt), 1); ++ } + } + /* }}} */ + #endif +diff -Nura php-5.0.5/ext/standard/dl.c hardening-patch-5.0.5-0.4.3/ext/standard/dl.c +--- php-5.0.5/ext/standard/dl.c 2005-05-04 15:48:01.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/dl.c 2005-09-11 23:30:52.000000000 +0200 +@@ -159,8 +159,35 @@ + RETURN_FALSE; + } + module_entry = get_module(); ++ ++ /* check if Hardening-Patch is installed */ ++ if (module_entry->zend_api < 1000000000) { ++ php_error_docref(NULL TSRMLS_CC, error_type, ++ "%s: Unable to initialize module\n" ++ "Module compiled without Hardening-Patch, module API=%d, debug=%d, thread-safety=%d\n" ++ "PHP compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "These options need to match\n", ++ module_entry->name, module_entry->zend_api, module_entry->zend_debug, module_entry->zts, ++ HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS); ++ DL_UNLOAD(handle); ++ RETURN_FALSE; ++ } ++ ++ /* check if correct Hardening-Patch is installed */ ++ if (module_entry->zend_api != HARDENING_PATCH_ZEND_MODULE_API_NO) { ++ php_error_docref(NULL TSRMLS_CC, error_type, ++ "%s: Unable to initialize module\n" ++ "Module compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "PHP compiled with Hardening-Patch=%d, module API=%d, debug=%d, thread-safety=%d\n" ++ "These options need to match\n", ++ module_entry->name, module_entry->zend_api, module_entry->real_zend_api, module_entry->zend_debug, module_entry->zts, ++ HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS); ++ DL_UNLOAD(handle); ++ RETURN_FALSE; ++ } ++ + if ((module_entry->zend_debug != ZEND_DEBUG) || (module_entry->zts != USING_ZTS) +- || (module_entry->zend_api != ZEND_MODULE_API_NO)) { ++ || (module_entry->real_zend_api != ZEND_MODULE_API_NO)) { + /* Check for pre-4.1.0 module which has a slightly different module_entry structure :( */ + struct pre_4_1_0_module_entry { + char *name; +@@ -194,7 +221,7 @@ + zts = ((struct pre_4_1_0_module_entry *)module_entry)->zts; + } else { + name = module_entry->name; +- zend_api = module_entry->zend_api; ++ zend_api = module_entry->real_zend_api; + zend_debug = module_entry->zend_debug; + zts = module_entry->zts; + } +diff -Nura php-5.0.5/ext/standard/file.c hardening-patch-5.0.5-0.4.3/ext/standard/file.c +--- php-5.0.5/ext/standard/file.c 2005-04-06 15:59:48.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/file.c 2005-09-11 23:30:52.000000000 +0200 +@@ -2044,7 +2044,7 @@ + #if (!defined(__BEOS__) && !defined(NETWARE) && HAVE_REALPATH) || defined(ZTS) + /* {{{ proto string realpath(string path) + Return the resolved path */ +-PHP_FUNCTION(realpath) ++PHP_FUNCTION(real_path) + { + zval **path; + char resolved_path_buff[MAXPATHLEN]; +diff -Nura php-5.0.5/ext/standard/file.h hardening-patch-5.0.5-0.4.3/ext/standard/file.h +--- php-5.0.5/ext/standard/file.h 2005-07-15 11:29:18.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/file.h 2005-09-11 23:30:52.000000000 +0200 +@@ -60,7 +60,7 @@ + PHP_FUNCTION(fd_set); + PHP_FUNCTION(fd_isset); + #if (!defined(__BEOS__) && HAVE_REALPATH) || defined(ZTS) +-PHP_FUNCTION(realpath); ++PHP_FUNCTION(real_path); + PHP_FUNCTION(fnmatch); + #endif + PHP_NAMED_FUNCTION(php_if_ftruncate); +diff -Nura php-5.0.5/ext/standard/head.c hardening-patch-5.0.5-0.4.3/ext/standard/head.c +--- php-5.0.5/ext/standard/head.c 2005-06-28 16:49:14.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/head.c 2005-09-11 23:30:52.000000000 +0200 +@@ -40,10 +40,31 @@ + { + zend_bool rep = 1; + sapi_header_line ctr = {0}; ++#if HARDENING_PATCH ++ int i; ++#endif + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &ctr.line, + &ctr.line_len, &rep, &ctr.response_code) == FAILURE) + return; ++ ++#if HARDENING_PATCH ++ if (!HG(hphp_multiheader)) { ++ for (i=0; i0 && (i"); + } + ++#if HARDENING_PATCH ++ if (!sapi_module.phpinfo_as_text) { ++ php_printf("

PHP Version %s with Hardening-Patch %s

\n", PHP_VERSION, HARDENING_PATCH_VERSION); ++ } else { ++ char temp_ver[40]; ++ ++ snprintf(temp_ver, sizeof(temp_ver), "%s/%s", PHP_VERSION, HARDENING_PATCH_VERSION); ++ php_info_print_table_row(2, "PHP/Hardening-Patch Version", temp_ver); ++ } ++#else + if (!sapi_module.phpinfo_as_text) { + php_printf("

PHP Version %s

\n", PHP_VERSION); + } else { + php_info_print_table_row(2, "PHP Version", PHP_VERSION); +- } ++ } ++#endif + php_info_print_box_end(); + php_info_print_table_start(); + php_info_print_table_row(2, "System", php_uname ); +diff -Nura php-5.0.5/ext/standard/php_standard.h hardening-patch-5.0.5-0.4.3/ext/standard/php_standard.h +--- php-5.0.5/ext/standard/php_standard.h 2004-01-08 18:32:51.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/php_standard.h 2005-09-11 23:30:52.000000000 +0200 +@@ -28,6 +28,7 @@ + #include "php_mail.h" + #include "md5.h" + #include "sha1.h" ++#include "sha256.h" + #include "html.h" + #include "exec.h" + #include "file.h" +diff -Nura php-5.0.5/ext/standard/sha256.c hardening-patch-5.0.5-0.4.3/ext/standard/sha256.c +--- php-5.0.5/ext/standard/sha256.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/sha256.c 2005-09-11 23:30:52.000000000 +0200 +@@ -0,0 +1,398 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 5 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2004 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 3.0 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available through the world-wide-web at the following url: | ++ | http://www.php.net/license/3_0.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++*/ ++ ++/* $Id: sha256.c,v 1.9 2004/01/08 08:17:34 andi Exp $ */ ++ ++#include ++#include "php.h" ++ ++/* This code is heavily based on the PHP md5/sha1 implementations */ ++ ++#include "sha256.h" ++ ++PHPAPI void make_sha256_digest(char *sha256str, unsigned char *digest) ++{ ++ int i; ++ ++ for (i = 0; i < 32; i++) { ++ sprintf(sha256str, "%02x", digest[i]); ++ sha256str += 2; ++ } ++ ++ *sha256str = '\0'; ++} ++ ++/* {{{ proto string sha256(string str [, bool raw_output]) ++ Calculate the sha256 hash of a string */ ++PHP_FUNCTION(sha256) ++{ ++ char *arg; ++ int arg_len; ++ zend_bool raw_output = 0; ++ char sha256str[65]; ++ PHP_SHA256_CTX context; ++ unsigned char digest[32]; ++ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &arg, &arg_len, &raw_output) == FAILURE) { ++ return; ++ } ++ ++ sha256str[0] = '\0'; ++ PHP_SHA256Init(&context); ++ PHP_SHA256Update(&context, arg, arg_len); ++ PHP_SHA256Final(digest, &context); ++ if (raw_output) { ++ RETURN_STRINGL(digest, 32, 1); ++ } else { ++ make_sha256_digest(sha256str, digest); ++ RETVAL_STRING(sha256str, 1); ++ } ++ ++} ++ ++/* }}} */ ++ ++/* {{{ proto string sha256_file(string filename [, bool raw_output]) ++ Calculate the sha256 hash of given filename */ ++PHP_FUNCTION(sha256_file) ++{ ++ char *arg; ++ int arg_len; ++ zend_bool raw_output = 0; ++ char sha256str[65]; ++ unsigned char buf[1024]; ++ unsigned char digest[32]; ++ PHP_SHA256_CTX context; ++ int n; ++ FILE *fp; ++ ++ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &arg, &arg_len, &raw_output) == FAILURE) { ++ return; ++ } ++ ++ if (PG(safe_mode) && (!php_checkuid(arg, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { ++ RETURN_FALSE; ++ } ++ ++ if (php_check_open_basedir(arg TSRMLS_CC)) { ++ RETURN_FALSE; ++ } ++ ++ if ((fp = VCWD_FOPEN(arg, "rb")) == NULL) { ++ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to open file"); ++ RETURN_FALSE; ++ } ++ ++ PHP_SHA256Init(&context); ++ ++ while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { ++ PHP_SHA256Update(&context, buf, n); ++ } ++ ++ PHP_SHA256Final(digest, &context); ++ ++ if (ferror(fp)) { ++ fclose(fp); ++ RETURN_FALSE; ++ } ++ ++ fclose(fp); ++ ++ if (raw_output) { ++ RETURN_STRINGL(digest, 32, 1); ++ } else { ++ make_sha256_digest(sha256str, digest); ++ RETVAL_STRING(sha256str, 1); ++ } ++} ++/* }}} */ ++ ++ ++static void SHA256Transform(php_uint32[8], const unsigned char[64]); ++static void SHA256Encode(unsigned char *, php_uint32 *, unsigned int); ++static void SHA256Decode(php_uint32 *, const unsigned char *, unsigned int); ++ ++static unsigned char PADDING[64] = ++{ ++ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ++}; ++ ++/* F, G, H and I are basic SHA256 functions. ++ */ ++#define F(x) (ROTATE_RIGHT(x,2) ^ ROTATE_RIGHT(x,13) ^ ROTATE_RIGHT(x,22)) ++#define G(x, y, z) (((x) & (y)) | ((z) & ((y) | (x)))) ++#define H(x) (ROTATE_RIGHT(x,6) ^ ROTATE_RIGHT(x,11) ^ ROTATE_RIGHT(x,25)) ++#define I(x, y, z) (((x) & (y)) | ((~x) & z)) ++ ++/* ROTATE_RIGHT rotates x right n bits. ++ */ ++#define ROTATE_RIGHT(x, n) (((x) >> (n)) | ((x) << (32-(n)))) ++ ++/* W[i] ++ */ ++#define W(i) ( tmp1=ROTATE_RIGHT(x[(i-15)&15],7)^ROTATE_RIGHT(x[(i-15)&15],18)^(x[(i-15)&15] >> 3), \ ++ tmp2=ROTATE_RIGHT(x[(i-2)&15],17)^ROTATE_RIGHT(x[(i-2)&15],19)^(x[(i-2)&15] >> 10), \ ++ (x[i&15]=x[i&15] + tmp1 + x[(i-7)&15] + tmp2) ) ++ ++/* ROUND function of sha256 ++ */ ++ ++#define ROUND(a,b,c,d,e,f,g,h,w,k) { \ ++ t1 = (h) + H((e)) + I((e), (f), (g)) + (k) + (php_uint32)(w); \ ++ (h) = F((a)) + G((a), (b), (c)) + t1; \ ++ (d) += t1; \ ++ } ++ ++ ++/* {{{ PHP_SHA256Init ++ * SHA256 initialization. Begins an SHA256 operation, writing a new context. ++ */ ++PHPAPI void PHP_SHA256Init(PHP_SHA256_CTX * context) ++{ ++ context->count[0] = context->count[1] = 0; ++ /* Load magic initialization constants. ++ */ ++ context->state[0] = 0x6a09e667; ++ context->state[1] = 0xbb67ae85; ++ context->state[2] = 0x3c6ef372; ++ context->state[3] = 0xa54ff53a; ++ context->state[4] = 0x510e527f; ++ context->state[5] = 0x9b05688c; ++ context->state[6] = 0x1f83d9ab; ++ context->state[7] = 0x5be0cd19; ++} ++/* }}} */ ++ ++/* {{{ PHP_SHA256Update ++ SHA256 block update operation. Continues an SHA256 message-digest ++ operation, processing another message block, and updating the ++ context. ++ */ ++PHPAPI void PHP_SHA256Update(PHP_SHA256_CTX * context, const unsigned char *input, ++ unsigned int inputLen) ++{ ++ unsigned int i, index, partLen; ++ ++ /* Compute number of bytes mod 64 */ ++ index = (unsigned int) ((context->count[0] >> 3) & 0x3F); ++ ++ /* Update number of bits */ ++ if ((context->count[0] += ((php_uint32) inputLen << 3)) ++ < ((php_uint32) inputLen << 3)) ++ context->count[1]++; ++ context->count[1] += ((php_uint32) inputLen >> 29); ++ ++ partLen = 64 - index; ++ ++ /* Transform as many times as possible. ++ */ ++ if (inputLen >= partLen) { ++ memcpy ++ ((unsigned char*) & context->buffer[index], (unsigned char*) input, partLen); ++ SHA256Transform(context->state, context->buffer); ++ ++ for (i = partLen; i + 63 < inputLen; i += 64) ++ SHA256Transform(context->state, &input[i]); ++ ++ index = 0; ++ } else ++ i = 0; ++ ++ /* Buffer remaining input */ ++ memcpy ++ ((unsigned char*) & context->buffer[index], (unsigned char*) & input[i], ++ inputLen - i); ++} ++/* }}} */ ++ ++/* {{{ PHP_SHA256Final ++ SHA256 finalization. Ends an SHA256 message-digest operation, writing the ++ the message digest and zeroizing the context. ++ */ ++PHPAPI void PHP_SHA256Final(unsigned char digest[32], PHP_SHA256_CTX * context) ++{ ++ unsigned char bits[8]; ++ unsigned int index, padLen; ++ ++ /* Save number of bits */ ++ bits[7] = context->count[0] & 0xFF; ++ bits[6] = (context->count[0] >> 8) & 0xFF; ++ bits[5] = (context->count[0] >> 16) & 0xFF; ++ bits[4] = (context->count[0] >> 24) & 0xFF; ++ bits[3] = context->count[1] & 0xFF; ++ bits[2] = (context->count[1] >> 8) & 0xFF; ++ bits[1] = (context->count[1] >> 16) & 0xFF; ++ bits[0] = (context->count[1] >> 24) & 0xFF; ++ ++ /* Pad out to 56 mod 64. ++ */ ++ index = (unsigned int) ((context->count[0] >> 3) & 0x3f); ++ padLen = (index < 56) ? (56 - index) : (120 - index); ++ PHP_SHA256Update(context, PADDING, padLen); ++ ++ /* Append length (before padding) */ ++ PHP_SHA256Update(context, bits, 8); ++ ++ /* Store state in digest */ ++ SHA256Encode(digest, context->state, 32); ++ ++ /* Zeroize sensitive information. ++ */ ++ memset((unsigned char*) context, 0, sizeof(*context)); ++} ++/* }}} */ ++ ++/* {{{ SHA256Transform ++ * SHA256 basic transformation. Transforms state based on block. ++ */ ++static void SHA256Transform(state, block) ++php_uint32 state[8]; ++const unsigned char block[64]; ++{ ++ php_uint32 a = state[0], b = state[1], c = state[2]; ++ php_uint32 d = state[3], e = state[4], f = state[5]; ++ php_uint32 g = state[6], h = state[7], x[16], tmp1, tmp2, t1; ++ ++ SHA256Decode(x, block, 64); ++ ++ ROUND(a, b, c, d, e, f, g, h, x[0], 0x428a2f98) ++ ROUND(h, a, b, c, d, e, f, g, x[1], 0x71374491) ++ ROUND(g, h, a, b, c, d, e, f, x[2], 0xb5c0fbcf) ++ ROUND(f, g, h, a, b, c, d, e, x[3], 0xe9b5dba5) ++ ROUND(e, f, g, h, a, b, c, d, x[4], 0x3956c25b) ++ ROUND(d, e, f, g, h, a, b, c, x[5], 0x59f111f1) ++ ROUND(c, d, e, f, g, h, a, b, x[6], 0x923f82a4) ++ ROUND(b, c, d, e, f, g, h, a, x[7], 0xab1c5ed5) ++ ROUND(a, b, c, d, e, f, g, h, x[8], 0xd807aa98) ++ ROUND(h, a, b, c, d, e, f, g, x[9], 0x12835b01) ++ ROUND(g, h, a, b, c, d, e, f, x[10], 0x243185be) ++ ROUND(f, g, h, a, b, c, d, e, x[11], 0x550c7dc3) ++ ROUND(e, f, g, h, a, b, c, d, x[12], 0x72be5d74) ++ ROUND(d, e, f, g, h, a, b, c, x[13], 0x80deb1fe) ++ ROUND(c, d, e, f, g, h, a, b, x[14], 0x9bdc06a7) ++ ROUND(b, c, d, e, f, g, h, a, x[15], 0xc19bf174) ++ ROUND(a, b, c, d, e, f, g, h, W(16), 0xe49b69c1) ++ ROUND(h, a, b, c, d, e, f, g, W(17), 0xefbe4786) ++ ROUND(g, h, a, b, c, d, e, f, W(18), 0x0fc19dc6) ++ ROUND(f, g, h, a, b, c, d, e, W(19), 0x240ca1cc) ++ ROUND(e, f, g, h, a, b, c, d, W(20), 0x2de92c6f) ++ ROUND(d, e, f, g, h, a, b, c, W(21), 0x4a7484aa) ++ ROUND(c, d, e, f, g, h, a, b, W(22), 0x5cb0a9dc) ++ ROUND(b, c, d, e, f, g, h, a, W(23), 0x76f988da) ++ ROUND(a, b, c, d, e, f, g, h, W(24), 0x983e5152) ++ ROUND(h, a, b, c, d, e, f, g, W(25), 0xa831c66d) ++ ROUND(g, h, a, b, c, d, e, f, W(26), 0xb00327c8) ++ ROUND(f, g, h, a, b, c, d, e, W(27), 0xbf597fc7) ++ ROUND(e, f, g, h, a, b, c, d, W(28), 0xc6e00bf3) ++ ROUND(d, e, f, g, h, a, b, c, W(29), 0xd5a79147) ++ ROUND(c, d, e, f, g, h, a, b, W(30), 0x06ca6351) ++ ROUND(b, c, d, e, f, g, h, a, W(31), 0x14292967) ++ ROUND(a, b, c, d, e, f, g, h, W(32), 0x27b70a85) ++ ROUND(h, a, b, c, d, e, f, g, W(33), 0x2e1b2138) ++ ROUND(g, h, a, b, c, d, e, f, W(34), 0x4d2c6dfc) ++ ROUND(f, g, h, a, b, c, d, e, W(35), 0x53380d13) ++ ROUND(e, f, g, h, a, b, c, d, W(36), 0x650a7354) ++ ROUND(d, e, f, g, h, a, b, c, W(37), 0x766a0abb) ++ ROUND(c, d, e, f, g, h, a, b, W(38), 0x81c2c92e) ++ ROUND(b, c, d, e, f, g, h, a, W(39), 0x92722c85) ++ ROUND(a, b, c, d, e, f, g, h, W(40), 0xa2bfe8a1) ++ ROUND(h, a, b, c, d, e, f, g, W(41), 0xa81a664b) ++ ROUND(g, h, a, b, c, d, e, f, W(42), 0xc24b8b70) ++ ROUND(f, g, h, a, b, c, d, e, W(43), 0xc76c51a3) ++ ROUND(e, f, g, h, a, b, c, d, W(44), 0xd192e819) ++ ROUND(d, e, f, g, h, a, b, c, W(45), 0xd6990624) ++ ROUND(c, d, e, f, g, h, a, b, W(46), 0xf40e3585) ++ ROUND(b, c, d, e, f, g, h, a, W(47), 0x106aa070) ++ ROUND(a, b, c, d, e, f, g, h, W(48), 0x19a4c116) ++ ROUND(h, a, b, c, d, e, f, g, W(49), 0x1e376c08) ++ ROUND(g, h, a, b, c, d, e, f, W(50), 0x2748774c) ++ ROUND(f, g, h, a, b, c, d, e, W(51), 0x34b0bcb5) ++ ROUND(e, f, g, h, a, b, c, d, W(52), 0x391c0cb3) ++ ROUND(d, e, f, g, h, a, b, c, W(53), 0x4ed8aa4a) ++ ROUND(c, d, e, f, g, h, a, b, W(54), 0x5b9cca4f) ++ ROUND(b, c, d, e, f, g, h, a, W(55), 0x682e6ff3) ++ ROUND(a, b, c, d, e, f, g, h, W(56), 0x748f82ee) ++ ROUND(h, a, b, c, d, e, f, g, W(57), 0x78a5636f) ++ ROUND(g, h, a, b, c, d, e, f, W(58), 0x84c87814) ++ ROUND(f, g, h, a, b, c, d, e, W(59), 0x8cc70208) ++ ROUND(e, f, g, h, a, b, c, d, W(60), 0x90befffa) ++ ROUND(d, e, f, g, h, a, b, c, W(61), 0xa4506ceb) ++ ROUND(c, d, e, f, g, h, a, b, W(62), 0xbef9a3f7) ++ ROUND(b, c, d, e, f, g, h, a, W(63), 0xc67178f2) ++ ++ state[0] += a; ++ state[1] += b; ++ state[2] += c; ++ state[3] += d; ++ state[4] += e; ++ state[5] += f; ++ state[6] += g; ++ state[7] += h; ++ ++ /* Zeroize sensitive information. */ ++ memset((unsigned char*) x, 0, sizeof(x)); ++} ++/* }}} */ ++ ++/* {{{ SHA256Encode ++ Encodes input (php_uint32) into output (unsigned char). Assumes len is ++ a multiple of 4. ++ */ ++static void SHA256Encode(output, input, len) ++unsigned char *output; ++php_uint32 *input; ++unsigned int len; ++{ ++ unsigned int i, j; ++ ++ for (i = 0, j = 0; j < len; i++, j += 4) { ++ output[j] = (unsigned char) ((input[i] >> 24) & 0xff); ++ output[j + 1] = (unsigned char) ((input[i] >> 16) & 0xff); ++ output[j + 2] = (unsigned char) ((input[i] >> 8) & 0xff); ++ output[j + 3] = (unsigned char) (input[i] & 0xff); ++ } ++} ++/* }}} */ ++ ++/* {{{ SHA256Decode ++ Decodes input (unsigned char) into output (php_uint32). Assumes len is ++ a multiple of 4. ++ */ ++static void SHA256Decode(output, input, len) ++php_uint32 *output; ++const unsigned char *input; ++unsigned int len; ++{ ++ unsigned int i, j; ++ ++ for (i = 0, j = 0; j < len; i++, j += 4) ++ output[i] = ((php_uint32) input[j + 3]) | (((php_uint32) input[j + 2]) << 8) | ++ (((php_uint32) input[j + 1]) << 16) | (((php_uint32) input[j]) << 24); ++} ++/* }}} */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-5.0.5/ext/standard/sha256.h hardening-patch-5.0.5-0.4.3/ext/standard/sha256.h +--- php-5.0.5/ext/standard/sha256.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/sha256.h 2005-09-11 23:30:52.000000000 +0200 +@@ -0,0 +1,40 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | PHP Version 5 | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 1997-2004 The PHP Group | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 3.0 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available through the world-wide-web at the following url: | ++ | http://www.php.net/license/3_0.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++*/ ++ ++/* $Id: sha256.h,v 1.4 2004/01/08 17:32:52 sniper Exp $ */ ++ ++#ifndef SHA256_H ++#define SHA256_H ++ ++#include "ext/standard/basic_functions.h" ++ ++/* SHA1 context. */ ++typedef struct { ++ php_uint32 state[8]; /* state (ABCD) */ ++ php_uint32 count[2]; /* number of bits, modulo 2^64 (lsb first) */ ++ unsigned char buffer[64]; /* input buffer */ ++} PHP_SHA256_CTX; ++ ++PHPAPI void PHP_SHA256Init(PHP_SHA256_CTX *); ++PHPAPI void PHP_SHA256Update(PHP_SHA256_CTX *, const unsigned char *, unsigned int); ++PHPAPI void PHP_SHA256Final(unsigned char[32], PHP_SHA256_CTX *); ++ ++PHP_FUNCTION(sha256); ++PHP_FUNCTION(sha256_file); ++ ++#endif +diff -Nura php-5.0.5/ext/standard/syslog.c hardening-patch-5.0.5-0.4.3/ext/standard/syslog.c +--- php-5.0.5/ext/standard/syslog.c 2005-07-15 11:29:19.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/ext/standard/syslog.c 2005-09-11 23:30:52.000000000 +0200 +@@ -42,6 +42,7 @@ + */ + PHP_MINIT_FUNCTION(syslog) + { ++#if !HARDENING_PATCH + /* error levels */ + REGISTER_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ + REGISTER_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ +@@ -97,7 +98,7 @@ + /* AIX doesn't have LOG_PERROR */ + REGISTER_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ + #endif +- ++#endif + return SUCCESS; + } + /* }}} */ +diff -Nura php-5.0.5/ext/varfilter/config.m4 hardening-patch-5.0.5-0.4.3/ext/varfilter/config.m4 +--- php-5.0.5/ext/varfilter/config.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/ext/varfilter/config.m4 2005-09-11 23:30:52.000000000 +0200 +@@ -0,0 +1,11 @@ ++dnl ++dnl $Id: config.m4,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++dnl ++ ++PHP_ARG_ENABLE(varfilter, whether to enable Hardening-Patch's variable filter, ++[ --disable-varfilter Disable Hardening-Patch's variable filter], yes) ++ ++if test "$PHP_VARFILTER" != "no"; then ++ AC_DEFINE(HAVE_VARFILTER, 1, [ ]) ++ PHP_NEW_EXTENSION(varfilter, varfilter.c, $ext_shared) ++fi +diff -Nura php-5.0.5/ext/varfilter/CREDITS hardening-patch-5.0.5-0.4.3/ext/varfilter/CREDITS +--- php-5.0.5/ext/varfilter/CREDITS 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/ext/varfilter/CREDITS 2005-09-11 23:30:52.000000000 +0200 +@@ -0,0 +1,2 @@ ++varfilter ++Stefan Esser +\ Kein Zeilenumbruch am Dateiende. +diff -Nura php-5.0.5/ext/varfilter/php_varfilter.h hardening-patch-5.0.5-0.4.3/ext/varfilter/php_varfilter.h +--- php-5.0.5/ext/varfilter/php_varfilter.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/ext/varfilter/php_varfilter.h 2005-09-12 00:03:50.000000000 +0200 +@@ -0,0 +1,112 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: php_varfilter.h,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifndef PHP_VARFILTER_H ++#define PHP_VARFILTER_H ++ ++extern zend_module_entry varfilter_module_entry; ++#define phpext_varfilter_ptr &varfilter_module_entry ++ ++#ifdef PHP_WIN32 ++#define PHP_VARFILTER_API __declspec(dllexport) ++#else ++#define PHP_VARFILTER_API ++#endif ++ ++#ifdef ZTS ++#include "TSRM.h" ++#endif ++ ++#include "SAPI.h" ++ ++#include "php_variables.h" ++ ++ ++PHP_MINIT_FUNCTION(varfilter); ++PHP_MSHUTDOWN_FUNCTION(varfilter); ++PHP_RINIT_FUNCTION(varfilter); ++PHP_RSHUTDOWN_FUNCTION(varfilter); ++PHP_MINFO_FUNCTION(varfilter); ++ ++ ++ZEND_BEGIN_MODULE_GLOBALS(varfilter) ++/* request variables */ ++ long max_request_variables; ++ long cur_request_variables; ++ long max_varname_length; ++ long max_totalname_length; ++ long max_value_length; ++ long max_array_depth; ++ long max_array_index_length; ++/* cookie variables */ ++ long max_cookie_vars; ++ long cur_cookie_vars; ++ long max_cookie_name_length; ++ long max_cookie_totalname_length; ++ long max_cookie_value_length; ++ long max_cookie_array_depth; ++ long max_cookie_array_index_length; ++/* get variables */ ++ long max_get_vars; ++ long cur_get_vars; ++ long max_get_name_length; ++ long max_get_totalname_length; ++ long max_get_value_length; ++ long max_get_array_depth; ++ long max_get_array_index_length; ++/* post variables */ ++ long max_post_vars; ++ long cur_post_vars; ++ long max_post_name_length; ++ long max_post_totalname_length; ++ long max_post_value_length; ++ long max_post_array_depth; ++ long max_post_array_index_length; ++/* fileupload */ ++ long max_uploads; ++ long cur_uploads; ++ zend_bool disallow_elf_files; ++ char *verification_script; ++ ++ZEND_END_MODULE_GLOBALS(varfilter) ++ ++ ++#ifdef ZTS ++#define VARFILTER_G(v) TSRMG(varfilter_globals_id, zend_varfilter_globals *, v) ++#else ++#define VARFILTER_G(v) (varfilter_globals.v) ++#endif ++ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter); ++SAPI_UPLOAD_VARNAME_FILTER_FUNC(varfilter_upload_varname_filter); ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter); ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter); ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter); ++ ++#endif /* PHP_VARFILTER_H */ ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * indent-tabs-mode: t ++ * End: ++ */ +diff -Nura php-5.0.5/ext/varfilter/varfilter.c hardening-patch-5.0.5-0.4.3/ext/varfilter/varfilter.c +--- php-5.0.5/ext/varfilter/varfilter.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/ext/varfilter/varfilter.c 2005-09-12 00:02:31.000000000 +0200 +@@ -0,0 +1,726 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardened-PHP Project's varfilter extension | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ ++ $Id: varfilter.c,v 1.1 2004/11/14 13:27:16 ionic Exp $ ++*/ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "php.h" ++#include "php_ini.h" ++#include "ext/standard/info.h" ++#include "php_varfilter.h" ++#include "hardening_patch.h" ++ ++ZEND_DECLARE_MODULE_GLOBALS(varfilter) ++ ++/* True global resources - no need for thread safety here */ ++static int le_varfilter; ++ ++/* {{{ varfilter_module_entry ++ */ ++zend_module_entry varfilter_module_entry = { ++#if ZEND_MODULE_API_NO >= 20010901 ++ STANDARD_MODULE_HEADER, ++#endif ++ "varfilter", ++ NULL, ++ PHP_MINIT(varfilter), ++ PHP_MSHUTDOWN(varfilter), ++ PHP_RINIT(varfilter), /* Replace with NULL if there's nothing to do at request start */ ++ PHP_RSHUTDOWN(varfilter), /* Replace with NULL if there's nothing to do at request end */ ++ PHP_MINFO(varfilter), ++#if ZEND_MODULE_API_NO >= 20010901 ++ "0.3.2", /* Replace with version number for your extension */ ++#endif ++ STANDARD_MODULE_PROPERTIES ++}; ++/* }}} */ ++ ++#ifdef COMPILE_DL_VARFILTER ++ZEND_GET_MODULE(varfilter) ++#endif ++ ++/* {{{ PHP_INI ++ */ ++PHP_INI_BEGIN() ++ /* for backward compatibility */ ++ STD_PHP_INI_ENTRY("varfilter.max_request_variables", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("varfilter.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.request.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_request_variables, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_varname_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_varname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.request.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.cookie.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_cookie_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_value_length", "10000", PHP_INI_PERDIR, OnUpdateLong, max_cookie_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.cookie.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_cookie_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.get.max_vars", "100", PHP_INI_PERDIR, OnUpdateLong, max_get_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_get_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_value_length", "512", PHP_INI_PERDIR, OnUpdateLong, max_get_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_depth", "50", PHP_INI_PERDIR, OnUpdateLong, max_get_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.get.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_get_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.post.max_vars", "200", PHP_INI_PERDIR, OnUpdateLong, max_post_vars, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_name_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_name_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_totalname_length", "256", PHP_INI_PERDIR, OnUpdateLong, max_post_totalname_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_value_length", "65000", PHP_INI_PERDIR, OnUpdateLong, max_post_value_length, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_depth", "100", PHP_INI_PERDIR, OnUpdateLong, max_post_array_depth, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.post.max_array_index_length", "64", PHP_INI_PERDIR, OnUpdateLong, max_post_array_index_length, zend_varfilter_globals, varfilter_globals) ++ ++ STD_PHP_INI_ENTRY("hphp.upload.max_uploads", "25", PHP_INI_PERDIR, OnUpdateLong, max_uploads, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.disallow_elf_files", "1", PHP_INI_SYSTEM, OnUpdateBool, disallow_elf_files, zend_varfilter_globals, varfilter_globals) ++ STD_PHP_INI_ENTRY("hphp.upload.verification_script", NULL, PHP_INI_SYSTEM, OnUpdateString, verification_script, zend_varfilter_globals, varfilter_globals) ++ ++ ++PHP_INI_END() ++/* }}} */ ++ ++/* {{{ php_varfilter_init_globals ++ */ ++static void php_varfilter_init_globals(zend_varfilter_globals *varfilter_globals) ++{ ++ varfilter_globals->max_request_variables = 200; ++ varfilter_globals->max_varname_length = 64; ++ varfilter_globals->max_value_length = 10000; ++ varfilter_globals->max_array_depth = 100; ++ varfilter_globals->max_totalname_length = 256; ++ varfilter_globals->max_array_index_length = 64; ++ ++ varfilter_globals->max_cookie_vars = 100; ++ varfilter_globals->max_cookie_name_length = 64; ++ varfilter_globals->max_cookie_totalname_length = 256; ++ varfilter_globals->max_cookie_value_length = 10000; ++ varfilter_globals->max_cookie_array_depth = 100; ++ varfilter_globals->max_cookie_array_index_length = 64; ++ ++ varfilter_globals->max_get_vars = 100; ++ varfilter_globals->max_get_name_length = 64; ++ varfilter_globals->max_get_totalname_length = 256; ++ varfilter_globals->max_get_value_length = 512; ++ varfilter_globals->max_get_array_depth = 50; ++ varfilter_globals->max_get_array_index_length = 64; ++ ++ varfilter_globals->max_post_vars = 200; ++ varfilter_globals->max_post_name_length = 64; ++ varfilter_globals->max_post_totalname_length = 256; ++ varfilter_globals->max_post_value_length = 65000; ++ varfilter_globals->max_post_array_depth = 100; ++ varfilter_globals->max_post_array_index_length = 64; ++ ++ varfilter_globals->max_uploads = 25; ++ varfilter_globals->disallow_elf_files = 1; ++ varfilter_globals->verification_script = NULL; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINIT_FUNCTION ++ */ ++PHP_MINIT_FUNCTION(varfilter) ++{ ++ ZEND_INIT_MODULE_GLOBALS(varfilter, php_varfilter_init_globals, NULL); ++ REGISTER_INI_ENTRIES(); ++ ++ sapi_register_input_filter(varfilter_input_filter); ++ sapi_register_upload_varname_filter(varfilter_upload_varname_filter); ++ sapi_register_pre_upload_filter(varfilter_pre_upload_filter); ++ sapi_register_upload_content_filter(varfilter_upload_content_filter); ++ sapi_register_post_upload_filter(varfilter_post_upload_filter); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MSHUTDOWN_FUNCTION ++ */ ++PHP_MSHUTDOWN_FUNCTION(varfilter) ++{ ++ UNREGISTER_INI_ENTRIES(); ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request start */ ++/* {{{ PHP_RINIT_FUNCTION ++ */ ++PHP_RINIT_FUNCTION(varfilter) ++{ ++ VARFILTER_G(cur_request_variables) = 0; ++ VARFILTER_G(cur_get_vars) = 0; ++ VARFILTER_G(cur_post_vars) = 0; ++ VARFILTER_G(cur_cookie_vars) = 0; ++ ++ VARFILTER_G(cur_uploads) = 0; ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* Remove if there's nothing to do at request end */ ++/* {{{ PHP_RSHUTDOWN_FUNCTION ++ */ ++PHP_RSHUTDOWN_FUNCTION(varfilter) ++{ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ PHP_MINFO_FUNCTION ++ */ ++PHP_MINFO_FUNCTION(varfilter) ++{ ++ php_info_print_table_start(); ++ php_info_print_table_header(2, "Hardening-Patch's variable filter support", "enabled"); ++ php_info_print_table_end(); ++ ++ DISPLAY_INI_ENTRIES(); ++} ++/* }}} */ ++ ++/* {{{ normalize_varname ++ */ ++static void normalize_varname(char *varname) ++{ ++ char *s=varname, *index=NULL, *indexend=NULL, *p; ++ ++ /* overjump leading space */ ++ while (*s == ' ') { ++ s++; ++ } ++ ++ /* and remove it */ ++ if (s != varname) { ++ memmove(varname, s, strlen(s)+1); ++ } ++ ++ for (p=varname; *p && *p != '['; p++) { ++ switch(*p) { ++ case ' ': ++ case '.': ++ *p='_'; ++ break; ++ } ++ } ++ ++ /* find index */ ++ index = strchr(varname, '['); ++ if (index) { ++ index++; ++ s=index; ++ } else { ++ return; ++ } ++ ++ /* done? */ ++ while (index) { ++ ++ while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') { ++ index++; ++ } ++ indexend = strchr(index, ']'); ++ indexend = indexend ? indexend + 1 : index + strlen(index); ++ ++ if (s != index) { ++ memmove(s, index, strlen(index)+1); ++ s += indexend-index; ++ } else { ++ s = indexend; ++ } ++ ++ if (*s == '[') { ++ s++; ++ index = s; ++ } else { ++ index = NULL; ++ } ++ } ++ *s++='\0'; ++} ++/* }}} */ ++ ++/* {{{ SAPI_UPLOAD_VARNAME_FILTER_FUNC ++ */ ++SAPI_UPLOAD_VARNAME_FILTER_FUNC(varfilter_upload_varname_filter) ++{ ++ char *index, *prev_index = NULL, *var; ++ unsigned int var_len, total_len, depth = 0; ++ ++ var = estrdup(varname); ++ ++ /* Normalize the variable name */ ++ normalize_varname(var); ++ ++ /* Find length of variable name */ ++ index = strchr(var, '['); ++ total_len = strlen(var); ++ var_len = index ? index-var : total_len; ++ ++ /* Drop this variable if it exceeds the varname/total length limit */ ++ if (VARFILTER_G(max_varname_length) && VARFILTER_G(max_varname_length) < var_len) { ++ php_security_log(S_FILES, "configured request variable name length limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ if (VARFILTER_G(max_totalname_length) && VARFILTER_G(max_totalname_length) < total_len) { ++ php_security_log(S_FILES, "configured request variable total name length limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ if (VARFILTER_G(max_post_name_length) && VARFILTER_G(max_post_name_length) < var_len) { ++ php_security_log(S_FILES, "configured POST variable name length limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ if (VARFILTER_G(max_post_totalname_length) && VARFILTER_G(max_post_totalname_length) < var_len) { ++ php_security_log(S_FILES, "configured POST variable total name length limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ ++ /* Find out array depth */ ++ while (index) { ++ unsigned int index_length; ++ ++ depth++; ++ index = strchr(index+1, '['); ++ ++ if (prev_index) { ++ index_length = index ? index - 1 - prev_index - 1: strlen(prev_index); ++ ++ if (VARFILTER_G(max_array_index_length) && VARFILTER_G(max_array_index_length) < index_length) { ++ php_security_log(S_FILES, "configured request variable array index length limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ if (VARFILTER_G(max_post_array_index_length) && VARFILTER_G(max_post_array_index_length) < index_length) { ++ php_security_log(S_FILES, "configured POST variable array index length limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ prev_index = index; ++ } ++ ++ } ++ ++ /* Drop this variable if it exceeds the array depth limit */ ++ if (VARFILTER_G(max_array_depth) && VARFILTER_G(max_array_depth) < depth) { ++ php_security_log(S_FILES, "configured request variable array depth limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ if (VARFILTER_G(max_post_array_depth) && VARFILTER_G(max_post_array_depth) < depth) { ++ php_security_log(S_FILES, "configured POST variable array depth limit exceeded - dropped %s", var); ++ goto return_failure; ++ } ++ ++ /* Drop this variable if it is one of GLOBALS, _GET, _POST, ... */ ++ /* This is to protect several silly scripts that do globalizing themself */ ++ ++ switch (var_len) { ++ case 18: ++ if (memcmp(var, "HTTP_RAW_POST_DATA", 18)==0) goto protected_varname2; ++ break; ++ case 17: ++ if (memcmp(var, "HTTP_SESSION_VARS", 17)==0) goto protected_varname2; ++ break; ++ case 16: ++ if (memcmp(var, "HTTP_SERVER_VARS", 16)==0) goto protected_varname2; ++ if (memcmp(var, "HTTP_COOKIE_VARS", 16)==0) goto protected_varname2; ++ break; ++ case 15: ++ if (memcmp(var, "HTTP_POST_FILES", 15)==0) goto protected_varname2; ++ break; ++ case 14: ++ if (memcmp(var, "HTTP_POST_VARS", 14)==0) goto protected_varname2; ++ break; ++ case 13: ++ if (memcmp(var, "HTTP_GET_VARS", 13)==0) goto protected_varname2; ++ if (memcmp(var, "HTTP_ENV_VARS", 13)==0) goto protected_varname2; ++ break; ++ case 8: ++ if (memcmp(var, "_SESSION", 8)==0) goto protected_varname2; ++ if (memcmp(var, "_REQUEST", 8)==0) goto protected_varname2; ++ break; ++ case 7: ++ if (memcmp(var, "GLOBALS", 7)==0) goto protected_varname2; ++ if (memcmp(var, "_COOKIE", 7)==0) goto protected_varname2; ++ if (memcmp(var, "_SERVER", 7)==0) goto protected_varname2; ++ break; ++ case 6: ++ if (memcmp(var, "_FILES", 6)==0) goto protected_varname2; ++ break; ++ case 5: ++ if (memcmp(var, "_POST", 5)==0) goto protected_varname2; ++ break; ++ case 4: ++ if (memcmp(var, "_ENV", 4)==0) goto protected_varname2; ++ if (memcmp(var, "_GET", 4)==0) goto protected_varname2; ++ break; ++ } ++ ++ efree(var); ++ return SUCCESS; ++protected_varname2: ++ php_security_log(S_FILES, "tried to register forbidden variable '%s' through FILE variables", var); ++return_failure: ++ efree(var); ++ return FAILURE; ++} ++/* }}} */ ++ ++/* {{{ SAPI_PRE_UPLOAD_FILTER_FUNC ++ */ ++SAPI_PRE_UPLOAD_FILTER_FUNC(varfilter_pre_upload_filter) ++{ ++ /* Drop this fileupload if the limit is reached */ ++ if (VARFILTER_G(max_uploads) && VARFILTER_G(max_uploads) <= VARFILTER_G(cur_uploads)) { ++ php_security_log(S_FILES, "configured fileupload limit exceeded - file dropped"); ++ return FAILURE; ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_UPLOAD_CONTENT_FILTER_FUNC ++ */ ++SAPI_UPLOAD_CONTENT_FILTER_FUNC(varfilter_upload_content_filter) ++{ ++ ++ if (VARFILTER_G(disallow_elf_files)) { ++ ++ if (offset == 0 && buffer_len > 10) { ++ ++ if (buffer[0] == 0x7F && buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F') { ++ php_security_log(S_FILES, "uploaded file is an ELF executable - file dropped"); ++ return FAILURE; ++ } ++ } ++ ++ } ++ ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_POST_UPLOAD_FILTER_FUNC ++ */ ++SAPI_POST_UPLOAD_FILTER_FUNC(varfilter_post_upload_filter) ++{ ++ int retval = SUCCESS; ++ ++ if (VARFILTER_G(verification_script)) { ++ char cmd[8192]; ++ FILE *in; ++ int first=1; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s", VARFILTER_G(verification_script), tmpfilename); ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_FILES, "unable to execute fileupload verification script %s - file dropped", VARFILTER_G(verification_script)); ++ return FAILURE; ++ } ++ ++ retval = FAILURE; ++ ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ if (first) { ++ retval = atoi(cmd) == 1 ? SUCCESS : FAILURE; ++ first = 0; ++ } ++ } ++ pclose(in); ++ } ++ ++ if (retval != SUCCESS) { ++ php_security_log(S_FILES, "fileupload verification script disallows file - file dropped"); ++ return FAILURE; ++ } ++ ++ VARFILTER_G(cur_uploads)++; ++ return SUCCESS; ++} ++/* }}} */ ++ ++/* {{{ SAPI_INPUT_FILTER_FUNC ++ */ ++SAPI_INPUT_FILTER_FUNC(varfilter_input_filter) ++{ ++ char *index, *prev_index = NULL; ++ unsigned int var_len, total_len, depth = 0; ++ ++ /* Drop this variable if the limit is reached */ ++ if (VARFILTER_G(max_request_variables) && VARFILTER_G(max_request_variables) <= VARFILTER_G(cur_request_variables)) { ++ php_security_log(S_VARS, "configured request variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_vars) && VARFILTER_G(max_get_vars) <= VARFILTER_G(cur_get_vars)) { ++ php_security_log(S_VARS, "configured GET variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_vars) && VARFILTER_G(max_cookie_vars) <= VARFILTER_G(cur_cookie_vars)) { ++ php_security_log(S_VARS, "configured COOKIE variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_vars) && VARFILTER_G(max_post_vars) <= VARFILTER_G(cur_post_vars)) { ++ php_security_log(S_VARS, "configured POST variable limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ ++ /* Drop this variable if it exceeds the value length limit */ ++ if (VARFILTER_G(max_value_length) && VARFILTER_G(max_value_length) < val_len) { ++ php_security_log(S_VARS, "configured request variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_value_length) && VARFILTER_G(max_get_value_length) < val_len) { ++ php_security_log(S_VARS, "configured GET variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_value_length) && VARFILTER_G(max_cookie_value_length) < val_len) { ++ php_security_log(S_VARS, "configured COOKIE variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_value_length) && VARFILTER_G(max_post_value_length) < val_len) { ++ php_security_log(S_VARS, "configured POST variable value length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Normalize the variable name */ ++ normalize_varname(var); ++ ++ /* Find length of variable name */ ++ index = strchr(var, '['); ++ total_len = strlen(var); ++ var_len = index ? index-var : total_len; ++ ++ /* Drop this variable if it exceeds the varname/total length limit */ ++ if (VARFILTER_G(max_varname_length) && VARFILTER_G(max_varname_length) < var_len) { ++ php_security_log(S_VARS, "configured request variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_totalname_length) && VARFILTER_G(max_totalname_length) < total_len) { ++ php_security_log(S_VARS, "configured request variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_name_length) && VARFILTER_G(max_get_name_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_get_totalname_length) && VARFILTER_G(max_get_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured GET variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_name_length) && VARFILTER_G(max_cookie_name_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_cookie_totalname_length) && VARFILTER_G(max_cookie_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured COOKIE variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_name_length) && VARFILTER_G(max_post_name_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ if (VARFILTER_G(max_post_totalname_length) && VARFILTER_G(max_post_totalname_length) < var_len) { ++ php_security_log(S_VARS, "configured POST variable total name length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Find out array depth */ ++ while (index) { ++ unsigned int index_length; ++ ++ depth++; ++ index = strchr(index+1, '['); ++ ++ if (prev_index) { ++ index_length = index ? index - 1 - prev_index - 1: strlen(prev_index); ++ ++ if (VARFILTER_G(max_array_index_length) && VARFILTER_G(max_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured request variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_index_length) && VARFILTER_G(max_get_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured GET variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_index_length) && VARFILTER_G(max_cookie_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured COOKIE variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_index_length) && VARFILTER_G(max_post_array_index_length) < index_length) { ++ php_security_log(S_VARS, "configured POST variable array index length limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ prev_index = index; ++ } ++ ++ } ++ ++ /* Drop this variable if it exceeds the array depth limit */ ++ if (VARFILTER_G(max_array_depth) && VARFILTER_G(max_array_depth) < depth) { ++ php_security_log(S_VARS, "configured request variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ switch (arg) { ++ case PARSE_GET: ++ if (VARFILTER_G(max_get_array_depth) && VARFILTER_G(max_get_array_depth) < depth) { ++ php_security_log(S_VARS, "configured GET variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_COOKIE: ++ if (VARFILTER_G(max_cookie_array_depth) && VARFILTER_G(max_cookie_array_depth) < depth) { ++ php_security_log(S_VARS, "configured COOKIE variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ case PARSE_POST: ++ if (VARFILTER_G(max_post_array_depth) && VARFILTER_G(max_post_array_depth) < depth) { ++ php_security_log(S_VARS, "configured POST variable array depth limit exceeded - dropped %s", var); ++ return 0; ++ } ++ break; ++ } ++ ++ /* Drop this variable if it is one of GLOBALS, _GET, _POST, ... */ ++ /* This is to protect several silly scripts that do globalizing themself */ ++ ++ switch (var_len) { ++ case 18: ++ if (memcmp(var, "HTTP_RAW_POST_DATA", 18)==0) goto protected_varname; ++ break; ++ case 17: ++ if (memcmp(var, "HTTP_SESSION_VARS", 17)==0) goto protected_varname; ++ break; ++ case 16: ++ if (memcmp(var, "HTTP_SERVER_VARS", 16)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_COOKIE_VARS", 16)==0) goto protected_varname; ++ break; ++ case 15: ++ if (memcmp(var, "HTTP_POST_FILES", 15)==0) goto protected_varname; ++ break; ++ case 14: ++ if (memcmp(var, "HTTP_POST_VARS", 14)==0) goto protected_varname; ++ break; ++ case 13: ++ if (memcmp(var, "HTTP_GET_VARS", 13)==0) goto protected_varname; ++ if (memcmp(var, "HTTP_ENV_VARS", 13)==0) goto protected_varname; ++ break; ++ case 8: ++ if (memcmp(var, "_SESSION", 8)==0) goto protected_varname; ++ if (memcmp(var, "_REQUEST", 8)==0) goto protected_varname; ++ break; ++ case 7: ++ if (memcmp(var, "GLOBALS", 7)==0) goto protected_varname; ++ if (memcmp(var, "_COOKIE", 7)==0) goto protected_varname; ++ if (memcmp(var, "_SERVER", 7)==0) goto protected_varname; ++ break; ++ case 6: ++ if (memcmp(var, "_FILES", 6)==0) goto protected_varname; ++ break; ++ case 5: ++ if (memcmp(var, "_POST", 5)==0) goto protected_varname; ++ break; ++ case 4: ++ if (memcmp(var, "_ENV", 4)==0) goto protected_varname; ++ if (memcmp(var, "_GET", 4)==0) goto protected_varname; ++ break; ++ } ++ ++ /* Okay let PHP register this variable */ ++ VARFILTER_G(cur_request_variables)++; ++ switch (arg) { ++ case PARSE_GET: ++ VARFILTER_G(cur_get_vars)++; ++ break; ++ case PARSE_COOKIE: ++ VARFILTER_G(cur_cookie_vars)++; ++ break; ++ case PARSE_POST: ++ VARFILTER_G(cur_post_vars)++; ++ break; ++ } ++ ++ if (new_val_len) { ++ *new_val_len = val_len; ++ } ++ ++ return 1; ++protected_varname: ++ php_security_log(S_VARS, "tried to register forbidden variable '%s' through %s variables", var, arg == PARSE_GET ? "GET" : arg == PARSE_POST ? "POST" : "COOKIE"); ++ return 0; ++} ++/* }}} */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: noet sw=4 ts=4 fdm=marker ++ * vim<600: noet sw=4 ts=4 ++ */ ++ ++ +diff -Nura php-5.0.5/main/fopen_wrappers.c hardening-patch-5.0.5-0.4.3/main/fopen_wrappers.c +--- php-5.0.5/main/fopen_wrappers.c 2005-07-16 14:14:44.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/main/fopen_wrappers.c 2005-09-11 23:30:52.000000000 +0200 +@@ -155,6 +155,21 @@ + char *pathbuf; + char *ptr; + char *end; ++ char path_copy[MAXPATHLEN]; ++ int path_len; ++ ++ /* Special case path ends with a trailing slash */ ++ path_len = strlen(path); ++ if (path_len >= MAXPATHLEN) { ++ errno = EPERM; /* we deny permission to open it */ ++ return -1; ++ } ++ if (path_len > 0 && path[path_len-1] == PHP_DIR_SEPARATOR) { ++ memcpy(path_copy, path, path_len+1); ++ while (path_len > 0 && path_copy[path_len-1] == PHP_DIR_SEPARATOR) path_len--; ++ path_copy[path_len] = '\0'; ++ path = (const char *)&path_copy; ++ } + + pathbuf = estrdup(PG(open_basedir)); + +diff -Nura php-5.0.5/main/hardened_globals.h hardening-patch-5.0.5-0.4.3/main/hardened_globals.h +--- php-5.0.5/main/hardened_globals.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/main/hardened_globals.h 2005-09-12 17:03:36.000000000 +0200 +@@ -0,0 +1,62 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENED_GLOBALS_H ++#define HARDENED_GLOBALS_H ++ ++typedef struct _hardened_globals hardened_globals_struct; ++ ++#ifdef ZTS ++# define HG(v) TSRMG(hardened_globals_id, hardened_globals_struct *, v) ++extern int hardened_globals_id; ++#else ++# define HG(v) (hardened_globals.v) ++extern struct _hardened_globals hardened_globals; ++#endif ++ ++ ++struct _hardened_globals { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_1; ++ unsigned int canary_2; ++#endif ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_3; ++ unsigned int canary_4; ++ unsigned int ll_canary_inited; ++#endif ++ zend_bool hphp_sql_bailout_on_error; ++ zend_bool hphp_multiheader; ++ HashTable *eval_whitelist; ++ HashTable *eval_blacklist; ++ HashTable *func_whitelist; ++ HashTable *func_blacklist; ++ HashTable *include_whitelist; ++ HashTable *include_blacklist; ++ unsigned int dummy; ++}; ++ ++ ++#endif /* HARDENED_GLOBALS_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nura php-5.0.5/main/hardening_patch.c hardening-patch-5.0.5-0.4.3/main/hardening_patch.c +--- php-5.0.5/main/hardening_patch.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/main/hardening_patch.c 2005-09-12 18:09:56.000000000 +0200 +@@ -0,0 +1,424 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: hardening_patch.c,v 1.2 2004/11/21 09:38:52 ionic Exp $ */ ++ ++#include "php.h" ++ ++#include ++#include ++ ++#if HAVE_UNISTD_H ++#include ++#endif ++#include "SAPI.h" ++#include "php_globals.h" ++ ++#if HARDENING_PATCH ++ ++#ifdef HAVE_SYS_SOCKET_H ++#include ++#endif ++ ++#if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE) ++#undef AF_UNIX ++#endif ++ ++#if defined(AF_UNIX) ++#include ++#endif ++ ++#define SYSLOG_PATH "/dev/log" ++ ++#include "snprintf.h" ++ ++#include "hardening_patch.h" ++ ++#ifdef ZTS ++#include "hardened_globals.h" ++int hardened_globals_id; ++#else ++struct _hardened_globals hardened_globals; ++#endif ++ ++static void hardened_globals_ctor(hardened_globals_struct *hardened_globals TSRMLS_DC) ++{ ++ memset(hardened_globals, 0, sizeof(*hardened_globals)); ++} ++ ++ ++PHPAPI void hardened_startup() ++{ ++#ifdef ZTS ++ ts_allocate_id(&hardened_globals_id, sizeof(hardened_globals_struct), (ts_allocate_ctor) hardened_globals_ctor, NULL); ++#else ++ hardened_globals_ctor(&hardened_globals TSRMLS_CC); ++#endif ++} ++ ++char *loglevel2string(int loglevel) ++{ ++ switch (loglevel) { ++ case S_FILES: ++ return "FILES"; ++ case S_INCLUDE: ++ return "INCLUDE"; ++ case S_MEMORY: ++ return "MEMORY"; ++ case S_MISC: ++ return "MISC"; ++ case S_SQL: ++ return "SQL"; ++ case S_EXECUTOR: ++ return "EXECUTOR"; ++ case S_VARS: ++ return "VARS"; ++ default: ++ return "UNKNOWN"; ++ } ++} ++ ++PHPAPI void php_security_log(int loglevel, char *fmt, ...) ++{ ++#if defined(AF_UNIX) ++ int s, r, i=0; ++ struct sockaddr_un saun; ++ char buf[4096+64]; ++ char error[4096+100]; ++ char *ip_address; ++ char *fname; ++ int lineno; ++ va_list ap; ++ TSRMLS_FETCH(); ++ ++ if (EG(hphp_log_use_x_forwarded_for)) { ++ ip_address = sapi_getenv("HTTP_X_FORWARDED_FOR", 20 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "X-FORWARDED-FOR not set"; ++ } ++ } else { ++ ip_address = sapi_getenv("REMOTE_ADDR", 11 TSRMLS_CC); ++ if (ip_address == NULL) { ++ ip_address = "REMOTE_ADDR not set"; ++ } ++ } ++ ++ ++ va_start(ap, fmt); ++ ap_php_vsnprintf(error, sizeof(error), fmt, ap); ++ va_end(ap); ++ while (error[i]) { ++ if (error[i] < 32) error[i] = '.'; ++ i++; ++ } ++ ++ if (zend_is_executing(TSRMLS_C)) { ++ lineno = zend_get_executed_lineno(TSRMLS_C); ++ fname = zend_get_executed_filename(TSRMLS_C); ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s', line %u)", error, ip_address, fname, lineno); ++ } else { ++ fname = sapi_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC); ++ if (fname==NULL) { ++ fname = "unknown"; ++ } ++ ap_php_snprintf(buf, sizeof(buf), "ALERT - %s (attacker '%s', file '%s')", error, ip_address, fname); ++ } ++ ++ /* Syslog-Logging disabled? */ ++ if ((EG(hphp_log_syslog) & loglevel)==0) { ++ goto log_sapi; ++ } ++ ++ ap_php_snprintf(error, sizeof(error), "<%u>hphp[%u]: %s\n", EG(hphp_log_syslog_facility)|EG(hphp_log_syslog_priority),getpid(),buf); ++ ++ s = socket(AF_UNIX, SOCK_DGRAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ s = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (s == -1) { ++ goto log_sapi; ++ } ++ ++ memset(&saun, 0, sizeof(saun)); ++ saun.sun_family = AF_UNIX; ++ strcpy(saun.sun_path, SYSLOG_PATH); ++ /*saun.sun_len = sizeof(saun);*/ ++ ++ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); ++ if (r) { ++ close(s); ++ goto log_sapi; ++ } ++ } ++ send(s, error, strlen(error), 0); ++ ++ close(s); ++ ++log_sapi: ++ /* SAPI Logging activated? */ ++ if ((EG(hphp_log_syslog) & loglevel)!=0) { ++ sapi_module.log_message(buf); ++ } ++ ++log_script: ++ /* script logging activaed? */ ++ if (((EG(hphp_log_script) & loglevel)!=0) && EG(hphp_log_scriptname)!=NULL) { ++ char cmd[8192], *cmdpos, *bufpos; ++ FILE *in; ++ int space; ++ ++ ap_php_snprintf(cmd, sizeof(cmd), "%s %s \'", EG(hphp_log_scriptname), loglevel2string(loglevel)); ++ space = sizeof(cmd) - strlen(cmd); ++ cmdpos = cmd + strlen(cmd); ++ bufpos = buf; ++ if (space <= 1) return; ++ while (space > 2 && *bufpos) { ++ if (*bufpos == '\'') { ++ if (space<=5) break; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\\'; ++ *cmdpos++ = '\''; ++ *cmdpos++ = '\''; ++ bufpos++; ++ space-=4; ++ } else { ++ *cmdpos++ = *bufpos++; ++ space--; ++ } ++ } ++ *cmdpos++ = '\''; ++ *cmdpos = 0; ++ ++ if ((in=VCWD_POPEN(cmd, "r"))==NULL) { ++ php_security_log(S_INTERNAL, "Unable to execute logging shell script: %s", EG(hphp_log_scriptname)); ++ return; ++ } ++ /* read and forget the result */ ++ while (1) { ++ int readbytes = fread(cmd, 1, sizeof(cmd), in); ++ if (readbytes<=0) { ++ break; ++ } ++ } ++ pclose(in); ++ } ++ ++#endif ++} ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++PHPAPI unsigned int php_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++ ++PHPAPI int php_is_valid_include(zval *z) ++{ ++ char *filename; ++ int len, i; ++ TSRMLS_FETCH(); ++ ++ /* must be of type string */ ++ if (z->type != IS_STRING || z->value.str.val == NULL) { ++ return (0); ++ } ++ ++ /* short cut */ ++ filename = z->value.str.val; ++ len = z->value.str.len; ++ ++ /* 1. must be shorter than MAXPATHLEN */ ++ if (len > MAXPATHLEN) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename ('%s') longer than MAXPATHLEN chars", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 2. must not be cutted */ ++ if (len != strlen(filename)) { ++ char *fname = estrndup(filename, len); ++ for (i=0; fname[i]; i++) if (fname[i] < 32) fname[i]='.'; ++ php_security_log(S_INCLUDE, "Include filename truncated by a \\0 after '%s'", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* 3. when it is an URL first check black/whitelist if both are empty disallow all URLs */ ++ if (strstr(filename, "://")) { ++ char *fname = estrndup(filename, len); ++ for (i=0; i < len; i++) if (fname[i] < 32) fname[i]='.'; ++ ++ /* no black or whitelist then disallow all */ ++ if (HG(include_whitelist)==NULL && HG(include_blacklist)==NULL) { ++ php_security_log(S_INCLUDE, "Include filename ('%s') is an URL", fname); ++ efree(fname); ++ return (0); ++ } ++ ++ /* whitelist is stronger than blacklist */ ++ if (HG(include_whitelist)) { ++ char *s, *t, *h, *index; ++ uint indexlen; ++ ulong numindex; ++ ++ s = filename; ++ ++ do { ++ zend_bool isOk = 0; ++ int tlen; ++ ++ t = h = strstr(s, "://"); ++ if (h == NULL) break; ++ ++ ++ while (t > s && (isalpha(t[-1]) || t[-1]=='_')) { ++ t--; ++ } ++ ++ tlen = strlen(t); ++ ++ zend_hash_internal_pointer_reset(HG(include_whitelist)); ++ do { ++ int r = zend_hash_get_current_key_ex(HG(include_whitelist), &index, &indexlen, &numindex, 0, NULL); ++ ++ if (r==HASH_KEY_NON_EXISTANT) { ++ break; ++ } ++ if (r==HASH_KEY_IS_STRING) { ++ if (h-t <= indexlen-1 && tlen>=indexlen-1) { ++ if (strncmp(t, index, indexlen-1)==0) { ++ isOk = 1; ++ break; ++ } ++ } ++ } ++ ++ zend_hash_move_forward(HG(include_whitelist)); ++ } while (1); ++ ++ /* not found in whitelist */ ++ if (!isOk) { ++ php_security_log(S_INCLUDE, "Include filename ('%s') is an URL that is not allowed in whitelist", fname); ++ efree(fname); ++ return 0; ++ } ++ ++ s = h + 3; ++ } while (1); ++ } else { ++ /* okay then handle the blacklist */ ++ char *s, *t, *h, *index; ++ uint indexlen; ++ ulong numindex; ++ ++ s = filename; ++ ++ do { ++ int tlen; ++ ++ t = h = strstr(s, "://"); ++ if (h == NULL) break; ++ ++ ++ while (t > s) { ++ if (isalpha(t[-1]) || t[-1]=='_') t--; ++ } ++ ++ tlen = strlen(t); ++ ++ zend_hash_internal_pointer_reset(HG(include_blacklist)); ++ do { ++ int r = zend_hash_get_current_key_ex(HG(include_blacklist), &index, &indexlen, &numindex, 0, NULL); ++ ++ if (r==HASH_KEY_NON_EXISTANT) { ++ break; ++ } ++ if (r==HASH_KEY_IS_STRING) { ++ if (h-t <= indexlen-1 && tlen>=indexlen-1) { ++ if (strncmp(t, index, indexlen-1)==0) { ++ php_security_log(S_INCLUDE, "Include filename ('%s') is an URL that is forbidden by the blacklist", fname); ++ efree(fname); ++ return 0; ++ } ++ } ++ } ++ ++ zend_hash_move_forward(HG(include_blacklist)); ++ } while (1); ++ ++ s = h + 3; ++ } while (1); ++ } ++ ++ efree(fname); ++ } ++ ++ /* 4. must not be an uploaded file */ ++ if (SG(rfc1867_uploaded_files)) { ++ if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) filename, len+1)) { ++ php_security_log(S_INCLUDE, "Include filename is an uploaded file"); ++ return (0); ++ } ++ } ++ ++ /* passed all tests */ ++ return (1); ++} ++ ++#endif ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-5.0.5/main/hardening_patch.h hardening-patch-5.0.5-0.4.3/main/hardening_patch.h +--- php-5.0.5/main/hardening_patch.h 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/main/hardening_patch.h 2005-09-11 23:43:23.000000000 +0200 +@@ -0,0 +1,46 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++ ++#ifndef HARDENING_PATCH_H ++#define HARDENING_PATCH_H ++ ++#include "zend.h" ++ ++#if HARDENING_PATCH ++PHPAPI void php_security_log(int loglevel, char *fmt, ...); ++PHPAPI void hardened_startup(); ++#define HARDENING_PATCH_VERSION "0.4.3" ++ ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++PHPAPI unsigned int php_canary(); ++#endif ++ ++#if HARDENING_PATCH_INC_PROTECT ++PHPAPI int php_is_valid_include(zval *z); ++#endif ++ ++#endif /* HARDENING_PATCH_H */ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ */ +diff -Nura php-5.0.5/main/hardening_patch.m4 hardening-patch-5.0.5-0.4.3/main/hardening_patch.m4 +--- php-5.0.5/main/hardening_patch.m4 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/main/hardening_patch.m4 2005-09-11 23:30:52.000000000 +0200 +@@ -0,0 +1,95 @@ ++dnl ++dnl $Id: hardening_patch.m4,v 1.1 2004/11/14 13:24:24 ionic Exp $ ++dnl ++dnl This file contains Hardening Patch for PHP specific autoconf functions. ++dnl ++ ++AC_ARG_ENABLE(hardening-patch-mm-protect, ++[ --disable-hardening-patch-mm-protect Disable the Memory Manager protection.],[ ++ DO_HARDENING_PATCH_MM_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_MM_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-ll-protect, ++[ --disable-hardening-patch-ll-protect Disable the Linked List protection.],[ ++ DO_HARDENING_PATCH_LL_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_LL_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-inc-protect, ++[ --disable-hardening-patch-inc-protect Disable include/require protection.],[ ++ DO_HARDENING_PATCH_INC_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_INC_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-fmt-protect, ++[ --disable-hardening-patch-fmt-protect Disable format string protection.],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_FMT_PROTECT=yes ++]) ++ ++AC_ARG_ENABLE(hardening-patch-hash-protect, ++[ --disable-hardening-patch-hash-protect Disable HashTable destructor protection.],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=$enableval ++],[ ++ DO_HARDENING_PATCH_HASH_PROTECT=yes ++]) ++ ++AC_MSG_CHECKING(whether to protect the Zend Memory Manager) ++AC_MSG_RESULT($DO_HARDENING_PATCH_MM_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the Zend Linked Lists) ++AC_MSG_RESULT($DO_HARDENING_PATCH_LL_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect include/require statements) ++AC_MSG_RESULT($DO_HARDENING_PATCH_INC_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect PHP Format String functions) ++AC_MSG_RESULT($DO_HARDENING_PATCH_FMT_PROTECT) ++ ++AC_MSG_CHECKING(whether to protect the destructor of Zend HashTables) ++AC_MSG_RESULT($DO_HARDENING_PATCH_HASH_PROTECT) ++ ++ ++AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ ++ ++if test "$DO_HARDENING_PATCH_MM_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 1, [Memory Manager Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_MM_PROTECT, 0, [Memory Manager Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_LL_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 1, [Linked List Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_LL_PROTECT, 0, [Linked List Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_INC_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 1, [Include/Require Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_INC_PROTECT, 0, [Include/Require Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_FMT_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 1, [Fmt String Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_FMT_PROTECT, 0, [Fmt String Protection]) ++fi ++ ++if test "$DO_HARDENING_PATCH_HASH_PROTECT" = "yes"; then ++dnl AC_DEFINE(HARDENING_PATCH, 1, [Hardening Patch]) ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 1, [HashTable DTOR Protection]) ++else ++ AC_DEFINE(HARDENING_PATCH_HASH_PROTECT, 0, [HashTable DTOR Protection]) ++fi ++ +diff -Nura php-5.0.5/main/main.c hardening-patch-5.0.5-0.4.3/main/main.c +--- php-5.0.5/main/main.c 2005-08-16 20:11:34.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/main/main.c 2005-09-11 23:30:52.000000000 +0200 +@@ -85,6 +85,10 @@ + + #include "SAPI.h" + #include "rfc1867.h" ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#endif ++ + /* }}} */ + + #ifndef ZTS +@@ -109,10 +113,33 @@ + */ + static PHP_INI_MH(OnChangeMemoryLimit) + { ++#if HARDENING_PATCH ++ long orig_memory_limit; ++ ++ if (entry->modified) { ++ orig_memory_limit = zend_atoi(entry->orig_value, entry->orig_value_length); ++ } else { ++ orig_memory_limit = 1<<30; ++ } ++ if (orig_memory_limit < 0 || orig_memory_limit > (1<<30)) { ++ orig_memory_limit = 1<<30; ++ } ++#endif + if (new_value) { + PG(memory_limit) = zend_atoi(new_value, new_value_length); ++#if HARDENING_PATCH ++ if (PG(memory_limit) > orig_memory_limit) { ++ PG(memory_limit) = orig_memory_limit; ++ php_security_log(S_MISC, "script tried to increase memory_limit above allowed value"); ++ return FAILURE; ++ } ++#endif + } else { ++#if HARDENING_PATCH ++ PG(memory_limit) = orig_memory_limit; ++#else + PG(memory_limit) = 1<<30; /* effectively, no limit */ ++#endif + } + return zend_set_memory_limit(PG(memory_limit)); + } +@@ -1322,6 +1349,10 @@ + tsrm_ls = ts_resource(0); + #endif + ++#if HARDENING_PATCH ++ hardened_startup(); ++#endif ++ + module_shutdown = 0; + module_startup = 1; + sapi_initialize_empty_request(TSRMLS_C); +@@ -1335,6 +1366,12 @@ + + php_output_startup(); + ++#if HARDENING_PATCH_INC_PROTECT ++ zuf.is_valid_include = php_is_valid_include; ++#endif ++#if HARDENING_PATCH ++ zuf.security_log_function = php_security_log; ++#endif + zuf.error_function = php_error_cb; + zuf.printf_function = php_printf; + zuf.write_function = php_body_write_wrapper; +@@ -1438,6 +1475,10 @@ + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, sizeof(PHP_CONFIG_FILE_PATH)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("HARDENING_PATCH", 1, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_STRINGL_CONSTANT("HARDENING_PATCH_VERSION", HARDENING_PATCH_VERSION, sizeof(HARDENING_PATCH_VERSION)-1, CONST_PERSISTENT | CONST_CS); ++#endif + REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("PHP_INT_MAX", LONG_MAX, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", sizeof(long), CONST_PERSISTENT | CONST_CS); +diff -Nura php-5.0.5/main/php_config.h.in hardening-patch-5.0.5-0.4.3/main/php_config.h.in +--- php-5.0.5/main/php_config.h.in 2005-09-05 13:16:27.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/main/php_config.h.in 2005-09-11 23:30:52.000000000 +0200 +@@ -752,6 +752,39 @@ + /* Enabling BIND8 compatibility for Panther */ + #undef BIND_8_COMPAT + ++/* Hardening-Patch for PHP */ ++#undef HARDENING_PATCH ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Memory Manager Protection */ ++#undef HARDENING_PATCH_MM_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Linked List Protection */ ++#undef HARDENING_PATCH_LL_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Include/Require Protection */ ++#undef HARDENING_PATCH_INC_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* Fmt String Protection */ ++#undef HARDENING_PATCH_FMT_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ ++/* HashTable DTOR Protection */ ++#undef HARDENING_PATCH_HASH_PROTECT ++ + /* Whether you have AOLserver */ + #undef HAVE_AOLSERVER + +@@ -1083,6 +1116,12 @@ + /* Define if you have the getaddrinfo function */ + #undef HAVE_GETADDRINFO + ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ ++/* Whether realpath is broken */ ++#undef PHP_BROKEN_REALPATH ++ + /* Whether system headers declare timezone */ + #undef HAVE_DECLARED_TIMEZONE + +diff -Nura php-5.0.5/main/php.h hardening-patch-5.0.5-0.4.3/main/php.h +--- php-5.0.5/main/php.h 2005-06-29 08:41:15.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/main/php.h 2005-09-11 23:30:52.000000000 +0200 +@@ -35,11 +35,19 @@ + #include "zend_qsort.h" + #include "php_compat.h" + ++ + #include "zend_API.h" + + #undef sprintf + #define sprintf php_sprintf + ++#if HARDENING_PATCH ++#if HAVE_REALPATH ++#undef realpath ++#define realpath php_realpath ++#endif ++#endif ++ + /* PHP's DEBUG value must match Zend's ZEND_DEBUG value */ + #undef PHP_DEBUG + #define PHP_DEBUG ZEND_DEBUG +@@ -330,6 +338,7 @@ + #define PHP_FUNCTION ZEND_FUNCTION + #define PHP_METHOD ZEND_METHOD + ++#define PHP_STATIC_FE ZEND_STATIC_FE + #define PHP_NAMED_FE ZEND_NAMED_FE + #define PHP_FE ZEND_FE + #define PHP_FALIAS ZEND_FALIAS +@@ -435,6 +444,10 @@ + #endif + #endif /* !XtOffsetOf */ + ++#if HARDENING_PATCH ++#include "hardening_patch.h" ++#endif ++ + #endif + + /* +diff -Nura php-5.0.5/main/php_variables.c hardening-patch-5.0.5-0.4.3/main/php_variables.c +--- php-5.0.5/main/php_variables.c 2005-09-01 21:15:51.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/main/php_variables.c 2005-09-11 23:30:52.000000000 +0200 +@@ -514,7 +514,7 @@ + */ + static inline void php_register_server_variables(TSRMLS_D) + { +- zval *array_ptr=NULL; ++ zval *array_ptr=NULL, *vptr; + /* turn off magic_quotes while importing server variables */ + int magic_quotes_gpc = PG(magic_quotes_gpc); + +@@ -530,6 +530,16 @@ + /* Server variables */ + if (sapi_module.register_server_variables) { + sapi_module.register_server_variables(array_ptr TSRMLS_CC); ++ if (zend_hash_find(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA"), (void **)&vptr)==SUCCESS) { ++ char *str; ++ if (vptr->type != IS_STRING) { ++ str = "Array"; ++ } else { ++ str = vptr->value.str.val; ++ } ++ php_security_log(S_VARS, "Attacker tried to overwrite HTTP_RAW_POST_DATA with '%s' through a HTTP header", str); ++ zend_hash_del(array_ptr->value.ht, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA")); ++ } + } + + /* PHP Authentication support */ +diff -Nura php-5.0.5/main/rfc1867.c hardening-patch-5.0.5-0.4.3/main/rfc1867.c +--- php-5.0.5/main/rfc1867.c 2005-07-13 22:51:12.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/main/rfc1867.c 2005-09-11 23:58:14.000000000 +0200 +@@ -132,6 +132,7 @@ + #define UPLOAD_ERROR_D 4 /* No file uploaded */ + #define UPLOAD_ERROR_E 6 /* Missing /tmp or similar directory */ + #define UPLOAD_ERROR_F 7 /* Failed to write file to disk */ ++#define UPLOAD_ERROR_X 32 /* Filter forbids fileupload */ + + void php_rfc1867_register_constants(TSRMLS_D) + { +@@ -142,6 +143,7 @@ + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE", UPLOAD_ERROR_D, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_CANT_WRITE", UPLOAD_ERROR_F, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FILTER", UPLOAD_ERROR_X, CONST_CS | CONST_PERSISTENT); + } + + static void normalize_protected_variable(char *varname TSRMLS_DC) +@@ -854,6 +856,7 @@ + char buff[FILLUNIT]; + char *cd=NULL,*param=NULL,*filename=NULL, *tmp=NULL; + int blen=0, wlen=0; ++ unsigned long offset; + + zend_llist_clean(&header); + +@@ -970,7 +973,11 @@ + tmp++; + } + } +- ++ ++ if (sapi_module.upload_varname_filter && sapi_module.upload_varname_filter(param TSRMLS_CC)==FAILURE) { ++ skip_upload = 1; ++ } ++ + total_bytes = cancel_upload = 0; + + if (!skip_upload) { +@@ -994,6 +1001,11 @@ + cancel_upload = UPLOAD_ERROR_D; + } + ++ if (sapi_module.pre_upload_filter && sapi_module.pre_upload_filter(param, filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_X; ++ } ++ ++ offset = 0; + end = 0; + while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC))) + { +@@ -1008,6 +1020,10 @@ + #endif + cancel_upload = UPLOAD_ERROR_B; + } else if (blen > 0) { ++ if (sapi_module.upload_content_filter && sapi_module.upload_content_filter(offset, buff, blen, &blen TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_X; ++ } ++ + wlen = write(fd, buff, blen); + + if (wlen < blen) { +@@ -1036,6 +1052,10 @@ + } + #endif + ++ if (!cancel_upload && sapi_module.post_upload_filter && sapi_module.post_upload_filter(temp_filename TSRMLS_CC)==FAILURE) { ++ cancel_upload = UPLOAD_ERROR_X; ++ } ++ + if (cancel_upload) { + if (temp_filename) { + if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */ +diff -Nura php-5.0.5/main/SAPI.c hardening-patch-5.0.5-0.4.3/main/SAPI.c +--- php-5.0.5/main/SAPI.c 2005-02-22 15:46:15.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/main/SAPI.c 2005-09-12 00:00:07.000000000 +0200 +@@ -821,6 +821,36 @@ + zend_hash_del(&known_post_content_types, post_entry->content_type, post_entry->content_type_len+1); + } + ++SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) ++{ ++ sapi_module.input_filter = input_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_upload_varname_filter(unsigned int (*upload_varname_filter)(char *varname TSRMLS_DC)) ++{ ++ sapi_module.upload_varname_filter = upload_varname_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)) ++{ ++ sapi_module.pre_upload_filter = pre_upload_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)) ++{ ++ sapi_module.upload_content_filter = upload_content_filter; ++ return SUCCESS; ++} ++ ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)) ++{ ++ sapi_module.post_upload_filter = post_upload_filter; ++ return SUCCESS; ++} ++ + + SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D)) + { +@@ -835,11 +865,6 @@ + return SUCCESS; + } + +-SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)) +-{ +- sapi_module.input_filter = input_filter; +- return SUCCESS; +-} + + SAPI_API int sapi_flush(TSRMLS_D) + { +diff -Nura php-5.0.5/main/SAPI.h hardening-patch-5.0.5-0.4.3/main/SAPI.h +--- php-5.0.5/main/SAPI.h 2004-01-08 18:33:04.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/main/SAPI.h 2005-09-12 00:29:07.000000000 +0200 +@@ -103,9 +103,10 @@ + char *current_user; + int current_user_length; + +- /* this is necessary for CLI module */ +- int argc; +- char **argv; ++ /* this is necessary for CLI module */ ++ int argc; ++ char **argv; ++ + } sapi_request_info; + + +@@ -183,6 +184,10 @@ + SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC)); + SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC)); + ++SAPI_API int sapi_register_pre_upload_filter(unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC)); ++SAPI_API int sapi_register_upload_content_filter(unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC)); ++SAPI_API int sapi_register_post_upload_filter(unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC)); ++ + SAPI_API int sapi_flush(TSRMLS_D); + SAPI_API struct stat *sapi_get_stat(TSRMLS_D); + SAPI_API char *sapi_getenv(char *name, size_t name_len TSRMLS_DC); +@@ -245,6 +250,11 @@ + int (*get_target_gid)(gid_t * TSRMLS_DC); + + unsigned int (*input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); ++ ++ unsigned int (*upload_varname_filter)(char *varname TSRMLS_DC); ++ unsigned int (*pre_upload_filter)(char *varname, char *filename TSRMLS_DC); ++ unsigned int (*upload_content_filter)(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC); ++ unsigned int (*post_upload_filter)(char *tmpfilename TSRMLS_DC); + + void (*ini_defaults)(HashTable *configuration_hash); + int phpinfo_as_text; +@@ -270,7 +280,11 @@ + + #define SAPI_DEFAULT_MIMETYPE "text/html" + #define SAPI_DEFAULT_CHARSET "" ++#if HARDENING_PATCH ++#define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION " with Hardening-Patch" ++#else + #define SAPI_PHP_VERSION_HEADER "X-Powered-By: PHP/" PHP_VERSION ++#endif + + #define SAPI_POST_READER_FUNC(post_reader) void post_reader(TSRMLS_D) + #define SAPI_POST_HANDLER_FUNC(post_handler) void post_handler(char *content_type_dup, void *arg TSRMLS_DC) +@@ -278,6 +292,11 @@ + #define SAPI_TREAT_DATA_FUNC(treat_data) void treat_data(int arg, char *str, zval* destArray TSRMLS_DC) + #define SAPI_INPUT_FILTER_FUNC(input_filter) unsigned int input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) + ++#define SAPI_UPLOAD_VARNAME_FILTER_FUNC(upload_varname_filter) unsigned int upload_varname_filter(char *varname TSRMLS_DC) ++#define SAPI_PRE_UPLOAD_FILTER_FUNC(pre_upload_filter) unsigned int pre_upload_filter(char *varname, char *filename TSRMLS_DC) ++#define SAPI_UPLOAD_CONTENT_FILTER_FUNC(upload_content_filter) unsigned int upload_content_filter(unsigned long offset, char *buffer, unsigned int buffer_len, unsigned int *new_buffer_len TSRMLS_DC) ++#define SAPI_POST_UPLOAD_FILTER_FUNC(post_upload_filter) unsigned int post_upload_filter(char *tmpfilename TSRMLS_DC) ++ + BEGIN_EXTERN_C() + SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data); + SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader); +diff -Nura php-5.0.5/main/snprintf.c hardening-patch-5.0.5-0.4.3/main/snprintf.c +--- php-5.0.5/main/snprintf.c 2004-11-16 00:14:40.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/main/snprintf.c 2005-09-11 23:30:52.000000000 +0200 +@@ -1013,7 +1013,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = cc; ++#endif + break; + + /* +diff -Nura php-5.0.5/main/spprintf.c hardening-patch-5.0.5-0.4.3/main/spprintf.c +--- php-5.0.5/main/spprintf.c 2004-04-16 01:04:49.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/main/spprintf.c 2005-09-11 23:30:52.000000000 +0200 +@@ -630,7 +630,11 @@ + + + case 'n': ++#if HARDENING_PATCH_FMT_PROTECT ++ php_security_log(S_MISC, "'n' specifier within format string"); ++#else + *(va_arg(ap, int *)) = xbuf->len; ++#endif + break; + + /* +diff -Nura php-5.0.5/php.ini-dist hardening-patch-5.0.5-0.4.3/php.ini-dist +--- php-5.0.5/php.ini-dist 2005-05-05 14:33:56.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/php.ini-dist 2005-09-12 23:47:08.000000000 +0200 +@@ -1197,6 +1197,197 @@ + ; instead of original one. + soap.wsdl_cache_ttl=86400 + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's Executor options ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++; White-/blacklist for function calls during normal execution ++;hphp.executor.func.whitelist = ord,chr ++;hphp.executor.func.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for function calls during eval() execution ++;hphp.executor.eval.whitelist = ord,chr ++;hphp.executor.eval.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for URLs allowes in include filenames ++; ++; - When both options are not set all URLs are forbidden ++; ++; - When both options are set whitelist is taken and blacklist ignored ++; ++; - An entry in the lists is either a URL sheme like: http, https ++; or the beginning of an URL like: php://input ++; ++;hphp.executor.include.whitelist = cookietest ++;hphp.executor.include.blacklist = http, https, ftp, ftps, php://input, file ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nura php-5.0.5/php.ini-recommended hardening-patch-5.0.5-0.4.3/php.ini-recommended +--- php-5.0.5/php.ini-recommended 2005-05-05 14:33:56.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/php.ini-recommended 2005-09-12 23:53:06.000000000 +0200 +@@ -1255,6 +1255,196 @@ + ; instead of original one. + soap.wsdl_cache_ttl=86400 + ++[hardening-patch] ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's logging ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; ++; hphp.log.syslog - Configures level for alerts reported through syslog ++; hphp.log.sapi - Configures level for alerts reported through SAPI errorlog ++; hphp.log.script - Configures level for alerts reported through external script ++; ++; hphp.log.syslog, hphp.log.sapi, hphp.log.script are bit-fields. ++; Or each number up to get desired Hardening-Patch's reporting level ++; ++; S_ALL - All alerts ++; S_MEMORY - All canary violations and the safe unlink protection use this class ++; S_VARS - All variable filters trigger this class ++; S_FILES - All violation of uploaded files filter use this class ++; S_INCLUDE - The protection against malicious include filenames use this class ++; S_SQL - Failed SQL queries in MySQL are logged with this class ++; S_EXECUTOR - The execution depth protection uses this logging class ++; S_MISC - All other log messages (f.e. format string protection) use this class ++; ++; Example: ++; ++; - Report all alerts (except memory alerts) to the SAPI errorlog, ++; memory alerts through syslog and SQL+Include alerts fo the script ++; ++;hphp.log.syslog = S_MEMORY ++;hphp.log.sapi = S_ALL & ~S_MEMORY ++;hphp.log.script = S_INCLUDE | S_SQL ++; ++; Syslog logging: ++; ++; - Facility configuration: one of the following facilities ++; ++; LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON ++; LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS ++; LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_LOCAL0 ++; LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4 ++; LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7, LOG_PID ++; LOG_CONS, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT ++; LOG_PERROR ++; ++; - Priority configuration: one of the followinf priorities ++; ++; LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_WARNING ++; LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_ERR ++; ++hphp.log.syslog.priority = LOG_ALERT ++hphp.log.syslog.facility = LOG_USER ++; ++; Script logging: ++; ++;hphp.log.script.name = /home/hphp/log_script ++; ++; Alert configuration: ++; ++; - Logged IP addresses from X-Forwarded-For instead of REMOTE_ADDR ++; ++;hphp.log.use-x-forwarded-for = On ++; ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's Executor options ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Execution depth limit ++;hphp.executor.max_depth = 8000 ++ ++; White-/blacklist for function calls during normal execution ++;hphp.executor.func.whitelist = ord,chr ++;hphp.executor.func.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for function calls during eval() execution ++;hphp.executor.eval.whitelist = ord,chr ++;hphp.executor.eval.blacklist = system,shell_exec,popen,proc_open,exec,passthru ++ ++; White-/blacklist for URLs allowes in include filenames ++; ++; - When both options are not set all URLs are forbidden ++; ++; - When both options are set whitelist is taken and blacklist ignored ++; ++; - An entry in the lists is either a URL sheme like: http, https ++; or the beginning of an URL like: php://input ++; ++;hphp.executor.include.whitelist = cookietest ++;hphp.executor.include.blacklist = http, https, ftp, ftps, php://input, file ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's REQUEST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of REQUEST variables ++hphp.request.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.request.max_varname_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.request.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.request.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.request.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.request.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's COOKIE variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.cookie.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.cookie.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.cookie.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.cookie.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.cookie.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.cookie.max_value_length = 10000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's GET variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of COOKIE variables ++hphp.get.max_vars = 100 ++ ++; Limits the length of variable names (without indices) ++hphp.get.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.get.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.get.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.get.max_array_depth = 50 ++ ++; Limits the length of variable values ++hphp.get.max_value_length = 512 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's POST variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of POST variables ++hphp.post.max_vars = 200 ++ ++; Limits the length of variable names (without indices) ++hphp.post.max_name_length = 64 ++ ++; Limits the length of complete variable names (with indices) ++hphp.post.max_totalname_length = 256 ++ ++; Limits the length of array indices ++hphp.post.max_array_index_length = 64 ++ ++; Limits the depth of arrays ++hphp.post.max_array_depth = 100 ++ ++; Limits the length of variable values ++hphp.post.max_value_length = 65000 ++ ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++; Hardening-Patch's fileupload variable filters ; ++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ++ ++; Limits the number of uploadable files ++hphp.upload.max_uploads = 25 ++ ++; Filter out the upload of ELF executables ++hphp.upload.disallow_elf_files = On ++ ++; External filterscript for upload verification ++;hphp.upload.verification_script = /home/hphp/verify_script ++ + ; Local Variables: + ; tab-width: 4 + ; End: +diff -Nura php-5.0.5/sapi/apache/mod_php5.c hardening-patch-5.0.5-0.4.3/sapi/apache/mod_php5.c +--- php-5.0.5/sapi/apache/mod_php5.c 2005-08-01 10:12:42.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/sapi/apache/mod_php5.c 2005-09-11 23:30:52.000000000 +0200 +@@ -455,7 +455,7 @@ + sapi_apache_get_fd, + sapi_apache_force_http_10, + sapi_apache_get_target_uid, +- sapi_apache_get_target_gid ++ sapi_apache_get_target_gid, + }; + /* }}} */ + +@@ -907,7 +907,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component("PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component("PHP/" PHP_VERSION); ++#endif + } + } + #endif +diff -Nura php-5.0.5/sapi/apache2filter/sapi_apache2.c hardening-patch-5.0.5-0.4.3/sapi/apache2filter/sapi_apache2.c +--- php-5.0.5/sapi/apache2filter/sapi_apache2.c 2005-07-16 14:30:10.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/sapi/apache2filter/sapi_apache2.c 2005-09-11 23:30:52.000000000 +0200 +@@ -562,7 +562,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nura php-5.0.5/sapi/apache2handler/sapi_apache2.c hardening-patch-5.0.5-0.4.3/sapi/apache2handler/sapi_apache2.c +--- php-5.0.5/sapi/apache2handler/sapi_apache2.c 2005-09-02 15:51:26.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/sapi/apache2handler/sapi_apache2.c 2005-09-11 23:30:52.000000000 +0200 +@@ -333,7 +333,11 @@ + { + TSRMLS_FETCH(); + if (PG(expose_php)) { ++#if HARDENING_PATCH ++ ap_add_version_component(p, "PHP/" PHP_VERSION " with Hardening-Patch"); ++#else + ap_add_version_component(p, "PHP/" PHP_VERSION); ++#endif + } + } + +diff -Nura php-5.0.5/sapi/cgi/cgi_main.c hardening-patch-5.0.5-0.4.3/sapi/cgi/cgi_main.c +--- php-5.0.5/sapi/cgi/cgi_main.c 2005-04-28 16:24:21.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/sapi/cgi/cgi_main.c 2005-09-11 23:30:52.000000000 +0200 +@@ -1419,11 +1419,19 @@ + SG(headers_sent) = 1; + SG(request_info).no_headers = 1; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit(1); + break; +diff -Nura php-5.0.5/sapi/cli/php_cli.c hardening-patch-5.0.5-0.4.3/sapi/cli/php_cli.c +--- php-5.0.5/sapi/cli/php_cli.c 2005-03-22 16:09:20.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/sapi/cli/php_cli.c 2005-09-11 23:30:52.000000000 +0200 +@@ -694,11 +694,19 @@ + if (php_request_startup(TSRMLS_C)==FAILURE) { + goto err; + } ++#if HARDENING_PATCH ++#if ZEND_DEBUG ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#else ++ php_printf("PHP %s with Hardening-Patch %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, HARDENING_PATCH_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); ++#endif ++#else + #if ZEND_DEBUG + php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #else + php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version()); + #endif ++#endif + php_end_ob_buffers(1 TSRMLS_CC); + exit_status=1; + goto out; +diff -Nura php-5.0.5/TSRM/TSRM.h hardening-patch-5.0.5-0.4.3/TSRM/TSRM.h +--- php-5.0.5/TSRM/TSRM.h 2005-03-11 12:12:07.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/TSRM/TSRM.h 2005-09-11 23:30:52.000000000 +0200 +@@ -33,6 +33,13 @@ + # define TSRM_API + #endif + ++#if HARDENING_PATCH ++# if HAVE_REALPATH ++# undef realpath ++# define realpath php_realpath ++# endif ++#endif ++ + /* Only compile multi-threading functions if we're in ZTS mode */ + #ifdef ZTS + +@@ -88,6 +95,7 @@ + + #define THREAD_HASH_OF(thr,ts) (unsigned long)thr%(unsigned long)ts + ++ + #ifdef __cplusplus + extern "C" { + #endif +diff -Nura php-5.0.5/TSRM/tsrm_virtual_cwd.c hardening-patch-5.0.5-0.4.3/TSRM/tsrm_virtual_cwd.c +--- php-5.0.5/TSRM/tsrm_virtual_cwd.c 2005-07-16 13:50:59.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/TSRM/tsrm_virtual_cwd.c 2005-09-11 23:30:52.000000000 +0200 +@@ -184,6 +184,165 @@ + return p; + } + ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved) ++{ ++ struct stat sb; ++ char *p, *q, *s; ++ size_t left_len, resolved_len; ++ unsigned symlinks; ++ int serrno, slen; ++ int is_dir = 1; ++ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; ++ ++ serrno = errno; ++ symlinks = 0; ++ if (path[0] == '/') { ++ resolved[0] = '/'; ++ resolved[1] = '\0'; ++ if (path[1] == '\0') ++ return (resolved); ++ resolved_len = 1; ++ left_len = strlcpy(left, path + 1, sizeof(left)); ++ } else { ++ if (getcwd(resolved, PATH_MAX) == NULL) { ++ strlcpy(resolved, ".", PATH_MAX); ++ return (NULL); ++ } ++ resolved_len = strlen(resolved); ++ left_len = strlcpy(left, path, sizeof(left)); ++ } ++ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ ++ /* ++ * Iterate over path components in `left'. ++ */ ++ while (left_len != 0) { ++ /* ++ * Extract the next path component and adjust `left' ++ * and its length. ++ */ ++ p = strchr(left, '/'); ++ s = p ? p : left + left_len; ++ if (s - left >= sizeof(next_token)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ memcpy(next_token, left, s - left); ++ next_token[s - left] = '\0'; ++ left_len -= s - left; ++ if (p != NULL) ++ memmove(left, s + 1, left_len + 1); ++ if (resolved[resolved_len - 1] != '/') { ++ if (resolved_len + 1 >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ resolved[resolved_len++] = '/'; ++ resolved[resolved_len] = '\0'; ++ } ++ if (next_token[0] == '\0') ++ continue; ++ else if (strcmp(next_token, ".") == 0) ++ continue; ++ else if (strcmp(next_token, "..") == 0) { ++ /* ++ * Strip the last path component except when we have ++ * single "/" ++ */ ++ if (!is_dir) { ++ errno = ENOENT; ++ return (NULL); ++ } ++ if (resolved_len > 1) { ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ continue; ++ } ++ ++ /* ++ * Append the next path component and lstat() it. If ++ * lstat() fails we still can return successfully if ++ * there are no more path components left. ++ */ ++ resolved_len = strlcat(resolved, next_token, PATH_MAX); ++ if (resolved_len >= PATH_MAX) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ if (lstat(resolved, &sb) != 0) { ++ if (errno == ENOENT && p == NULL) { ++ errno = serrno; ++ return (resolved); ++ } ++ return (NULL); ++ } ++ if (S_ISLNK(sb.st_mode)) { ++ if (symlinks++ > MAXSYMLINKS) { ++ errno = ELOOP; ++ return (NULL); ++ } ++ slen = readlink(resolved, symlink, sizeof(symlink) - 1); ++ if (slen < 0) ++ return (NULL); ++ symlink[slen] = '\0'; ++ if (symlink[0] == '/') { ++ resolved[1] = 0; ++ resolved_len = 1; ++ } else if (resolved_len > 1) { ++ /* Strip the last path component. */ ++ resolved[resolved_len - 1] = '\0'; ++ q = strrchr(resolved, '/'); ++ *q = '\0'; ++ resolved_len = q - resolved; ++ } ++ ++ /* ++ * If there are any path components left, then ++ * append them to symlink. The result is placed ++ * in `left'. ++ */ ++ if (p != NULL) { ++ if (symlink[slen - 1] != '/') { ++ if (slen + 1 >= sizeof(symlink)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ symlink[slen] = '/'; ++ symlink[slen + 1] = 0; ++ } ++ left_len = strlcat(symlink, left, sizeof(left)); ++ if (left_len >= sizeof(left)) { ++ errno = ENAMETOOLONG; ++ return (NULL); ++ } ++ } ++ left_len = strlcpy(left, symlink, sizeof(left)); ++ } else { ++ if (S_ISDIR(sb.st_mode)) { ++ is_dir = 1; ++ } else { ++ is_dir = 0; ++ } ++ } ++ } ++ ++ /* ++ * Remove trailing slash except when the resolved pathname ++ * is a single "/". ++ */ ++ if (resolved_len > 1 && resolved[resolved_len - 1] == '/') ++ resolved[resolved_len - 1] = '\0'; ++ return (resolved); ++} ++#endif ++ + CWD_API void virtual_cwd_startup(void) + { + char cwd[MAXPATHLEN]; +@@ -321,8 +480,7 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now +- return 1; */ ++ return 1; + } + } + } else { /* Concat current directory with relative path and then run realpath() on it */ +@@ -348,9 +506,8 @@ + path = resolved_path; + path_length = strlen(path); + } else { +- /* disable for now + free(tmp); +- return 1; */ ++ return 1; + } + } + free(tmp); +diff -Nura php-5.0.5/TSRM/tsrm_virtual_cwd.h hardening-patch-5.0.5-0.4.3/TSRM/tsrm_virtual_cwd.h +--- php-5.0.5/TSRM/tsrm_virtual_cwd.h 2005-07-16 13:50:59.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/TSRM/tsrm_virtual_cwd.h 2005-09-11 23:30:52.000000000 +0200 +@@ -126,6 +126,22 @@ + + typedef int (*verify_path_func)(const cwd_state *); + ++#ifndef HAVE_STRLCPY ++CWD_API size_t php_strlcpy(char *dst, const char *src, size_t siz); ++#undef strlcpy ++#define strlcpy php_strlcpy ++#endif ++ ++#ifndef HAVE_STRLCAT ++CWD_API size_t php_strlcat(char *dst, const char *src, size_t siz); ++#undef strlcat ++#define strlcat php_strlcat ++#endif ++ ++ ++#if HARDENING_PATCH ++CWD_API char *php_realpath(const char *path, char *resolved); ++#endif + CWD_API void virtual_cwd_startup(void); + CWD_API void virtual_cwd_shutdown(void); + CWD_API char *virtual_getcwd_ex(size_t *length TSRMLS_DC); +diff -Nura php-5.0.5/Zend/zend_alloc.c hardening-patch-5.0.5-0.4.3/Zend/zend_alloc.c +--- php-5.0.5/Zend/zend_alloc.c 2005-08-18 17:14:23.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_alloc.c 2005-09-11 23:30:52.000000000 +0200 +@@ -64,6 +64,11 @@ + # define END_MAGIC_SIZE 0 + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++# define CANARY_SIZE sizeof(unsigned int) ++#else ++# define CANARY_SIZE 0 ++#endif + + # if MEMORY_LIMIT + # if ZEND_DEBUG +@@ -105,9 +110,17 @@ + if (p==AG(head)) { \ + AG(head) = p->pNext; \ + } else { \ ++ if (p != p->pLast->pNext) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pLast->pNext = p->pNext; \ + } \ + if (p->pNext) { \ ++ if (p != p->pNext->pLast) { \ ++ zend_security_log(S_MEMORY, "linked list corrupt on efree() - heap corruption detected"); \ ++ exit(1); \ ++ } \ + p->pNext->pLast = p->pLast; \ + } + #else +@@ -146,6 +159,12 @@ + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (size > LONG_MAX - sizeof(zend_mem_header) - MEM_HEADER_PADDING - END_MAGIC_SIZE - CANARY_SIZE) { ++ zend_security_log(S_MEMORY, "emalloc() - requested size would result in integer overflow"); ++ exit(1); ++ } ++#endif + CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size); + + #if !ZEND_DISABLE_MEMORY_CACHE +@@ -164,6 +183,10 @@ + AG(cache_stats)[CACHE_INDEX][1]++; + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->cached = 0; + p->size = size; + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); +@@ -180,7 +203,7 @@ + AG(allocated_memory_peak) = AG(allocated_memory); + } + #endif +- p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE + CANARY_SIZE); + #if !ZEND_DISABLE_MEMORY_CACHE + } + #endif +@@ -212,7 +235,10 @@ + # endif + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif +- ++#if HARDENING_PATCH_MM_PROTECT ++ p->canary = HG(canary_1); ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + HANDLE_UNBLOCK_INTERRUPTIONS(); + return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING); + } +@@ -240,6 +266,10 @@ + } + } + ++ ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by safe_emalloc()"); ++#endif + zend_error(E_ERROR, "Possible integer overflow in memory allocation (%zd * %zd + %zd)", nmemb, size, offset); + return 0; + } +@@ -248,9 +278,25 @@ + + ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p = (zend_mem_header *) ((char *)ptr - sizeof(zend_mem_header) - MEM_HEADER_PADDING); + DECLARE_CACHE_VARS(); + TSRMLS_FETCH(); ++ ++#if HARDENING_PATCH_MM_PROTECT ++ if (p->canary != HG(canary_1)) goto efree_canary_mismatch; ++ memcpy(&canary_2, (((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), CANARY_SIZE); ++ if (canary_2 != HG(canary_2)) { ++efree_canary_mismatch: ++ zend_security_log(S_MEMORY, "canary mismatch on efree() - heap overflow or double efree detected"); ++ exit(1); ++ } ++ /* to catch double efree()s */ ++ memset((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), 0, CANARY_SIZE); ++ p->canary = 0; ++#endif + + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { +@@ -292,23 +338,35 @@ + + ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { +- void *p; +- int final_size = size*nmemb; ++ char *p; ++ size_t _size = nmemb * size; ++ ++ if (nmemb && (_size/nmemb!=size)) { ++#if HARDENING_PATCH ++ zend_security_log(S_MEMORY, "Possible integer overflow catched by ecalloc()"); ++#endif ++ fprintf(stderr,"FATAL: ecalloc(): Unable to allocate %ld * %ld bytes\n", (long) nmemb, (long) size); ++#if ZEND_DEBUG && HAVE_KILL && HAVE_GETPID ++ kill(getpid(), SIGSEGV); ++#else ++ exit(1); ++#endif ++ } + +- HANDLE_BLOCK_INTERRUPTIONS(); +- p = _emalloc(final_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); +- if (!p) { +- HANDLE_UNBLOCK_INTERRUPTIONS(); +- return (void *) p; ++ p = (char *) _emalloc(_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); ++ if (p) { ++ memset(p, 0, _size); + } +- memset(p, 0, final_size); +- HANDLE_UNBLOCK_INTERRUPTIONS(); +- return p; ++ ++ return ((void *)p); + } + + + ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) + { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary_2; ++#endif + zend_mem_header *p; + zend_mem_header *orig; + DECLARE_CACHE_VARS(); +@@ -320,6 +378,16 @@ + + p = orig = (zend_mem_header *) ((char *)ptr-sizeof(zend_mem_header)-MEM_HEADER_PADDING); + ++#if HARDENING_PATCH_MM_PROTECT ++ if (p->canary != HG(canary_1)) goto erealloc_canary_mismatch; ++ memcpy(&canary_2, (((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + p->size + END_MAGIC_SIZE), CANARY_SIZE); ++ if (canary_2 != HG(canary_2)) { ++erealloc_canary_mismatch: ++ zend_security_log(S_MEMORY, "canary mismatch on erealloc() - heap overflow detected"); ++ exit(1); ++ } ++#endif ++ + #if defined(ZTS) && TSRM_DEBUG + if (p->thread_id != tsrm_thread_id()) { + void *new_p; +@@ -343,7 +411,7 @@ + } + #endif + REMOVE_POINTER_FROM_LIST(p); +- p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE); ++ p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE+CANARY_SIZE); + if (!p) { + if (!allow_failure) { + fprintf(stderr,"FATAL: erealloc(): Unable to allocate %ld bytes\n", (long) size); +@@ -365,6 +433,9 @@ + memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long)); + #endif + ++#if HARDENING_PATCH_MM_PROTECT ++ memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size + END_MAGIC_SIZE), &HG(canary_2), CANARY_SIZE); ++#endif + p->size = size; + + HANDLE_UNBLOCK_INTERRUPTIONS(); +@@ -439,6 +510,10 @@ + { + AG(head) = NULL; + ++#if HARDENING_PATCH_MM_PROTECT ++ HG(canary_1) = zend_canary(); ++ HG(canary_2) = zend_canary(); ++#endif + #if MEMORY_LIMIT + AG(memory_limit) = 1<<30; /* ridiculous limit, effectively no limit */ + AG(allocated_memory) = 0; +diff -Nura php-5.0.5/Zend/zend_alloc.h hardening-patch-5.0.5-0.4.3/Zend/zend_alloc.h +--- php-5.0.5/Zend/zend_alloc.h 2005-06-07 15:37:13.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_alloc.h 2005-09-11 23:30:52.000000000 +0200 +@@ -35,6 +35,9 @@ + #define MEM_BLOCK_CACHED_MAGIC 0xFB8277DCL + + typedef struct _zend_mem_header { ++#if HARDENING_PATCH_MM_PROTECT ++ unsigned int canary; ++#endif + #if ZEND_DEBUG + long magic; + char *filename; +diff -Nura php-5.0.5/Zend/zend_API.h hardening-patch-5.0.5-0.4.3/Zend/zend_API.h +--- php-5.0.5/Zend/zend_API.h 2005-06-27 19:42:06.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_API.h 2005-09-11 23:30:52.000000000 +0200 +@@ -47,6 +47,7 @@ + #define ZEND_METHOD(classname, name) ZEND_NAMED_FUNCTION(ZEND_FN(classname##_##name)) + + #define ZEND_FENTRY(zend_name, name, arg_info, flags) { #zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeof(struct _zend_arg_info)-1), flags }, ++#define ZEND_STATIC_FE(zend_name, name, arg_info) { zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeof(struct _zend_arg_info)-1), 0 }, + + #define ZEND_NAMED_FE(zend_name, name, arg_info) ZEND_FENTRY(zend_name, name, arg_info, 0) + #define ZEND_FE(name, arg_info) ZEND_FENTRY(name, ZEND_FN(name), arg_info, 0) +diff -Nura php-5.0.5/Zend/zend_builtin_functions.c hardening-patch-5.0.5-0.4.3/Zend/zend_builtin_functions.c +--- php-5.0.5/Zend/zend_builtin_functions.c 2005-06-27 19:42:06.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_builtin_functions.c 2005-09-11 23:30:52.000000000 +0200 +@@ -52,6 +52,9 @@ + static ZEND_FUNCTION(crash); + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++static ZEND_FUNCTION(heap_overflow); ++#endif + static ZEND_FUNCTION(get_included_files); + static ZEND_FUNCTION(is_subclass_of); + static ZEND_FUNCTION(is_a); +@@ -111,6 +114,9 @@ + ZEND_FE(crash, NULL) + #endif + #endif ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ ZEND_FE(heap_overflow, NULL) ++#endif + ZEND_FE(get_included_files, NULL) + ZEND_FALIAS(get_required_files, get_included_files, NULL) + ZEND_FE(is_subclass_of, NULL) +@@ -991,6 +997,19 @@ + + #endif /* ZEND_DEBUG */ + ++ ++#if HARDENING_PATCH_MM_PROTECT_DEBUG ++ZEND_FUNCTION(heap_overflow) ++{ ++ char *nowhere = emalloc(10); ++ ++ memcpy(nowhere, "something1234567890", sizeof("something1234567890")); ++ ++ efree(nowhere); ++} ++#endif ++ ++ + /* {{{ proto array get_included_files(void) + Returns an array with the file names that were include_once()'d */ + ZEND_FUNCTION(get_included_files) +diff -Nura php-5.0.5/Zend/zend.c hardening-patch-5.0.5-0.4.3/Zend/zend.c +--- php-5.0.5/Zend/zend.c 2005-07-22 09:33:27.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend.c 2005-09-12 17:02:36.000000000 +0200 +@@ -54,6 +54,12 @@ + ZEND_API void (*zend_unblock_interruptions)(void); + ZEND_API void (*zend_ticks_function)(int ticks); + ZEND_API void (*zend_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); ++#if HARDENING_PATCH ++ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif + int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); + + void (*zend_on_timeout)(int seconds TSRMLS_DC); +@@ -72,9 +78,391 @@ + return SUCCESS; + } + ++#if HARDENING_PATCH ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog) = S_ALL & ~S_SQL | S_MEMORY | S_INTERNAL; ++ } else { ++ EG(hphp_log_syslog) = atoi(new_value) | S_MEMORY | S_INTERNAL; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_facility) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_facility) = LOG_USER; ++ } else { ++ EG(hphp_log_syslog_facility) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_syslog_priority) ++{ ++ if (!new_value) { ++ EG(hphp_log_syslog_priority) = LOG_ALERT; ++ } else { ++ EG(hphp_log_syslog_priority) = atoi(new_value); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_sapi) ++{ ++ if (!new_value) { ++ EG(hphp_log_sapi) = S_ALL & ~S_SQL | S_INTERNAL; ++ } else { ++ EG(hphp_log_sapi) = atoi(new_value) | S_INTERNAL; ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_script) ++{ ++ if (!new_value) { ++ EG(hphp_log_script) = S_ALL & ~S_MEMORY; ++ } else { ++ EG(hphp_log_script) = atoi(new_value) & (~S_MEMORY) & (~S_INTERNAL); ++ } ++ return SUCCESS; ++} ++static ZEND_INI_MH(OnUpdateHPHP_log_scriptname) ++{ ++ if (!new_value) { ++ EG(hphp_log_scriptname) = NULL; ++ } else { ++ if (EG(hphp_log_scriptname)) { ++ pefree(EG(hphp_log_scriptname),1); ++ } ++ EG(hphp_log_scriptname) = pestrdup(new_value,1); ++ } ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_include_whitelist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++include_whitelist_destroy: ++ if (HG(include_whitelist)) { ++ zend_hash_destroy(HG(include_whitelist)); ++ efree(HG(include_whitelist)); ++ } ++ HG(include_whitelist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto include_whitelist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(include_whitelist)); ++ zend_hash_init(HG(include_whitelist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(include_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(include_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_include_blacklist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++include_blacklist_destroy: ++ if (HG(include_blacklist)) { ++ zend_hash_destroy(HG(include_blacklist)); ++ efree(HG(include_blacklist)); ++ } ++ HG(include_blacklist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto include_blacklist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(include_blacklist)); ++ zend_hash_init(HG(include_blacklist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(include_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(include_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_eval_whitelist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++eval_whitelist_destroy: ++ if (HG(eval_whitelist)) { ++ zend_hash_destroy(HG(eval_whitelist)); ++ efree(HG(eval_whitelist)); ++ } ++ HG(eval_whitelist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto eval_whitelist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(eval_whitelist)); ++ zend_hash_init(HG(eval_whitelist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(eval_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(eval_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_eval_blacklist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++eval_blacklist_destroy: ++ if (HG(eval_blacklist)) { ++ zend_hash_destroy(HG(eval_blacklist)); ++ efree(HG(eval_blacklist)); ++ } ++ HG(eval_blacklist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto eval_blacklist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(eval_blacklist)); ++ zend_hash_init(HG(eval_blacklist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(eval_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(eval_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_func_whitelist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++func_whitelist_destroy: ++ if (HG(func_whitelist)) { ++ zend_hash_destroy(HG(func_whitelist)); ++ efree(HG(func_whitelist)); ++ } ++ HG(func_whitelist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto func_whitelist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(func_whitelist)); ++ zend_hash_init(HG(func_whitelist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(func_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(func_whitelist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ return SUCCESS; ++} ++ ++static ZEND_INI_MH(OnUpdateHPHP_func_blacklist) ++{ ++ char *s = NULL, *e, *val; ++ unsigned long dummy = 1; ++ ++ if (!new_value) { ++func_blacklist_destroy: ++ if (HG(func_blacklist)) { ++ zend_hash_destroy(HG(func_blacklist)); ++ efree(HG(func_blacklist)); ++ } ++ HG(func_blacklist) = NULL; ++ return SUCCESS; ++ } ++ if (!(*new_value)) { ++ goto func_blacklist_destroy; ++ } ++ ++ ALLOC_HASHTABLE(HG(func_blacklist)); ++ zend_hash_init(HG(func_blacklist), 5, NULL, NULL, 0); ++ ++ val = zend_str_tolower_dup(new_value, strlen(new_value)); ++ e = val; ++ ++ while (*e) { ++ switch (*e) { ++ case ' ': ++ case ',': ++ if (s) { ++ *e = '\0'; ++ zend_hash_add(HG(func_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ s = NULL; ++ } ++ break; ++ default: ++ if (!s) { ++ s = e; ++ } ++ break; ++ } ++ e++; ++ } ++ if (s) { ++ zend_hash_add(HG(func_blacklist), s, e-s+1, &dummy, sizeof(unsigned long), NULL); ++ } ++ efree(val); ++ ++ ++ return SUCCESS; ++} ++ ++#endif + + ZEND_INI_BEGIN() + ZEND_INI_ENTRY("error_reporting", NULL, ZEND_INI_ALL, OnUpdateErrorReporting) ++#if HARDENING_PATCH ++ ZEND_INI_ENTRY("hphp.log.syslog", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog) ++ ZEND_INI_ENTRY("hphp.log.syslog.facility", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_facility) ++ ZEND_INI_ENTRY("hphp.log.syslog.priority", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_syslog_priority) ++ ZEND_INI_ENTRY("hphp.log.sapi", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_sapi) ++ ZEND_INI_ENTRY("hphp.log.script", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_script) ++ ZEND_INI_ENTRY("hphp.log.script.name", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_log_scriptname) ++ STD_ZEND_INI_BOOLEAN("hphp.log.use-x-forwarded-for", "0", ZEND_INI_SYSTEM, OnUpdateBool, hphp_log_use_x_forwarded_for, zend_executor_globals, executor_globals) ++ ++ ZEND_INI_ENTRY("hphp.executor.include.whitelist", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_include_whitelist) ++ ZEND_INI_ENTRY("hphp.executor.include.blacklist", NULL, ZEND_INI_SYSTEM, OnUpdateHPHP_include_blacklist) ++ ZEND_INI_ENTRY("hphp.executor.eval.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_eval_whitelist) ++ ZEND_INI_ENTRY("hphp.executor.eval.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_eval_blacklist) ++ ZEND_INI_ENTRY("hphp.executor.func.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_func_whitelist) ++ ZEND_INI_ENTRY("hphp.executor.func.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateHPHP_func_blacklist) ++ ++ STD_ZEND_INI_ENTRY("hphp.executor.max_depth", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateLong, hphp_executor_max_depth, zend_executor_globals, executor_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.sql.bailout_on_error", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, hphp_sql_bailout_on_error, hardened_globals_struct, hardened_globals) ++ STD_ZEND_INI_BOOLEAN("hphp.multiheader", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, hphp_multiheader, hardened_globals_struct, hardened_globals) ++#endif + STD_ZEND_INI_BOOLEAN("zend.ze1_compatibility_mode", "0", ZEND_INI_ALL, OnUpdateBool, ze1_compatibility_mode, zend_executor_globals, executor_globals) + ZEND_INI_END() + +@@ -476,6 +864,7 @@ + EG(user_error_handler) = NULL; + EG(user_exception_handler) = NULL; + EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(in_autoload) = NULL; + EG(current_execute_data) = NULL; + EG(current_module) = NULL; +@@ -545,6 +934,14 @@ + extern zend_scanner_globals language_scanner_globals; + #endif + ++ /* Set up Hardening-Patch utility functions first */ ++#if HARDENING_PATCH ++ zend_security_log = utility_functions->security_log_function; ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ zend_is_valid_include = utility_functions->is_valid_include; ++#endif ++ + #ifdef ZTS + ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); + #else +@@ -747,6 +1144,7 @@ + } + CG(unclean_shutdown) = 1; + CG(in_compilation) = EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(current_execute_data) = NULL; + longjmp(EG(bailout), FAILURE); + } +diff -Nura php-5.0.5/Zend/zend_canary.c hardening-patch-5.0.5-0.4.3/Zend/zend_canary.c +--- php-5.0.5/Zend/zend_canary.c 1970-01-01 01:00:00.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_canary.c 2005-09-11 23:30:52.000000000 +0200 +@@ -0,0 +1,58 @@ ++/* ++ +----------------------------------------------------------------------+ ++ | Hardening-Patch for PHP | ++ +----------------------------------------------------------------------+ ++ | Copyright (c) 2004-2005 Stefan Esser | ++ +----------------------------------------------------------------------+ ++ | This source file is subject to version 2.02 of the PHP license, | ++ | that is bundled with this package in the file LICENSE, and is | ++ | available at through the world-wide-web at | ++ | http://www.php.net/license/2_02.txt. | ++ | If you did not receive a copy of the PHP license and are unable to | ++ | obtain it through the world-wide-web, please send a note to | ++ | license@php.net so we can mail you a copy immediately. | ++ +----------------------------------------------------------------------+ ++ | Author: Stefan Esser | ++ +----------------------------------------------------------------------+ ++ */ ++/* $Id: zend_canary.c,v 1.1 2004/11/26 12:45:41 ionic Exp $ */ ++ ++#include "zend.h" ++ ++#include ++#include ++ ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ ++/* will be replaced later with more compatible method */ ++ZEND_API unsigned int zend_canary() ++{ ++ time_t t; ++ unsigned int canary; ++ int fd; ++ ++ fd = open("/dev/urandom", 0); ++ if (fd != -1) { ++ int r = read(fd, &canary, sizeof(canary)); ++ close(fd); ++ if (r == sizeof(canary)) { ++ return (canary); ++ } ++ } ++ /* not good but we never want to do this */ ++ time(&t); ++ canary = *(unsigned int *)&t + getpid() << 16; ++ return (canary); ++} ++#endif ++ ++ ++/* ++ * Local variables: ++ * tab-width: 4 ++ * c-basic-offset: 4 ++ * End: ++ * vim600: sw=4 ts=4 fdm=marker ++ * vim<600: sw=4 ts=4 ++ */ +diff -Nura php-5.0.5/Zend/zend_compile.c hardening-patch-5.0.5-0.4.3/Zend/zend_compile.c +--- php-5.0.5/Zend/zend_compile.c 2005-07-19 09:33:24.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_compile.c 2005-09-11 23:30:52.000000000 +0200 +@@ -979,6 +979,13 @@ + op_array.prototype = NULL; + + op_array.line_start = zend_get_compiled_lineno(TSRMLS_C); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array.created_by_eval = 1; ++ } else { ++ op_array.created_by_eval = 0; ++ } ++#endif + + if (is_method) { + char *short_class_name = CG(active_class_entry)->name; +diff -Nura php-5.0.5/Zend/zend_compile.h hardening-patch-5.0.5-0.4.3/Zend/zend_compile.h +--- php-5.0.5/Zend/zend_compile.h 2005-06-24 10:45:43.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_compile.h 2005-09-11 23:30:52.000000000 +0200 +@@ -203,6 +203,9 @@ + zend_uint doc_comment_len; + + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; ++#if HARDENING_PATCH ++ zend_bool created_by_eval; ++#endif + }; + + +@@ -281,6 +284,8 @@ + zval *object; + union _temp_variable *Ts; + zend_bool original_in_execution; ++ zend_uint original_in_code_type; ++ zend_uint execute_depth; + zend_class_entry *calling_scope; + struct _zend_execute_data *prev_execute_data; + }; +@@ -774,6 +779,7 @@ + #define ZEND_OVERLOADED_FUNCTION 3 + #define ZEND_EVAL_CODE 4 + #define ZEND_OVERLOADED_FUNCTION_TEMPORARY 5 ++#define ZEND_SANDBOX_CODE 6 + + #define ZEND_INTERNAL_CLASS 1 + #define ZEND_USER_CLASS 2 +diff -Nura php-5.0.5/Zend/zend_constants.c hardening-patch-5.0.5-0.4.3/Zend/zend_constants.c +--- php-5.0.5/Zend/zend_constants.c 2004-07-13 21:22:11.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_constants.c 2005-09-11 23:30:52.000000000 +0200 +@@ -107,6 +107,73 @@ + REGISTER_MAIN_LONG_CONSTANT("E_USER_NOTICE", E_USER_NOTICE, CONST_PERSISTENT | CONST_CS); + + REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS); ++#if HARDENING_PATCH ++ REGISTER_MAIN_LONG_CONSTANT("S_MEMORY", S_MEMORY, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_VARS", S_VARS, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_FILES", S_FILES, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INCLUDE", S_INCLUDE, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_SQL", S_SQL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_EXECUTOR", S_EXECUTOR, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_MISC", S_MISC, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_INTERNAL", S_INTERNAL, CONST_PERSISTENT | CONST_CS); ++ REGISTER_MAIN_LONG_CONSTANT("S_ALL", S_ALL, CONST_PERSISTENT | CONST_CS); ++ ++ /* error levels */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_EMERG", LOG_EMERG, CONST_CS | CONST_PERSISTENT); /* system unusable */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ALERT", LOG_ALERT, CONST_CS | CONST_PERSISTENT); /* immediate action required */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRIT", LOG_CRIT, CONST_CS | CONST_PERSISTENT); /* critical conditions */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ERR", LOG_ERR, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_WARNING", LOG_WARNING, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOTICE", LOG_NOTICE, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_INFO", LOG_INFO, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DEBUG", LOG_DEBUG, CONST_CS | CONST_PERSISTENT); ++ /* facility: type of program logging the message */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_KERN", LOG_KERN, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_USER", LOG_USER, CONST_CS | CONST_PERSISTENT); /* generic user level */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_MAIL", LOG_MAIL, CONST_CS | CONST_PERSISTENT); /* log to email */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_DAEMON", LOG_DAEMON, CONST_CS | CONST_PERSISTENT); /* other system daemons */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTH", LOG_AUTH, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_SYSLOG", LOG_SYSLOG, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LPR", LOG_LPR, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NEWS ++ /* No LOG_NEWS on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NEWS", LOG_NEWS, CONST_CS | CONST_PERSISTENT); /* usenet new */ ++#endif ++#ifdef LOG_UUCP ++ /* No LOG_UUCP on HP-UX */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_UUCP", LOG_UUCP, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_CRON ++ /* apparently some systems don't have this one */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CRON", LOG_CRON, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_AUTHPRIV ++ /* AIX doesn't have LOG_AUTHPRIV */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_AUTHPRIV", LOG_AUTHPRIV, CONST_CS | CONST_PERSISTENT); ++#endif ++#if !defined(PHP_WIN32) && !defined(NETWARE) ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL0", LOG_LOCAL0, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL1", LOG_LOCAL1, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL2", LOG_LOCAL2, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL3", LOG_LOCAL3, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL4", LOG_LOCAL4, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL5", LOG_LOCAL5, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL6", LOG_LOCAL6, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_LOCAL7", LOG_LOCAL7, CONST_CS | CONST_PERSISTENT); ++#endif ++ /* options */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PID", LOG_PID, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_CONS", LOG_CONS, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_ODELAY", LOG_ODELAY, CONST_CS | CONST_PERSISTENT); ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NDELAY", LOG_NDELAY, CONST_CS | CONST_PERSISTENT); ++#ifdef LOG_NOWAIT ++ REGISTER_MAIN_LONG_CONSTANT("LOG_NOWAIT", LOG_NOWAIT, CONST_CS | CONST_PERSISTENT); ++#endif ++#ifdef LOG_PERROR ++ /* AIX doesn't have LOG_PERROR */ ++ REGISTER_MAIN_LONG_CONSTANT("LOG_PERROR", LOG_PERROR, CONST_CS | CONST_PERSISTENT); /*log to stderr*/ ++#endif ++#endif + + /* true/false constants */ + { +diff -Nura php-5.0.5/Zend/zend_errors.h hardening-patch-5.0.5-0.4.3/Zend/zend_errors.h +--- php-5.0.5/Zend/zend_errors.h 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_errors.h 2005-09-12 18:12:35.000000000 +0200 +@@ -38,6 +38,18 @@ + #define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE) + #define E_CORE (E_CORE_ERROR | E_CORE_WARNING) + ++#if HARDENING_PATCH ++#define S_MEMORY (1<<0L) ++#define S_VARS (1<<1L) ++#define S_FILES (1<<2L) ++#define S_INCLUDE (1<<3L) ++#define S_SQL (1<<4L) ++#define S_EXECUTOR (1<<5L) ++#define S_MISC (1<<30L) ++#define S_INTERNAL (1<<29L) ++#define S_ALL (S_MEMORY | S_VARS | S_INCLUDE | S_FILES | S_MISC | S_SQL | S_EXECUTOR) ++#endif ++ + #endif /* ZEND_ERRORS_H */ + + /* +diff -Nura php-5.0.5/Zend/zend_execute_API.c hardening-patch-5.0.5-0.4.3/Zend/zend_execute_API.c +--- php-5.0.5/Zend/zend_execute_API.c 2005-09-02 09:46:39.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_execute_API.c 2005-09-11 23:30:52.000000000 +0200 +@@ -137,6 +137,7 @@ + EG(class_table) = CG(class_table); + + EG(in_execution) = 0; ++ EG(in_code_type) = 0; + EG(in_autoload) = NULL; + + zend_ptr_stack_init(&EG(argument_stack)); +@@ -725,6 +726,39 @@ + if (zend_hash_find(fci->function_table, function_name_lc, fci->function_name->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { + EX(function_state).function = NULL; + } ++#if HARDENING_PATCH ++ else { ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), function_name_lc, fci->function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", function_name_lc); ++ efree(function_name_lc); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), function_name_lc, fci->function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", function_name_lc); ++ efree(function_name_lc); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), function_name_lc, fci->function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", function_name_lc); ++ efree(function_name_lc); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), function_name_lc, fci->function_name->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", function_name_lc); ++ efree(function_name_lc); ++ zend_bailout(); ++ } ++ } ++ } ++#endif + efree(function_name_lc); + } + +@@ -999,7 +1033,7 @@ + return retval; + } + +-ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) ++ZEND_API int zend_eval_string_ex_ex(char *str, zval *retval_ptr, char *string_name, int type TSRMLS_DC) + { + zval pv; + zend_op_array *new_op_array; +@@ -1032,6 +1066,7 @@ + zval **original_return_value_ptr_ptr = EG(return_value_ptr_ptr); + zend_op **original_opline_ptr = EG(opline_ptr); + ++ new_op_array->type = type; + EG(return_value_ptr_ptr) = &local_retval_ptr; + EG(active_op_array) = new_op_array; + EG(no_extensions)=1; +@@ -1066,6 +1101,12 @@ + } + + ++ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC) ++{ ++ return (zend_eval_string_ex_ex(str, retval_ptr, string_name, ZEND_EVAL_CODE TSRMLS_CC)); ++} ++ ++ + ZEND_API int zend_eval_string_ex(char *str, zval *retval_ptr, char *string_name, int handle_exceptions TSRMLS_DC) + { + int result; +diff -Nura php-5.0.5/Zend/zend_execute.c hardening-patch-5.0.5-0.4.3/Zend/zend_execute.c +--- php-5.0.5/Zend/zend_execute.c 2005-09-01 15:21:56.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_execute.c 2005-09-11 23:30:52.000000000 +0200 +@@ -1374,6 +1374,7 @@ + efree(EX(Ts)); \ + } \ + EG(in_execution) = EX(original_in_execution); \ ++ EG(in_code_type) = EX(original_in_code_type); \ + EG(current_execute_data) = EX(prev_execute_data); \ + return 1; /* CHECK_ME */ + +@@ -1400,6 +1401,16 @@ + EX(original_in_execution) = EG(in_execution); + EX(prev_execute_data) = EG(current_execute_data); + EG(current_execute_data) = &execute_data; ++#if HARDENING_PATCH ++ EX(execute_depth) = 0; ++ ++ if ((op_array->type == ZEND_EVAL_CODE || op_array->created_by_eval)&& EG(in_code_type) != ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_EVAL_CODE; ++ } else if (op_array->type == ZEND_SANDBOX_CODE) { ++ EG(in_code_type) = ZEND_SANDBOX_CODE; ++ op_array->type = ZEND_EVAL_CODE; ++ } ++#endif + + EG(in_execution) = 1; + if (op_array->start_op) { +@@ -1426,6 +1437,19 @@ + EX(function_state).function_symbol_table = NULL; + #endif + ++#if HARDENING_PATCH ++ if (EX(prev_execute_data) == NULL) { ++ EX(execute_depth) = 0; ++ } else { ++ EX(execute_depth) = EX(prev_execute_data)->execute_depth + 1; ++ } ++ ++ if (EG(hphp_executor_max_depth) > 0 && EX(execute_depth) > EG(hphp_executor_max_depth)) { ++ zend_security_log(S_EXECUTOR, "Maximum execution depth of %u violated", EG(hphp_executor_max_depth)); ++ zend_bailout(); ++ } ++#endif ++ + while (1) { + #ifdef ZEND_WIN32 + if (EG(timed_out)) { +@@ -2680,6 +2704,37 @@ + efree(lcname); + zend_error(E_ERROR, "Call to undefined function %s()", function_name_strval); + } ++#if HARDENING_PATCH ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), lcname, function_name_strlen+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", lcname); ++ efree(lcname); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), lcname, function_name_strlen+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", lcname); ++ efree(lcname); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), lcname, function_name_strlen+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", lcname); ++ efree(lcname); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), lcname, function_name_strlen+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", lcname); ++ efree(lcname); ++ zend_bailout(); ++ } ++ } ++#endif + + efree(lcname); + if (!is_const) { +@@ -2886,6 +2941,34 @@ + if (zend_hash_find(EG(function_table), fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { + zend_error(E_ERROR, "Unknown function: %s()\n", fname->value.str.val); + } ++#if HARDENING_PATCH ++ if (EG(in_code_type) == ZEND_EVAL_CODE) { ++ if (HG(eval_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(eval_whitelist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(eval_blacklist) != NULL) { ++ if (zend_hash_exists(HG(eval_blacklist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within eval blacklist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } ++ } ++ ++ if (HG(func_whitelist) != NULL) { ++ if (!zend_hash_exists(HG(func_whitelist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function outside of whitelist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } else if (HG(func_blacklist) != NULL) { ++ if (zend_hash_exists(HG(func_blacklist), fname->value.str.val, fname->value.str.len+1)) { ++ zend_security_log(S_EXECUTOR, "function within blacklist called: %s()", fname->value.str.val); ++ zend_bailout(); ++ } ++ } ++#endif ++ + EX(object) = NULL; + EX(calling_scope) = EX(function_state).function->common.scope; + +@@ -3573,7 +3656,12 @@ + int dummy = 1; + zend_file_handle file_handle; + ++#if HARDENING_PATCH_INC_PROTECT ++ if (zend_is_valid_include(inc_filename) ++ && (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC))) { ++#else + if (SUCCESS == zend_stream_open(inc_filename->value.str.val, &file_handle TSRMLS_CC)) { ++#endif + + if (!file_handle.opened_path) { + file_handle.opened_path = estrndup(inc_filename->value.str.val, inc_filename->value.str.len); +@@ -3598,6 +3686,11 @@ + break; + case ZEND_INCLUDE: + case ZEND_REQUIRE: ++#if HARDENING_PATCH_INC_PROTECT ++ if (!zend_is_valid_include(inc_filename)) { ++ break; ++ } ++#endif + new_op_array = compile_filename(opline->op2.u.constant.value.lval, inc_filename TSRMLS_CC); + break; + case ZEND_EVAL: { +diff -Nura php-5.0.5/Zend/zend_extensions.c hardening-patch-5.0.5-0.4.3/Zend/zend_extensions.c +--- php-5.0.5/Zend/zend_extensions.c 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_extensions.c 2005-09-11 23:30:52.000000000 +0200 +@@ -55,23 +55,44 @@ + return FAILURE; + } + ++ /* check if module is compiled against Hardening-Patch */ ++ if (extension_version_info->zend_extension_api_no < 1000000000) { ++ fprintf(stderr, "%s is not compiled with Hardening-Patch.\n" ++ "The Hardening-Patch version %d is installed.\n\n", ++ new_extension->name, ++ HARDENING_PATCH_ZEND_EXTENSION_API_NO); ++ DL_UNLOAD(handle); ++ return FAILURE; ++ } ++ ++ ++ /* check if module is compiled against correct Hardening-Patch version */ ++ if (extension_version_info->zend_extension_api_no != HARDENING_PATCH_ZEND_EXTENSION_API_NO) { ++ fprintf(stderr, "%s requires Hardening-Patch version %d.\n" ++ "The Hardening-Patch version %d is installed.\n\n", ++ new_extension->name, ++ extension_version_info->zend_extension_api_no, ++ HARDENING_PATCH_ZEND_EXTENSION_API_NO); ++ DL_UNLOAD(handle); ++ return FAILURE; ++ } + + /* allow extension to proclaim compatibility with any Zend version */ +- if (extension_version_info->zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) { +- if (extension_version_info->zend_extension_api_no > ZEND_EXTENSION_API_NO) { ++ if (extension_version_info->real_zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) { ++ if (extension_version_info->real_zend_extension_api_no > ZEND_EXTENSION_API_NO) { + fprintf(stderr, "%s requires Zend Engine API version %d.\n" + "The Zend Engine API version %d which is installed, is outdated.\n\n", + new_extension->name, +- extension_version_info->zend_extension_api_no, ++ extension_version_info->real_zend_extension_api_no, + ZEND_EXTENSION_API_NO); + DL_UNLOAD(handle); + return FAILURE; +- } else if (extension_version_info->zend_extension_api_no < ZEND_EXTENSION_API_NO) { ++ } else if (extension_version_info->real_zend_extension_api_no < ZEND_EXTENSION_API_NO) { + fprintf(stderr, "%s requires Zend Engine API version %d.\n" + "The Zend Engine API version %d which is installed, is newer.\n" + "Contact %s at %s for a later version of %s.\n\n", + new_extension->name, +- extension_version_info->zend_extension_api_no, ++ extension_version_info->real_zend_extension_api_no, + ZEND_EXTENSION_API_NO, + new_extension->author, + new_extension->URL, +diff -Nura php-5.0.5/Zend/zend_extensions.h hardening-patch-5.0.5-0.4.3/Zend/zend_extensions.h +--- php-5.0.5/Zend/zend_extensions.h 2004-11-25 21:26:48.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_extensions.h 2005-09-11 23:30:52.000000000 +0200 +@@ -24,9 +24,11 @@ + + #include "zend_compile.h" + +-/* The first number is the engine version and the rest is the date. ++/* The first API number is a flag saying that Hardening-Patch is used. ++ * The second number is the engine version and the date. + * This way engine 2 API no. is always greater than engine 1 API no.. + */ ++#define HARDENING_PATCH_ZEND_EXTENSION_API_NO 1002050805 + #define ZEND_EXTENSION_API_NO 220040412 + + typedef struct _zend_extension_version_info { +@@ -34,6 +36,7 @@ + char *required_zend_version; + unsigned char thread_safe; + unsigned char debug; ++ int real_zend_extension_api_no; + } zend_extension_version_info; + + +@@ -101,7 +104,7 @@ + + + #define ZEND_EXTENSION() \ +- ZEND_EXT_API zend_extension_version_info extension_version_info = { ZEND_EXTENSION_API_NO, ZEND_VERSION, ZTS_V, ZEND_DEBUG } ++ ZEND_EXT_API zend_extension_version_info extension_version_info = { HARDENING_PATCH_ZEND_EXTENSION_API_NO, ZEND_VERSION, ZTS_V, ZEND_DEBUG, ZEND_EXTENSION_API_NO } + + #define STANDARD_ZEND_EXTENSION_PROPERTIES NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1 + #define COMPAT_ZEND_EXTENSION_PROPERTIES NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1 +diff -Nura php-5.0.5/Zend/zend_globals.h hardening-patch-5.0.5-0.4.3/Zend/zend_globals.h +--- php-5.0.5/Zend/zend_globals.h 2004-11-04 00:14:31.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_globals.h 2005-09-11 23:30:52.000000000 +0200 +@@ -174,6 +174,16 @@ + + int error_reporting; + int orig_error_reporting; ++#if HARDENING_PATCH ++ int hphp_log_syslog; ++ int hphp_log_syslog_facility; ++ int hphp_log_syslog_priority; ++ int hphp_log_sapi; ++ int hphp_log_script; ++ char *hphp_log_scriptname; ++ zend_bool hphp_log_use_x_forwarded_for; ++ long hphp_executor_max_depth; ++#endif + int exit_status; + + zend_op_array *active_op_array; +@@ -191,6 +201,7 @@ + int ticks_count; + + zend_bool in_execution; ++ zend_uint in_code_type; + HashTable *in_autoload; + zend_bool bailout_set; + zend_bool full_tables_cleanup; +diff -Nura php-5.0.5/Zend/zend.h hardening-patch-5.0.5-0.4.3/Zend/zend.h +--- php-5.0.5/Zend/zend.h 2005-08-25 19:41:08.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend.h 2005-09-11 23:30:52.000000000 +0200 +@@ -290,6 +290,7 @@ + /* Variable information */ + zvalue_value value; /* value */ + zend_uint refcount; ++ zend_ushort flags; + zend_uchar type; /* active type */ + zend_uchar is_ref; + }; +@@ -359,6 +360,12 @@ + void (*on_timeout)(int seconds TSRMLS_DC); + int (*stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); + int (*vspprintf_function)(char **pbuf, size_t max_len, const char *format, va_list ap); ++#if HARDENING_PATCH ++ void (*security_log_function)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++ int (*is_valid_include)(zval *z); ++#endif + } zend_utility_functions; + + +@@ -497,6 +504,16 @@ + extern void (*zend_on_timeout)(int seconds TSRMLS_DC); + extern ZEND_API int (*zend_stream_open_function)(const char *filename, zend_file_handle *handle TSRMLS_DC); + extern int (*zend_vspprintf)(char **pbuf, size_t max_len, const char *format, va_list ap); ++#if HARDENING_PATCH ++extern ZEND_API void (*zend_security_log)(int loglevel, char *fmt, ...); ++#endif ++#if HARDENING_PATCH_INC_PROTECT ++extern ZEND_API int (*zend_is_valid_include)(zval *z); ++#endif ++ ++#if HARDENING_PATCH_MM_PROTECT || HARDENING_PATCH_LL_PROTECT || HARDENING_PATCH_HASH_PROTECT ++ZEND_API unsigned int zend_canary(void); ++#endif + + + ZEND_API void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); +@@ -621,6 +638,11 @@ + #define ZEND_MAX_RESERVED_RESOURCES 4 + + ++#if HARDENING_PATCH ++#include "hardened_globals.h" ++#include "php_syslog.h" ++#endif ++ + #endif /* ZEND_H */ + + /* +diff -Nura php-5.0.5/Zend/zend_hash.c hardening-patch-5.0.5-0.4.3/Zend/zend_hash.c +--- php-5.0.5/Zend/zend_hash.c 2005-04-25 08:11:00.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_hash.c 2005-09-11 23:30:52.000000000 +0200 +@@ -21,6 +21,18 @@ + + #include "zend.h" + ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int zend_hash_canary = 0x1234567; ++ zend_bool zend_hash_canary_inited = 0; ++#endif ++ ++#define CHECK_HASH_CANARY(hash) \ ++ if (zend_hash_canary != (hash)->canary) { \ ++ zend_security_log(S_MEMORY, "Zend HashTable canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++ + #define CONNECT_TO_BUCKET_DLLIST(element, list_head) \ + (element)->pNext = (list_head); \ + (element)->pLast = NULL; \ +@@ -138,6 +150,9 @@ + { + uint i = 3; + Bucket **tmp; ++#if HARDENING_PATCH_HASH_PROTECT ++ TSRMLS_FETCH(); ++#endif + + SET_INCONSISTENT(HT_OK); + +@@ -147,6 +162,13 @@ + + ht->nTableSize = 1 << i; + ht->nTableMask = ht->nTableSize - 1; ++#if HARDENING_PATCH_HASH_PROTECT ++ if (zend_hash_canary_inited==0) { ++ zend_hash_canary = zend_canary(); ++ zend_hash_canary_inited = 1; ++ } ++ ht->canary = zend_hash_canary; ++#endif + ht->pDestructor = pDestructor; + ht->arBuckets = NULL; + ht->pListHead = NULL; +@@ -226,6 +248,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -291,6 +316,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -366,6 +394,9 @@ + } + #endif + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + UPDATE_DATA(ht, p, pData, nDataSize); +@@ -414,7 +445,7 @@ + IS_CONSISTENT(ht); + + if ((ht->nTableSize << 1) > 0) { /* Let's double the table size */ +- t = (Bucket **) perealloc_recoverable(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); ++ t = (Bucket **) perealloc(ht->arBuckets, (ht->nTableSize << 1) * sizeof(Bucket *), ht->persistent); + if (t) { + HANDLE_BLOCK_INTERRUPTIONS(); + ht->arBuckets = t; +@@ -424,6 +455,7 @@ + HANDLE_UNBLOCK_INTERRUPTIONS(); + return SUCCESS; + } ++ zend_error(E_ERROR, "zend_hash_do_resize - out of memory"); + return FAILURE; + } + return SUCCESS; +@@ -487,6 +519,9 @@ + ht->pInternalPointer = p->pListNext; + } + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +@@ -516,6 +551,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -542,6 +580,9 @@ + q = p; + p = p->pListNext; + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(q->pData); + } + if (!q->pDataPtr && q->pData) { +@@ -571,6 +612,9 @@ + HANDLE_BLOCK_INTERRUPTIONS(); + + if (ht->pDestructor) { ++#if HARDENING_PATCH_HASH_PROTECT ++ CHECK_HASH_CANARY(ht); ++#endif + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { +diff -Nura php-5.0.5/Zend/zend_hash.h hardening-patch-5.0.5-0.4.3/Zend/zend_hash.h +--- php-5.0.5/Zend/zend_hash.h 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_hash.h 2005-09-11 23:30:52.000000000 +0200 +@@ -58,6 +58,9 @@ + } Bucket; + + typedef struct _hashtable { ++#if HARDENING_PATCH_HASH_PROTECT ++ unsigned int canary; ++#endif + uint nTableSize; + uint nTableMask; + uint nNumOfElements; +diff -Nura php-5.0.5/Zend/zend_language_scanner.l hardening-patch-5.0.5-0.4.3/Zend/zend_language_scanner.l +--- php-5.0.5/Zend/zend_language_scanner.l 2005-06-09 10:54:24.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_language_scanner.l 2005-09-11 23:30:52.000000000 +0200 +@@ -386,6 +386,13 @@ + compilation_successful=0; + } else { + init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array->created_by_eval = 1; ++ } else { ++ op_array->created_by_eval = 0; ++ } ++#endif + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + compiler_result = zendparse(TSRMLS_C); +diff -Nura php-5.0.5/Zend/zend_language_scanner.c hardening-patch-5.0.5-0.4.3/Zend/zend_language_scanner.c +--- php-5.0.5/Zend/zend_language_scanner.c 2005-09-05 13:16:27.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_language_scanner.c 2005-09-11 23:30:52.000000000 +0200 +@@ -3153,6 +3153,13 @@ + compilation_successful=0; + } else { + init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC); ++#if HARDENING_PATCH ++ if (EG(in_code_type)==ZEND_EVAL_CODE) { ++ op_array->created_by_eval = 1; ++ } else { ++ op_array->created_by_eval = 0; ++ } ++#endif + CG(in_compilation) = 1; + CG(active_op_array) = op_array; + compiler_result = zendparse(TSRMLS_C); +diff -Nura php-5.0.5/Zend/zend_llist.c hardening-patch-5.0.5-0.4.3/Zend/zend_llist.c +--- php-5.0.5/Zend/zend_llist.c 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_llist.c 2005-09-11 23:30:52.000000000 +0200 +@@ -22,9 +22,34 @@ + #include "zend.h" + #include "zend_llist.h" + #include "zend_qsort.h" ++#include "zend_globals.h" ++ ++#define CHECK_LIST_CANARY(list) \ ++ if (HG(canary_3) != (list)->canary_h || HG(canary_4) != (list)->canary_t) { \ ++ zend_security_log(S_MEMORY, "linked list canary was overwritten"); \ ++ exit(1); \ ++ } ++ ++#define CHECK_LISTELEMENT_CANARY(elem) \ ++ if (HG(canary_3) != (elem)->canary) { \ ++ zend_security_log(S_MEMORY, "linked list element canary was overwritten"); \ ++ exit(1); \ ++ } ++ + + ZEND_API void zend_llist_init(zend_llist *l, size_t size, llist_dtor_func_t dtor, unsigned char persistent) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ ++ if (!HG(ll_canary_inited)) { ++ HG(canary_3) = zend_canary(); ++ HG(canary_4) = zend_canary(); ++ HG(ll_canary_inited) = 1; ++ } ++ l->canary_h = HG(canary_3); ++ l->canary_t = HG(canary_4); ++#endif + l->head = NULL; + l->tail = NULL; + l->count = 0; +@@ -38,6 +63,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->prev = l->tail; + tmp->next = NULL; + if (l->tail) { +@@ -56,6 +86,11 @@ + { + zend_llist_element *tmp = pemalloc(sizeof(zend_llist_element)+l->size-1, l->persistent); + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++ tmp->canary = HG(canary_3); ++#endif + tmp->next = l->head; + tmp->prev = NULL; + if (l->head) { +@@ -93,10 +128,20 @@ + zend_llist_element *current=l->head; + zend_llist_element *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (compare(current->data, element)) { + DEL_LLIST_ELEMENT(current, l); ++#if HARDENING_PATCH_LL_PROTECT ++ current->canary = 0; ++#endif + break; + } + current = next; +@@ -108,7 +153,14 @@ + { + zend_llist_element *current=l->head, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + while (current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(current) ++#endif + next = current->next; + if (l->dtor) { + l->dtor(current->data); +@@ -133,7 +185,14 @@ + zend_llist_element *old_tail; + void *data; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if ((old_tail = l->tail)) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(old_tail) ++#endif + if (l->tail->prev) { + l->tail->prev->next = NULL; + } +@@ -159,9 +218,16 @@ + { + zend_llist_element *ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(src) ++#endif + zend_llist_init(dst, src->size, src->dtor, src->persistent); + ptr = src->head; + while (ptr) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(ptr) ++#endif + zend_llist_add_element(dst, ptr->data); + ptr = ptr->next; + } +@@ -172,11 +238,21 @@ + { + zend_llist_element *element, *next; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + element=l->head; + while (element) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + next = element->next; + if (func(element->data)) { + DEL_LLIST_ELEMENT(element, l); ++#if HARDENING_PATCH_LL_PROTECT ++ element->canary = 0; ++#endif + } + element = next; + } +@@ -187,7 +263,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data TSRMLS_CC); + } + } +@@ -199,6 +281,9 @@ + zend_llist_element **elements; + zend_llist_element *element, **ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + if (l->count <= 0) { + return; + } +@@ -208,6 +293,9 @@ + ptr = &elements[0]; + + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + *ptr++ = element; + } + +@@ -230,7 +318,13 @@ + { + zend_llist_element *element; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, arg TSRMLS_CC); + } + } +@@ -241,8 +335,14 @@ + zend_llist_element *element; + va_list args; + ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LIST_CANARY(l) ++#endif + va_start(args, num_args); + for (element=l->head; element; element=element->next) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(element) ++#endif + func(element->data, num_args, args TSRMLS_CC); + } + va_end(args); +@@ -251,6 +351,10 @@ + + ZEND_API int zend_llist_count(zend_llist *l) + { ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + return l->count; + } + +@@ -259,8 +363,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->head; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -272,8 +383,15 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + *current = l->tail; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } else { + return NULL; +@@ -285,9 +403,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->next; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +@@ -299,9 +427,19 @@ + { + zend_llist_position *current = pos ? pos : &l->traverse_ptr; + ++#if HARDENING_PATCH_LL_PROTECT ++ TSRMLS_FETCH(); ++ CHECK_LIST_CANARY(l) ++#endif + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + *current = (*current)->prev; + if (*current) { ++#if HARDENING_PATCH_LL_PROTECT ++ CHECK_LISTELEMENT_CANARY(*current) ++#endif + return (*current)->data; + } + } +diff -Nura php-5.0.5/Zend/zend_llist.h hardening-patch-5.0.5-0.4.3/Zend/zend_llist.h +--- php-5.0.5/Zend/zend_llist.h 2004-01-08 18:31:47.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_llist.h 2005-09-11 23:30:52.000000000 +0200 +@@ -23,6 +23,9 @@ + #define ZEND_LLIST_H + + typedef struct _zend_llist_element { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary; ++#endif + struct _zend_llist_element *next; + struct _zend_llist_element *prev; + char data[1]; /* Needs to always be last in the struct */ +@@ -35,6 +38,9 @@ + typedef void (*llist_apply_func_t)(void * TSRMLS_DC); + + typedef struct _zend_llist { ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_h; /* head */ ++#endif + zend_llist_element *head; + zend_llist_element *tail; + size_t count; +@@ -42,6 +48,9 @@ + llist_dtor_func_t dtor; + unsigned char persistent; + zend_llist_element *traverse_ptr; ++#if HARDENING_PATCH_LL_PROTECT ++ unsigned int canary_t; /* tail */ ++#endif + } zend_llist; + + typedef zend_llist_element* zend_llist_position; +diff -Nura php-5.0.5/Zend/zend_modules.h hardening-patch-5.0.5-0.4.3/Zend/zend_modules.h +--- php-5.0.5/Zend/zend_modules.h 2005-03-16 00:47:12.000000000 +0100 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_modules.h 2005-09-12 22:59:59.000000000 +0200 +@@ -38,6 +38,7 @@ + extern struct _zend_arg_info fourth_arg_force_ref[5]; + extern struct _zend_arg_info all_args_by_ref[1]; + ++#define HARDENING_PATCH_ZEND_MODULE_API_NO 1002050912 + #define ZEND_MODULE_API_NO 20041030 + #ifdef ZTS + #define USING_ZTS 1 +@@ -45,10 +46,10 @@ + #define USING_ZTS 0 + #endif + +-#define STANDARD_MODULE_HEADER sizeof(zend_module_entry), ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS, NULL +-#define ZE2_STANDARD_MODULE_HEADER sizeof(zend_module_entry), ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS, ini_entries ++#define STANDARD_MODULE_HEADER sizeof(zend_module_entry), HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS, NULL ++#define ZE2_STANDARD_MODULE_HEADER sizeof(zend_module_entry), HARDENING_PATCH_ZEND_MODULE_API_NO, ZEND_DEBUG, USING_ZTS, ini_entries + +-#define STANDARD_MODULE_PROPERTIES_EX 0, 0, 0, NULL, 0 ++#define STANDARD_MODULE_PROPERTIES_EX 0, 0, 0, NULL, 0, ZEND_MODULE_API_NO + + #define STANDARD_MODULE_PROPERTIES \ + NULL, STANDARD_MODULE_PROPERTIES_EX +@@ -81,6 +82,7 @@ + unsigned char type; + void *handle; + int module_number; ++ unsigned int real_zend_api; + }; + + +diff -Nura php-5.0.5/Zend/zend_opcode.c hardening-patch-5.0.5-0.4.3/Zend/zend_opcode.c +--- php-5.0.5/Zend/zend_opcode.c 2004-06-06 10:37:12.000000000 +0200 ++++ hardening-patch-5.0.5-0.4.3/Zend/zend_opcode.c 2005-09-11 23:30:52.000000000 +0200 +@@ -92,6 +92,9 @@ + op_array->uses_this = 0; + + op_array->start_op = NULL; ++#if HARDENING_PATCH ++ op_array->created_by_eval = 0; ++#endif + + zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC); + } -- cgit v1.3