From 36dbfacbe64697d959f524e537b15b73c090d898 Mon Sep 17 00:00:00 2001 From: Stefan Esser Date: Sun, 21 Feb 2010 11:44:54 +0100 Subject: Inital commit --- CREDITS | 2 + Changelog | 223 +++ aes.c | 382 +++++ compat_snprintf.c | 1001 +++++++++++++ config.m4 | 9 + config.w32 | 11 + crypt.c | 214 +++ crypt_blowfish.c | 751 ++++++++++ crypt_md5.c | 163 ++ crypt_md5.h | 37 + crypt_win32.c | 355 +++++ crypt_win32.h | 60 + ex_imp.c | 450 ++++++ execute.c | 1750 ++++++++++++++++++++++ header.c | 353 +++++ ifilter.c | 732 +++++++++ log.c | 404 +++++ mbregex.h | 26 + mbregex/COPYING.LIB | 515 +++++++ mbregex/mbregex.h | 213 +++ memory_limit.c | 90 ++ php_suhosin.h | 420 ++++++ post_handler.c | 114 ++ rfc1867.c | 1355 +++++++++++++++++ session.c | 714 +++++++++ sha256.c | 432 ++++++ sha256.h | 38 + suhosin.c | 1248 +++++++++++++++ suhosin.ini | 444 ++++++ suhosin_logo.h | 180 +++ suhosin_rfc1867.h | 88 ++ tests/empty.inc | 3 + tests/executor/disable_emod_off.phpt | 18 + tests/executor/disable_emod_on.phpt | 19 + tests/executor/disable_eval_off.phpt | 15 + tests/executor/disable_eval_on.phpt | 17 + tests/executor/memory_limit.phpt | 29 + tests/executor/memory_limit_other_hardlimit.phpt | 28 + tests/executor/negative_memory_limit.phpt | 18 + tests/executor/preg_replace.phpt | 30 + tests/executor/preg_replace_error.phpt | 32 + tests/executor/recursion_maxdepth.phpt | 31 + tests/filter/get_globals.phpt | 24 + tests/funcs/crypt_blowfish.phpt | 13 + tests/funcs/crypt_ext_des.phpt | 12 + tests/funcs/crypt_md5.phpt | 11 + tests/funcs/crypt_std_des.phpt | 11 + tests/funcs/sha256.phpt | 40 + tests/include/include_constant.phpt | 17 + tests/include/include_etc_passwd.phpt | 23 + tests/include/include_once_constant.phpt | 17 + tests/include/include_once_tmpvar.phpt | 19 + tests/include/include_once_var.phpt | 18 + tests/include/include_tmpvar.phpt | 19 + tests/include/include_var.phpt | 18 + tests/include/require_constant.phpt | 17 + tests/include/require_once_constant.phpt | 17 + tests/include/require_once_tmpvar.phpt | 19 + tests/include/require_once_var.phpt | 18 + tests/include/require_tmpvar.phpt | 19 + tests/include/require_var.phpt | 18 + tests/skipif.inc | 4 + tests/skipifcli.inc | 8 + tests/skipifnotcli.inc | 8 + treat_data.c | 216 +++ ufilter.c | 367 +++++ 66 files changed, 13967 insertions(+) create mode 100644 CREDITS create mode 100644 Changelog create mode 100644 aes.c create mode 100644 compat_snprintf.c create mode 100644 config.m4 create mode 100644 config.w32 create mode 100644 crypt.c create mode 100644 crypt_blowfish.c create mode 100644 crypt_md5.c create mode 100644 crypt_md5.h create mode 100644 crypt_win32.c create mode 100644 crypt_win32.h create mode 100644 ex_imp.c create mode 100644 execute.c create mode 100644 header.c create mode 100644 ifilter.c create mode 100644 log.c create mode 100644 mbregex.h create mode 100644 mbregex/COPYING.LIB create mode 100644 mbregex/mbregex.h create mode 100644 memory_limit.c create mode 100644 php_suhosin.h create mode 100644 post_handler.c create mode 100644 rfc1867.c create mode 100644 session.c create mode 100644 sha256.c create mode 100644 sha256.h create mode 100644 suhosin.c create mode 100644 suhosin.ini create mode 100644 suhosin_logo.h create mode 100644 suhosin_rfc1867.h create mode 100644 tests/empty.inc create mode 100644 tests/executor/disable_emod_off.phpt create mode 100644 tests/executor/disable_emod_on.phpt create mode 100644 tests/executor/disable_eval_off.phpt create mode 100644 tests/executor/disable_eval_on.phpt create mode 100644 tests/executor/memory_limit.phpt create mode 100644 tests/executor/memory_limit_other_hardlimit.phpt create mode 100644 tests/executor/negative_memory_limit.phpt create mode 100644 tests/executor/preg_replace.phpt create mode 100644 tests/executor/preg_replace_error.phpt create mode 100644 tests/executor/recursion_maxdepth.phpt create mode 100644 tests/filter/get_globals.phpt create mode 100644 tests/funcs/crypt_blowfish.phpt create mode 100644 tests/funcs/crypt_ext_des.phpt create mode 100644 tests/funcs/crypt_md5.phpt create mode 100644 tests/funcs/crypt_std_des.phpt create mode 100644 tests/funcs/sha256.phpt create mode 100644 tests/include/include_constant.phpt create mode 100644 tests/include/include_etc_passwd.phpt create mode 100644 tests/include/include_once_constant.phpt create mode 100644 tests/include/include_once_tmpvar.phpt create mode 100644 tests/include/include_once_var.phpt create mode 100644 tests/include/include_tmpvar.phpt create mode 100644 tests/include/include_var.phpt create mode 100644 tests/include/require_constant.phpt create mode 100644 tests/include/require_once_constant.phpt create mode 100644 tests/include/require_once_tmpvar.phpt create mode 100644 tests/include/require_once_var.phpt create mode 100644 tests/include/require_tmpvar.phpt create mode 100644 tests/include/require_var.phpt create mode 100644 tests/skipif.inc create mode 100644 tests/skipifcli.inc create mode 100644 tests/skipifnotcli.inc create mode 100644 treat_data.c create mode 100644 ufilter.c diff --git a/CREDITS b/CREDITS new file mode 100644 index 0000000..db77681 --- /dev/null +++ b/CREDITS @@ -0,0 +1,2 @@ +suhosin +Stefan Esser diff --git a/Changelog b/Changelog new file mode 100644 index 0000000..eb90e44 --- /dev/null +++ b/Changelog @@ -0,0 +1,223 @@ +2009-08-15 - 0.9.29 + + - Fixing crash bugs with PHP 5.3.0 caused by unexpected NULL in EG(active_symbol_table) + - Added more compatible way to retrieve ext/session globals + - Increased default length and count limit for POST variables (for people not reading docu) + +2009-08-14 - 0.9.28 + + - Fixed crash bug with PHP 5.2.10 caused by a change in extension load order of ext/session + - Fixed harmless parameter order error in a bogus memset() + - Disable suhosin.session.cryptua by default because of Internet Explorer 8 "features" + - Added suhosin.executor.include.allow_writable_files which can be disabled to disallow + inclusion of files writable by the webserver + +2008-08-23 - 0.9.27 + + - Fixed typo in replacement rand() / mt_rand() that was hidden by LAZY symbol loading + +2008-08-22 - 0.9.26 + + - Fixed problem with suhosin.perdir + Thanks to Hosteurope for tracking this down + - Fixed problems with ext/uploadprogress + Reported by: Christian Stocker + - Added suhosin.srand.ignore and suhosin.mt_srand.ignore (default: on) + - Modified rand()/srand() to use the Mersenne Twister algorithm with separate state + - Added better internal seeding of rand() and mt_rand() + +2008-08-06 - 0.9.25 + + - Fixed PHP 4 compilation problem introduced in 0.9.24 + - Fixed PHP 5.3 compilation problem + - Changed PHP default POST handler to PHP's current handler + +2008-05-10 - 0.9.24 + + - Added support for method-calls to function handling + - This fixes white- and blacklist affecting methods with the same name + +2008-01-14 - 0.9.23 + + - Fixed suhosin extension now compiles with snapshots of PHP 5.3 + - Fixed crypt() behaves like normal again when there is no salt supplied + +2007-12-01 - 0.9.22 + + - Removed LFS warning message because it crashed on several systems + +2007-11-30 - 0.9.21 + + - Fixed function_exists() now checks the Suhosin permissions + - Fixed crypt() salt no longer uses Blowfish by default + - Fixed .htaccess/perdir support + - Fixed compilation problem on OS/X + - Added protection against some attacks through _SERVER variables + - Added suhosin.server.strip and suhosin.server.encode + - Added error message that warns about the LFS binary incompatibility + +2007-05-19 - 0.9.20 + + - Added protection flags against whitespace at variable start + - Added mutex around crypt() to close the PHP crypt() + thread safety vulnerability class + - Improved HTTP Response Splitting Protection + - Changed default maximum array depth to 50 for GPCR + - Fixed possible endless loop in file logging + - Fixed file locking in file logging + +2007-05-01 - 0.9.19 + + - Fixed typo in HTTP header protection (only during simulation mode) + Reported by: Ilia Alshanetsky + - Fixed wrong \0 termination in cookie decryptor + - Fixed possible crash in SERVER variables protection when SAPI=embedded + Fix provided by: Olivier Blin/Mandriva Linux + - Added possibility to en-/disable INI_PERDIR + Problem reported by: Ilia Alshanetsky + - Added PHP Warning when disabled function is called + - Added examples for new configuration option in suhosin.ini + +2007-03-06 - 0.9.18 + + - Fixed session double hooking in edge case + - Added additional crash protection for PHP's session module + +2007-03-04 - 0.9.17 + + - Added a suhosin.ini example configuration + Thanks to Mandriva Linux for supplying us with one + - Added new logging device: file + - Fixed that suhosin.filter.action did not affect POST limits + - Fixed behaviour of request variable limit to be an upper limit + for the other settings instead of being additive limit + - Fixed hard_memory_limit bypass due to casting bug in PHP + Problem was found by: Ilia Alshanetsky + - Fixed some sql prefix/postfix problems + - Added experimental SQL injection heuristic + +2006-12-02 - 0.9.16 + + - Added suhosin.stealth which controls if suhosin loads in + stealth mode when it is not the only zend_extension + (Required for full compatibility with certain encoders + that consider open source untrusted. e.g. ionCube, Zend) + - Activate suhosin.stealth by default + - Fixed that Suhosin tries handling functions disabled by + disable_function. In v0.9.15 it was impossible to disable + phpinfo() with disable_function. + Problem was found by: Thorsten Schifferdecker + +2006-11-28 - 0.9.15 + + - Added a transparent protection for open phpinfo() pages by + adding an HTML META ROBOTS tag to the output that forbids + indexing and archiving + +2006-11-22 - 0.9.14 + + - Drop wrongly decrypted cookies instead of leaving them empty + - Fix another problem with urlencoded cookie names + - Fix compilation problem with PHP4 + - Added better regression to the release process to stop + compilation and missing symbol problems + +2006-11-20 - 0.9.13 + + - More compatible support for ap_php_snprintf() for old PHP + - Changed phpinfo() output to put suhosin logo into a data: URL + for Opera and Gecko based browsers when expose_php=off + +2006-11-14 - 0.9.12 + + - Adding ap_php_snprintf() when compiling against PHP 4.3.9 + - Added suhosin.protectkey to remove cryptkeys from phpinfo() output + - Disabled suhosin.cookie.encrypt in default install + - Fixed static compilation against PHP 5.2.0 + +2006-11-06 - 0.9.11 + + - Fixed input filter for simulation mode + +2006-10-26 - 0.9.10 + + - Fixed ZTS compile problem in new code + - Fixed PHP4 compile problem in new code + +2006-10-25 - 0.9.9 + + - Fixed mail() protection that failed to detect some injected headers + - Fixed cookie decryption to not potentially trash apache memory + - Fixed cookie enctyption to handle url encoded names correctly + - Added suhosin.cookie/session.checkraddr + - Added suhosin.cookie.cryptlist + - Added suhosin.cookie.plainlist + - Added suhosin_encrypt_cookie function for JS + - Added suhosin_get_raw_cookies function + - Changed dropped variable error messages + +2006-10-08 - 0.9.8 + + - Fixed a PHP4 ZTS compile problem + +2006-10-08 - 0.9.7 + + - Moved input handler hooking to a later place to ensure better compatibility + with 3rd party extensions + - Fixed a problem with overlong mail headers in mail protection + - Fixed a problem with empty log/verification script names + - Fixed a PHP4 compile problem with old gcc/in ZTS mode + - Added mbregex.h from PHP4 to solve compile problems on systesm with broken + header installations + +2006-10-02 - 0.9.6 + + - Disallow symlink() when open_basedir (activated by default) + - Fix a problem with compilation in Visual Studio + +2006-09-29 - 0.9.5 + + - Added missing logo file + - Added suhosin.apc_bug_workaround flag to enable compatibility with buggy APC 3.0.12x + +2006-09-29 - 0.9.4 + + - Added version number and logo to phpinfo() output + - Fixed that all uploaded files are dropped after a single one was disallowed + - Added undocumented suhosin.coredump flag to tell suhosin to dump core instead + of logging S_MEMORY events + - Disable handling of rfc1867 mbstring decoding + +2006-09-24 - 0.9.3 + + - Added protection against endless recursion for suhosin.log.phpscript + - Added possibility to disable open_basedir and safe_mode for suhosin.log.phpscript + - Added suhosin.executor.include.max_traversal to stop directory traversal includes + +2006-09-19 - 0.9.2 + + - Fixes broken rfc1867 fileupload hook + - Changed definition of binary to: 0..31, 128..255 except whitespace + - Added suhosin.log.phpscript(.name) directive to log to a PHP script + +2006-09-16 - 0.9.1 + + - A bunch of changes to compile and work on Windows + +2006-09-09 - BETA + + - Added decryption of HTTP_COOKIE + - Fixed a last problem in suhosin_strcasestr() helper function + +2006-09-08 - BETA + + - Fixed a problem within suhosin_strcasestr() because it broke + URL checks + +2006-09-07 - BETA + + - CVS version of PHP 5.2.0 was changed to support incasesensitive + URLs, support for this in suhosin added + - Fixed a problem when preg_replace() was called with more than + 4 parameters + diff --git a/aes.c b/aes.c new file mode 100644 index 0000000..f8804da --- /dev/null +++ b/aes.c @@ -0,0 +1,382 @@ +/* Rijndael Block Cipher - rijndael.c + + Written by Mike Scott 21st April 1999 + mike@compapp.dcu.ie + An alternative faster version is implemented in MIRACL + ftp://ftp.computing.dcu.ie/pub/crypto/miracl.zip + + Copyright (c) 1999 Mike Scott + + Simply compile and run, e.g. + + cl /O2 rijndael.c (Microsoft C) + bcc32 /O2 rijndael.c (Borland C) + gcc -O2 rijndael.c -o rijndael (Gnu C) + + Compiles and runs fine as a C++ program also. + + See rijndael documentation. The code follows the documentation as closely + as possible, and where possible uses the same function and variable names. + + Permission for free direct or derivative use is granted subject + to compliance with any conditions that the originators of the + algorithm place on its exploitation. + + Inspiration from Brian Gladman's implementation is acknowledged. + + Written for clarity, rather than speed. + Assumes long is 32 bit quantity. + Full implementation. + Endian indifferent. +*/ + +#include "php.h" +#include "php_suhosin.h" + +/* rotates x one bit to the left */ + +#define ROTL(x) (((x)>>7)|((x)<<1)) + +/* Rotates 32-bit word left by 1, 2 or 3 byte */ + +#define ROTL8(x) (((x)<<8)|((x)>>24)) +#define ROTL16(x) (((x)<<16)|((x)>>16)) +#define ROTL24(x) (((x)<<24)|((x)>>8)) + +/* Fixed Data */ + +static BYTE InCo[4]={0xB,0xD,0x9,0xE}; /* Inverse Coefficients */ + +static BYTE fbsub[256]; +static BYTE rbsub[256]; +static BYTE ptab[256],ltab[256]; +static WORD ftable[256]; +static WORD rtable[256]; +static WORD rco[30]; + +/* Parameter-dependent data */ + +static int Nk,Nb,Nr; + +static WORD pack(BYTE *b) +{ /* pack bytes into a 32-bit Word */ + return ((WORD)b[3]<<24)|((WORD)b[2]<<16)|((WORD)b[1]<<8)|(WORD)b[0]; +} + +static void unpack(WORD a,BYTE *b) +{ /* unpack bytes from a word */ + b[0]=(BYTE)a; + b[1]=(BYTE)(a>>8); + b[2]=(BYTE)(a>>16); + b[3]=(BYTE)(a>>24); +} + +static BYTE xtime(BYTE a) +{ + BYTE b; + if (a&0x80) b=0x1B; + else b=0; + a<<=1; + a^=b; + return a; +} + +static BYTE bmul(BYTE x,BYTE y) +{ /* x.y= AntiLog(Log(x) + Log(y)) */ + if (x && y) return ptab[(ltab[x]+ltab[y])%255]; + else return 0; +} + +static WORD SubByte(WORD a) +{ + BYTE b[4]; + unpack(a,b); + b[0]=fbsub[b[0]]; + b[1]=fbsub[b[1]]; + b[2]=fbsub[b[2]]; + b[3]=fbsub[b[3]]; + return pack(b); +} + +static BYTE product(WORD x,WORD y) +{ /* dot product of two 4-byte arrays */ + BYTE xb[4],yb[4]; + unpack(x,xb); + unpack(y,yb); + return bmul(xb[0],yb[0])^bmul(xb[1],yb[1])^bmul(xb[2],yb[2])^bmul(xb[3],yb[3]); +} + +static WORD InvMixCol(WORD x) +{ /* matrix Multiplication */ + WORD y,m; + BYTE b[4]; + + m=pack(InCo); + b[3]=product(m,x); + m=ROTL24(m); + b[2]=product(m,x); + m=ROTL24(m); + b[1]=product(m,x); + m=ROTL24(m); + b[0]=product(m,x); + y=pack(b); + return y; +} + +static BYTE ByteSub(BYTE x) +{ + BYTE y=ptab[255-ltab[x]]; /* multiplicative inverse */ + x=y; x=ROTL(x); + y^=x; x=ROTL(x); + y^=x; x=ROTL(x); + y^=x; x=ROTL(x); + y^=x; y^=0x63; + return y; +} + +void suhosin_aes_gentables() +{ /* generate tables */ + int i; + BYTE y,b[4]; + + /* use 3 as primitive root to generate power and log tables */ + + ltab[0]=0; + ptab[0]=1; ltab[1]=0; + ptab[1]=3; ltab[3]=1; + for (i=2;i<256;i++) + { + ptab[i]=ptab[i-1]^xtime(ptab[i-1]); + ltab[ptab[i]]=i; + } + + /* affine transformation:- each bit is xored with itself shifted one bit */ + + fbsub[0]=0x63; + rbsub[0x63]=0; + for (i=1;i<256;i++) + { + y=ByteSub((BYTE)i); + fbsub[i]=y; rbsub[y]=i; + } + + for (i=0,y=1;i<30;i++) + { + rco[i]=y; + y=xtime(y); + } + + /* calculate forward and reverse tables */ + for (i=0;i<256;i++) + { + y=fbsub[i]; + b[3]=y^xtime(y); b[2]=y; + b[1]=y; b[0]=xtime(y); + ftable[i]=pack(b); + + y=rbsub[i]; + b[3]=bmul(InCo[0],y); b[2]=bmul(InCo[1],y); + b[1]=bmul(InCo[2],y); b[0]=bmul(InCo[3],y); + rtable[i]=pack(b); + } +} + +void suhosin_aes_gkey(int nb,int nk,char *key TSRMLS_DC) +{ /* blocksize=32*nb bits. Key=32*nk bits */ + /* currently nb,bk = 4, 6 or 8 */ + /* key comes as 4*Nk bytes */ + /* Key Scheduler. Create expanded encryption key */ + int i,j,k,m,N; + int C1,C2,C3; + WORD CipherKey[8]; + + Nb=nb; Nk=nk; + + /* Nr is number of rounds */ + if (Nb>=Nk) Nr=6+Nb; + else Nr=6+Nk; + + C1=1; + if (Nb<8) { C2=2; C3=3; } + else { C2=3; C3=4; } + + /* pre-calculate forward and reverse increments */ + for (m=j=0;j>8)])^ + ROTL16(ftable[(BYTE)(x[SUHOSIN_G(fi)[m+1]]>>16)])^ + ROTL24(ftable[x[SUHOSIN_G(fi)[m+2]]>>24]); + } + t=x; x=y; y=t; /* swap pointers */ + } + +/* Last Round - unroll if possible */ + for (m=j=0;j>8)])^ + ROTL16((WORD)fbsub[(BYTE)(x[SUHOSIN_G(fi)[m+1]]>>16)])^ + ROTL24((WORD)fbsub[x[SUHOSIN_G(fi)[m+2]]>>24]); + } + for (i=j=0;i>8)])^ + ROTL16(rtable[(BYTE)(x[SUHOSIN_G(ri)[m+1]]>>16)])^ + ROTL24(rtable[x[SUHOSIN_G(ri)[m+2]]>>24]); + } + t=x; x=y; y=t; /* swap pointers */ + } + +/* Last Round - unroll if possible */ + for (m=j=0;j>8)])^ + ROTL16((WORD)rbsub[(BYTE)(x[SUHOSIN_G(ri)[m+1]]>>16)])^ + ROTL24((WORD)rbsub[x[SUHOSIN_G(ri)[m+2]]>>24]); + } + for (i=j=0;i. + * + * This code is based on, and used with the permission of, the + * SIO stdio-replacement strx_* functions by Panos Tsirigotis + * for xinetd. + */ + +#include "php.h" + +#if ((PHP_MAJOR_VERSION == 4) && (PHP_MINOR_VERSION == 3) && (PHP_RELEASE_VERSION < 10)) + +#include +#include +#include +#include +#include +#include +#include + +#define FALSE 0 +#define TRUE 1 +#define NUL '\0' +#define INT_NULL ((int *)0) + +#define S_NULL "(null)" +#define S_NULL_LEN 6 + +#define FLOAT_DIGITS 6 +#define EXPONENT_LENGTH 10 + + +/* + * Convert num to its decimal format. + * Return value: + * - a pointer to a string containing the number (no sign) + * - len contains the length of the string + * - is_negative is set to TRUE or FALSE depending on the sign + * of the number (always set to FALSE if is_unsigned is TRUE) + * + * The caller provides a buffer for the string: that is the buf_end argument + * which is a pointer to the END of the buffer + 1 (i.e. if the buffer + * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) + */ +char * +ap_php_conv_10(register wide_int num, register bool_int is_unsigned, + register bool_int * is_negative, char *buf_end, register int *len) +{ + register char *p = buf_end; + register u_wide_int magnitude; + + if (is_unsigned) { + magnitude = (u_wide_int) num; + *is_negative = FALSE; + } else { + *is_negative = (num < 0); + + /* + * On a 2's complement machine, negating the most negative integer + * results in a number that cannot be represented as a signed integer. + * Here is what we do to obtain the number's magnitude: + * a. add 1 to the number + * b. negate it (becomes positive) + * c. convert it to unsigned + * d. add 1 + */ + if (*is_negative) { + wide_int t = num + 1; + + magnitude = ((u_wide_int) - t) + 1; + } else + magnitude = (u_wide_int) num; + } + + /* + * We use a do-while loop so that we write at least 1 digit + */ + do { + register u_wide_int new_magnitude = magnitude / 10; + + *--p = (char)(magnitude - new_magnitude * 10 + '0'); + magnitude = new_magnitude; + } + while (magnitude); + + *len = buf_end - p; + return (p); +} + +/* If you change this value then also change bug24640.phpt. + */ +#define NDIG 80 + + +/* + * Convert a floating point number to a string formats 'f', 'e' or 'E'. + * The result is placed in buf, and len denotes the length of the string + * The sign is returned in the is_negative argument (and is not placed + * in buf). + */ +char * + ap_php_conv_fp(register char format, register double num, + boolean_e add_dp, int precision, bool_int * is_negative, char *buf, int *len) +{ + register char *s = buf; + register char *p; + int decimal_point; + char buf1[NDIG]; + + if (format == 'f') + p = ap_php_fcvt(num, precision, &decimal_point, is_negative, buf1); + else /* either e or E format */ + p = ap_php_ecvt(num, precision + 1, &decimal_point, is_negative, buf1); + + /* + * Check for Infinity and NaN + */ + if (isalpha((int)*p)) { + *len = strlen(p); + memcpy(buf, p, *len + 1); + *is_negative = FALSE; + return (buf); + } + if (format == 'f') { + if (decimal_point <= 0) { + *s++ = '0'; + if (precision > 0) { + *s++ = '.'; + while (decimal_point++ < 0) + *s++ = '0'; + } else if (add_dp) { + *s++ = '.'; + } + } else { + while (decimal_point-- > 0) { + *s++ = *p++; + } + if (precision > 0 || add_dp) { + *s++ = '.'; + } + } + } else { + *s++ = *p++; + if (precision > 0 || add_dp) + *s++ = '.'; + } + + /* + * copy the rest of p, the NUL is NOT copied + */ + while (*p) + *s++ = *p++; + + if (format != 'f') { + char temp[EXPONENT_LENGTH]; /* for exponent conversion */ + int t_len; + bool_int exponent_is_negative; + + *s++ = format; /* either e or E */ + decimal_point--; + if (decimal_point != 0) { + p = ap_php_conv_10((wide_int) decimal_point, FALSE, &exponent_is_negative, + &temp[EXPONENT_LENGTH], &t_len); + *s++ = exponent_is_negative ? '-' : '+'; + + /* + * Make sure the exponent has at least 2 digits + */ + if (t_len == 1) + *s++ = '0'; + while (t_len--) + *s++ = *p++; + } else { + *s++ = '+'; + *s++ = '0'; + *s++ = '0'; + } + } + *len = s - buf; + return (buf); +} + + +/* + * Convert num to a base X number where X is a power of 2. nbits determines X. + * For example, if nbits is 3, we do base 8 conversion + * Return value: + * a pointer to a string containing the number + * + * The caller provides a buffer for the string: that is the buf_end argument + * which is a pointer to the END of the buffer + 1 (i.e. if the buffer + * is declared as buf[ 100 ], buf_end should be &buf[ 100 ]) + */ +char * + ap_php_conv_p2(register u_wide_int num, register int nbits, + char format, char *buf_end, register int *len) +{ + register int mask = (1 << nbits) - 1; + register char *p = buf_end; + static char low_digits[] = "0123456789abcdef"; + static char upper_digits[] = "0123456789ABCDEF"; + register char *digits = (format == 'X') ? upper_digits : low_digits; + + do { + *--p = digits[num & mask]; + num >>= nbits; + } + while (num); + + *len = buf_end - p; + return (p); +} + +/* + * cvt.c - IEEE floating point formatting routines for FreeBSD + * from GNU libc-4.6.27 + */ + +/* + * ap_php_ecvt converts to decimal + * the number of digits is specified by ndigit + * decpt is set to the position of the decimal point + * sign is set to 0 for positive, 1 for negative + */ + + +char * +ap_php_cvt(double arg, int ndigits, int *decpt, int *sign, int eflag, char *buf) +{ + register int r2; + int mvl; + double fi, fj; + register char *p, *p1; + + if (ndigits >= NDIG - 1) + ndigits = NDIG - 2; + r2 = 0; + *sign = 0; + p = &buf[0]; + if (arg < 0) { + *sign = 1; + arg = -arg; + } + arg = modf(arg, &fi); + p1 = &buf[NDIG]; + /* + * Do integer part + */ + if (fi != 0) { + p1 = &buf[NDIG]; + while (fi != 0) { + fj = modf(fi / 10, &fi); + if (p1 <= &buf[0]) { + mvl = NDIG - ndigits; + memmove(&buf[mvl], &buf[0], NDIG-mvl-1); + p1 += mvl; + } + *--p1 = (int) ((fj + .03) * 10) + '0'; + r2++; + } + while (p1 < &buf[NDIG]) + *p++ = *p1++; + } else if (arg > 0) { + while ((fj = arg * 10) < 1) { + if (!eflag && (r2 * -1) < ndigits) { + break; + } + arg = fj; + r2--; + } + } + p1 = &buf[ndigits]; + if (eflag == 0) + p1 += r2; + *decpt = r2; + if (p1 < &buf[0]) { + buf[0] = '\0'; + return (buf); + } + if (p <= p1 && p < &buf[NDIG]) { + arg = modf(arg * 10, &fj); + if ((int)fj==10) { + *p++ = '1'; + fj = 0; + *decpt = ++r2; + } + while (p <= p1 && p < &buf[NDIG]) { + *p++ = (int) fj + '0'; + arg = modf(arg * 10, &fj); + } + } + if (p1 >= &buf[NDIG]) { + buf[NDIG - 1] = '\0'; + return (buf); + } + p = p1; + *p1 += 5; + while (*p1 > '9') { + *p1 = '0'; + if (p1 > buf) + ++ * --p1; + else { + *p1 = '1'; + (*decpt)++; + if (eflag == 0) { + if (p > buf) + *p = '0'; + p++; + } + } + } + *p = '\0'; + return (buf); +} + +char * +ap_php_ecvt(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return (ap_php_cvt(arg, ndigits, decpt, sign, 1, buf)); +} + +char * +ap_php_fcvt(double arg, int ndigits, int *decpt, int *sign, char *buf) +{ + return (ap_php_cvt(arg, ndigits, decpt, sign, 0, buf)); +} + +/* + * ap_php_gcvt - Floating output conversion to + * minimal length string + */ + +char * +ap_php_gcvt(double number, int ndigit, char *buf, boolean_e altform) +{ + int sign, decpt; + register char *p1, *p2; + register int i; + char buf1[NDIG]; + + if (ndigit >= NDIG - 1) { + ndigit = NDIG - 2; + } + + p1 = ap_php_ecvt(number, ndigit, &decpt, &sign, buf1); + p2 = buf; + if (sign) + *p2++ = '-'; + for (i = ndigit - 1; i > 0 && p1[i] == '0'; i--) + ndigit--; + if ((decpt >= 0 && decpt - ndigit > 4) + || (decpt < 0 && decpt < -3)) { /* use E-style */ + decpt--; + *p2++ = *p1++; + *p2++ = '.'; + for (i = 1; i < ndigit; i++) + *p2++ = *p1++; + if (*(p2 - 1) == '.') { + *p2++ = '0'; + } + *p2++ = 'e'; + if (decpt < 0) { + decpt = -decpt; + *p2++ = '-'; + } else + *p2++ = '+'; + if (decpt / 100 > 0) + *p2++ = decpt / 100 + '0'; + if (decpt / 10 > 0) + *p2++ = (decpt % 100) / 10 + '0'; + *p2++ = decpt % 10 + '0'; + } else { + if (decpt <= 0) { + if (*p1 != '0') { + *p2++ = '0'; + *p2++ = '.'; + } + while (decpt < 0) { + decpt++; + *p2++ = '0'; + } + } + for (i = 1; i <= ndigit; i++) { + *p2++ = *p1++; + if (i == decpt) + *p2++ = '.'; + } + if (ndigit < decpt) { + while (ndigit++ < decpt) + *p2++ = '0'; + *p2++ = '.'; + } + } + if (p2[-1] == '.' && !altform) + p2--; + *p2 = '\0'; + return (buf); +} + + +/* + * NUM_BUF_SIZE is the size of the buffer used for arithmetic conversions + * + * XXX: this is a magic number; do not decrease it + */ +#define NUM_BUF_SIZE 512 + + +/* + * Descriptor for buffer area + */ +struct buf_area { + char *buf_end; + char *nextb; /* pointer to next byte to read/write */ +}; + +typedef struct buf_area buffy; + +/* + * The INS_CHAR macro inserts a character in the buffer and writes + * the buffer back to disk if necessary + * It uses the char pointers sp and bep: + * sp points to the next available character in the buffer + * bep points to the end-of-buffer+1 + * While using this macro, note that the nextb pointer is NOT updated. + * + * NOTE: Evaluation of the c argument should not have any side-effects + */ +#define INS_CHAR(c, sp, bep, cc) \ + { \ + if (sp < bep) \ + { \ + *sp++ = c; \ + } \ + cc++; \ + } + +#define NUM( c ) ( c - '0' ) + +#define STR_TO_DEC( str, num ) \ + num = NUM( *str++ ) ; \ + while ( isdigit((int)*str ) ) \ + { \ + num *= 10 ; \ + num += NUM( *str++ ) ; \ + } + +/* + * This macro does zero padding so that the precision + * requirement is satisfied. The padding is done by + * adding '0's to the left of the string that is going + * to be printed. + */ +#define FIX_PRECISION( adjust, precision, s, s_len ) \ + if ( adjust ) \ + while ( s_len < precision ) \ + { \ + *--s = '0' ; \ + s_len++ ; \ + } + +/* + * Macro that does padding. The padding is done by printing + * the character ch. + */ +#define PAD( width, len, ch ) do \ + { \ + INS_CHAR( ch, sp, bep, cc ) ; \ + width-- ; \ + } \ + while ( width > len ) + +/* + * Prefix the character ch to the string str + * Increase length + * Set the has_prefix flag + */ +#define PREFIX( str, length, ch ) *--str = ch ; length++ ; has_prefix = YES + + +/* + * Do format conversion placing the output in buffer + */ +static int format_converter(register buffy * odp, const char *fmt, + va_list ap) +{ + register char *sp; + register char *bep; + register int cc = 0; + register int i; + + register char *s = NULL; + char *q; + int s_len; + + register int min_width = 0; + int precision = 0; + enum { + LEFT, RIGHT + } adjust; + char pad_char; + char prefix_char; + + double fp_num; + wide_int i_num = (wide_int) 0; + u_wide_int ui_num; + + char num_buf[NUM_BUF_SIZE]; + char char_buf[2]; /* for printing %% and % */ + + /* + * Flag variables + */ + boolean_e is_long; + boolean_e alternate_form; + boolean_e print_sign; + boolean_e print_blank; + boolean_e adjust_precision; + boolean_e adjust_width; + bool_int is_negative; + + sp = odp->nextb; + bep = odp->buf_end; + + while (*fmt) { + if (*fmt != '%') { + INS_CHAR(*fmt, sp, bep, cc); + } else { + /* + * Default variable settings + */ + adjust = RIGHT; + alternate_form = print_sign = print_blank = NO; + pad_char = ' '; + prefix_char = NUL; + + fmt++; + + /* + * Try to avoid checking for flags, width or precision + */ + if (isascii((int)*fmt) && !islower((int)*fmt)) { + /* + * Recognize flags: -, #, BLANK, + + */ + for (;; fmt++) { + if (*fmt == '-') + adjust = LEFT; + else if (*fmt == '+') + print_sign = YES; + else if (*fmt == '#') + alternate_form = YES; + else if (*fmt == ' ') + print_blank = YES; + else if (*fmt == '0') + pad_char = '0'; + else + break; + } + + /* + * Check if a width was specified + */ + if (isdigit((int)*fmt)) { + STR_TO_DEC(fmt, min_width); + adjust_width = YES; + } else if (*fmt == '*') { + min_width = va_arg(ap, int); + fmt++; + adjust_width = YES; + if (min_width < 0) { + adjust = LEFT; + min_width = -min_width; + } + } else + adjust_width = NO; + + /* + * Check if a precision was specified + * + * XXX: an unreasonable amount of precision may be specified + * resulting in overflow of num_buf. Currently we + * ignore this possibility. + */ + if (*fmt == '.') { + adjust_precision = YES; + fmt++; + if (isdigit((int)*fmt)) { + STR_TO_DEC(fmt, precision); + } else if (*fmt == '*') { + precision = va_arg(ap, int); + fmt++; + if (precision < 0) + precision = 0; + } else + precision = 0; + } else + adjust_precision = NO; + } else + adjust_precision = adjust_width = NO; + + /* + * Modifier check + */ + if (*fmt == 'l') { + is_long = YES; + fmt++; + } else + is_long = NO; + + /* + * Argument extraction and printing. + * First we determine the argument type. + * Then, we convert the argument to a string. + * On exit from the switch, s points to the string that + * must be printed, s_len has the length of the string + * The precision requirements, if any, are reflected in s_len. + * + * NOTE: pad_char may be set to '0' because of the 0 flag. + * It is reset to ' ' by non-numeric formats + */ + switch (*fmt) { + case 'u': + if (is_long) + i_num = va_arg(ap, u_wide_int); + else + i_num = (wide_int) va_arg(ap, unsigned int); + /* + * The rest also applies to other integer formats, so fall + * into that case. + */ + case 'd': + case 'i': + /* + * Get the arg if we haven't already. + */ + if ((*fmt) != 'u') { + if (is_long) + i_num = va_arg(ap, wide_int); + else + i_num = (wide_int) va_arg(ap, int); + }; + s = ap_php_conv_10(i_num, (*fmt) == 'u', &is_negative, + &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + + if (*fmt != 'u') { + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + } + break; + + + case 'o': + if (is_long) + ui_num = va_arg(ap, u_wide_int); + else + ui_num = (u_wide_int) va_arg(ap, unsigned int); + s = ap_php_conv_p2(ui_num, 3, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && *s != '0') { + *--s = '0'; + s_len++; + } + break; + + + case 'x': + case 'X': + if (is_long) + ui_num = (u_wide_int) va_arg(ap, u_wide_int); + else + ui_num = (u_wide_int) va_arg(ap, unsigned int); + s = ap_php_conv_p2(ui_num, 4, *fmt, + &num_buf[NUM_BUF_SIZE], &s_len); + FIX_PRECISION(adjust_precision, precision, s, s_len); + if (alternate_form && i_num != 0) { + *--s = *fmt; /* 'x' or 'X' */ + *--s = '0'; + s_len += 2; + } + break; + + + case 's': + s = va_arg(ap, char *); + if (s != NULL) { + s_len = strlen(s); + if (adjust_precision && precision < s_len) + s_len = precision; + } else { + s = S_NULL; + s_len = S_NULL_LEN; + } + pad_char = ' '; + break; + + + case 'f': + case 'e': + case 'E': + fp_num = va_arg(ap, double); + + if (zend_isnan(fp_num)) { + s = "nan"; + s_len = 3; + } else if (zend_isinf(fp_num)) { + s = "inf"; + s_len = 3; + } else { + s = ap_php_conv_fp(*fmt, fp_num, alternate_form, + (adjust_precision == NO) ? FLOAT_DIGITS : precision, + &is_negative, &num_buf[1], &s_len); + if (is_negative) + prefix_char = '-'; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + } + break; + + + case 'g': + case 'G': + fp_num = va_arg(ap, double); + + if (zend_isnan(fp_num)) { + s = "NAN"; + s_len = 3; + break; + } else if (zend_isinf(fp_num)) { + if (fp_num > 0) { + s = "INF"; + s_len = 3; + } else { + s = "-INF"; + s_len = 4; + } + break; + } + + if (adjust_precision == NO) + precision = FLOAT_DIGITS; + else if (precision == 0) + precision = 1; + /* + * * We use &num_buf[ 1 ], so that we have room for the sign + */ + s = ap_php_gcvt(fp_num, precision, &num_buf[1], alternate_form); + if (*s == '-') + prefix_char = *s++; + else if (print_sign) + prefix_char = '+'; + else if (print_blank) + prefix_char = ' '; + + s_len = strlen(s); + + if (alternate_form && (q = strchr(s, '.')) == NULL) + s[s_len++] = '.'; + if (*fmt == 'G' && (q = strchr(s, 'e')) != NULL) + *q = 'E'; + break; + + + case 'c': + char_buf[0] = (char) (va_arg(ap, int)); + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case '%': + char_buf[0] = '%'; + s = &char_buf[0]; + s_len = 1; + pad_char = ' '; + break; + + + case 'n': + *(va_arg(ap, int *)) = cc; + break; + + /* + * Always extract the argument as a "char *" pointer. We + * should be using "void *" but there are still machines + * that don't understand it. + * If the pointer size is equal to the size of an unsigned + * integer we convert the pointer to a hex number, otherwise + * we print "%p" to indicate that we don't handle "%p". + */ + case 'p': + ui_num = (u_wide_int) va_arg(ap, char *); + + if (sizeof(char *) <= sizeof(u_wide_int)) + s = ap_php_conv_p2(ui_num, 4, 'x', + &num_buf[NUM_BUF_SIZE], &s_len); + else { + s = "%p"; + s_len = 2; + } + pad_char = ' '; + break; + + + case NUL: + /* + * The last character of the format string was %. + * We ignore it. + */ + continue; + + + /* + * The default case is for unrecognized %'s. + * We print % to help the user identify what + * option is not understood. + * This is also useful in case the user wants to pass + * the output of format_converter to another function + * that understands some other % (like syslog). + * Note that we can't point s inside fmt because the + * unknown could be preceded by width etc. + */ + default: + char_buf[0] = '%'; + char_buf[1] = *fmt; + s = char_buf; + s_len = 2; + pad_char = ' '; + break; + } + + if (prefix_char != NUL) { + *--s = prefix_char; + s_len++; + } + if (adjust_width && adjust == RIGHT && min_width > s_len) { + if (pad_char == '0' && prefix_char != NUL) { + INS_CHAR(*s, sp, bep, cc) + s++; + s_len--; + min_width--; + } + PAD(min_width, s_len, pad_char); + } + /* + * Print the string s. + */ + for (i = s_len; i != 0; i--) { + INS_CHAR(*s, sp, bep, cc); + s++; + } + + if (adjust_width && adjust == LEFT && min_width > s_len) + PAD(min_width, s_len, pad_char); + } + fmt++; + } + odp->nextb = sp; + return (cc); +} + + +/* + * This is the general purpose conversion function. + */ +static void strx_printv(int *ccp, char *buf, size_t len, const char *format, + va_list ap) +{ + buffy od; + int cc; + + /* + * First initialize the descriptor + * Notice that if no length is given, we initialize buf_end to the + * highest possible address. + */ + if (len == 0) { + od.buf_end = (char *) ~0; + od.nextb = (char *) ~0; + } else { + od.buf_end = &buf[len-1]; + od.nextb = buf; + } + + /* + * Do the conversion + */ + cc = format_converter(&od, format, ap); + if (len != 0 && od.nextb <= od.buf_end) + *(od.nextb) = '\0'; + if (ccp) + *ccp = cc; +} + + +int ap_php_snprintf(char *buf, size_t len, const char *format,...) +{ + int cc; + va_list ap; + + va_start(ap, format); + strx_printv(&cc, buf, len, format, ap); + va_end(ap); + return (cc); +} + + +int ap_php_vsnprintf(char *buf, size_t len, const char *format, va_list ap) +{ + int cc; + + strx_printv(&cc, buf, len, format, ap); + return (cc); +} + +#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 --git a/config.m4 b/config.m4 new file mode 100644 index 0000000..d5e52e2 --- /dev/null +++ b/config.m4 @@ -0,0 +1,9 @@ +dnl $Id: config.m4,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ +dnl config.m4 for extension suhosin + +PHP_ARG_ENABLE(suhosin, whether to enable suhosin support, +[ --enable-suhosin Enable suhosin support]) + +if test "$PHP_SUHOSIN" != "no"; then + PHP_NEW_EXTENSION(suhosin, suhosin.c crypt.c crypt_blowfish.c sha256.c memory_limit.c treat_data.c ifilter.c post_handler.c ufilter.c rfc1867.c log.c header.c execute.c ex_imp.c session.c aes.c compat_snprintf.c, $ext_shared) +fi diff --git a/config.w32 b/config.w32 new file mode 100644 index 0000000..bd0e169 --- /dev/null +++ b/config.w32 @@ -0,0 +1,11 @@ +// $Id: config.w32,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ +// vim:ft=javascript + +ARG_ENABLE("suhosin", "whether to enable suhosin support", "yes"); + +if (PHP_SUHOSIN == "yes") { + EXTENSION("suhosin", "suhosin.c crypt.c crypt_blowfish.c sha256.c memory_limit.c treat_data.c ifilter.c post_handler.c ufilter.c rfc1867.c log.c header.c execute.c ex_imp.c session.c aes.c"); + if (PHP_SUHOSIN_SHARED) { + ADD_SOURCES(configure_module_dirname, "crypt_win32.c crypt_md5.c", "suhosin"); + } +} diff --git a/crypt.c b/crypt.c new file mode 100644 index 0000000..72a34c8 --- /dev/null +++ b/crypt.c @@ -0,0 +1,214 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: crypt.c,v 1.2 2008-01-04 11:23:47 sesser Exp $ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "php_suhosin.h" + + +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_CRYPT_H +#include +#endif +#if TM_IN_SYS_TIME +#include +#else +#include +#endif +#if HAVE_STRING_H +#include +#else +#include +#endif + +#ifdef PHP_WIN32 +#include +extern char *crypt(char *__key, char *__salt); +#endif + +#include "ext/standard/php_lcg.h" +#include "ext/standard/php_crypt.h" +#include "ext/standard/php_rand.h" + + +#define PHP_CRYPT_RAND php_rand(TSRMLS_C) + +#define BLOWFISH_SALT_LEN 60 + +#ifdef ZTS +static MUTEX_T suhosin_crypt_mutex; +#endif + +static int CRYPT_MD5 = 0; + +char *suhosin_crypt_blowfish_rn(char *key, char *setting, char *output, int size); +char *suhosin_crypt_gensalt_blowfish_rn(unsigned long count, char *input, int size, char *output, int output_size); + +static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static void php_to64(char *s, long v, int n) +{ + while (--n >= 0) { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } +} + +/* {{{ proto string crypt(string str [, string salt]) + Encrypt a string */ +static PHP_FUNCTION(suhosin_crypt) +{ + char salt[BLOWFISH_SALT_LEN+1]; + char *str, *salt_in = NULL; + int str_len, salt_in_len; + + salt[0]=salt[BLOWFISH_SALT_LEN]='\0'; + /* This will produce suitable results if people depend on DES-encryption + available (passing always 2-character salt). At least for glibc6.1 */ + memset(&salt[1], '$', BLOWFISH_SALT_LEN-1); + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, + &salt_in, &salt_in_len) == FAILURE) { + return; + } + + if (salt_in) { + memcpy(salt, salt_in, MIN(BLOWFISH_SALT_LEN, salt_in_len)); + } + + /* The automatic salt generation only covers standard DES and md5-crypt */ + if(!*salt) { + if (CRYPT_MD5) { + strcpy(salt, "$1$"); + php_to64(&salt[3], PHP_CRYPT_RAND, 4); + php_to64(&salt[7], PHP_CRYPT_RAND, 4); + strcpy(&salt[11], "$"); + } else { + php_to64(&salt[0], PHP_CRYPT_RAND, 2); + salt[2] = '\0'; + } + } + + 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[BLOWFISH_SALT_LEN+1]; + + output[0] = 0; + suhosin_crypt_blowfish_rn(str, salt, output, sizeof(output)); + RETVAL_STRING(output, 1); + + } else { +#ifdef ZTS + tsrm_mutex_lock(suhosin_crypt_mutex); +#endif + RETVAL_STRING(crypt(str, salt), 1); +#ifdef ZTS + tsrm_mutex_unlock(suhosin_crypt_mutex); +#endif + } +} +/* }}} */ + + +/* {{{ suhosin_crypt_functions[] + */ +static function_entry suhosin_crypt_functions[] = { + PHP_NAMED_FE(crypt, PHP_FN(suhosin_crypt), NULL) + {NULL, NULL, NULL} +}; +/* }}} */ + + +void suhosin_hook_crypt() +{ + zend_constant *c; + TSRMLS_FETCH(); + + /* check if we have MD5 support */ + if (zend_hash_find(EG(zend_constants), "CRYPT_MD5", sizeof("CRYPT_MD5"), (void **) &c) == SUCCESS) { + if (c->value.type == IS_LONG && c->value.value.lval > 0) { + CRYPT_MD5 = 1; + } + } + + /* check if we already have blowfish support */ + if (zend_hash_find(EG(zend_constants), "CRYPT_BLOWFISH", sizeof("CRYPT_BLOWFISH"), (void **) &c) == FAILURE) { + + /* should we just bailout when this constant is not known at all? */ + return; + } + + if (c->value.type == IS_LONG && c->value.value.lval > 0) { + + /* blowfish support already installed */ + return; + } + + /* mark blowfish as supported */ + c->value.type = IS_LONG; + c->value.value.lval = 1; + + /* now fix the CRYPT_SALT_LENGTH constant */ + if (zend_hash_find(EG(zend_constants), "CRYPT_SALT_LENGTH", sizeof("CRYPT_SALT_LENGTH"), (void **) &c) == SUCCESS) { + c->value.type = IS_LONG; + c->value.value.lval = BLOWFISH_SALT_LEN; + } +#ifdef ZTS + suhosin_crypt_mutex = tsrm_mutex_alloc(); +#endif + + /* replace the crypt() function */ + zend_hash_del(CG(function_table), "crypt", sizeof("crypt")); +#ifndef ZEND_ENGINE_2 + zend_register_functions(suhosin_crypt_functions, NULL, MODULE_PERSISTENT TSRMLS_CC); +#else + zend_register_functions(NULL, suhosin_crypt_functions, NULL, MODULE_PERSISTENT TSRMLS_CC); +#endif + + + + +} + + +/* + * 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 --git a/crypt_blowfish.c b/crypt_blowfish.c new file mode 100644 index 0000000..cdc3ac5 --- /dev/null +++ b/crypt_blowfish.c @@ -0,0 +1,751 @@ +/* + $Id: crypt_blowfish.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ +*/ +/* + * 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 *suhosin_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 *suhosin_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 --git a/crypt_md5.c b/crypt_md5.c new file mode 100644 index 0000000..14aeb79 --- /dev/null +++ b/crypt_md5.c @@ -0,0 +1,163 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2006 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: Edin Kadribasic | + +----------------------------------------------------------------------+ + */ + +/* $Id: crypt_md5.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ */ + +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * from FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp + * via OpenBSD: md5crypt.c,v 1.9 1997/07/23 20:58:27 kstailey Exp + * via NetBSD: md5crypt.c,v 1.4.2.1 2002/01/22 19:31:59 he Exp + * + */ + +#include "php.h" +#include "ext/standard/md5.h" +#include "crypt_md5.h" + +static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +static void to64(char *, php_uint32, int); + +static void +to64(char *s, php_uint32 v, int n) +{ + + while (--n >= 0) { + *s++ = itoa64[v & 0x3f]; + v >>= 6; + } +} + +/* + * MD5 password encryption. + */ +char * +md5_crypt(const char *pw, const char *salt) +{ + static char passwd[120], *p; + const char *sp, *ep; + unsigned char final[16]; + unsigned int i, sl, pwl; + PHP_MD5_CTX ctx, ctx1; + php_uint32 l; + int pl; + + pwl = strlen(pw); + + /* Refine the salt first */ + sp = salt; + + /* If it starts with the magic string, then skip that */ + if (strncmp(sp, MD5_MAGIC, MD5_MAGIC_LEN) == 0) + sp += MD5_MAGIC_LEN; + + /* It stops at the first '$', max 8 chars */ + for (ep = sp; *ep != '\0' && *ep != '$' && ep < (sp + 8); ep++) + continue; + + /* get the length of the true salt */ + sl = ep - sp; + + PHP_MD5Init(&ctx); + + /* The password first, since that is what is most unknown */ + PHP_MD5Update(&ctx, (const unsigned char *)pw, pwl); + + /* Then our magic string */ + PHP_MD5Update(&ctx, (const unsigned char *)MD5_MAGIC, MD5_MAGIC_LEN); + + /* Then the raw salt */ + PHP_MD5Update(&ctx, (const unsigned char *)sp, sl); + + /* Then just as many characters of the MD5(pw,salt,pw) */ + PHP_MD5Init(&ctx1); + PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl); + PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl); + PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl); + PHP_MD5Final(final, &ctx1); + + for (pl = pwl; pl > 0; pl -= 16) + PHP_MD5Update(&ctx, final, (unsigned int)(pl > 16 ? 16 : pl)); + + /* Don't leave anything around in vm they could use. */ + memset(final, 0, sizeof(final)); + + /* Then something really weird... */ + for (i = pwl; i != 0; i >>= 1) + if ((i & 1) != 0) + PHP_MD5Update(&ctx, final, 1); + else + PHP_MD5Update(&ctx, (const unsigned char *)pw, 1); + + /* Now make the output string */ + memcpy(passwd, MD5_MAGIC, MD5_MAGIC_LEN); + strlcpy(passwd + MD5_MAGIC_LEN, sp, sl + 1); + strcat(passwd, "$"); + + PHP_MD5Final(final, &ctx); + + /* + * And now, just to make sure things don't run too fast. On a 60 MHz + * Pentium this takes 34 msec, so you would need 30 seconds to build + * a 1000 entry dictionary... + */ + for (i = 0; i < 1000; i++) { + PHP_MD5Init(&ctx1); + + if ((i & 1) != 0) + PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl); + else + PHP_MD5Update(&ctx1, final, 16); + + if ((i % 3) != 0) + PHP_MD5Update(&ctx1, (const unsigned char *)sp, sl); + + if ((i % 7) != 0) + PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl); + + if ((i & 1) != 0) + PHP_MD5Update(&ctx1, final, 16); + else + PHP_MD5Update(&ctx1, (const unsigned char *)pw, pwl); + + PHP_MD5Final(final, &ctx1); + } + + p = passwd + sl + MD5_MAGIC_LEN + 1; + + l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4; + l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4; + l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4; + l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4; + l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4; + l = final[11] ; to64(p,l,2); p += 2; + *p = '\0'; + + /* Don't leave anything around in vm they could use. */ + memset(final, 0, sizeof(final)); + return (passwd); +} + diff --git a/crypt_md5.h b/crypt_md5.h new file mode 100644 index 0000000..56f03a2 --- /dev/null +++ b/crypt_md5.h @@ -0,0 +1,37 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2006 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: Edin Kadribasic | + +----------------------------------------------------------------------+ + */ + +/* $Id: crypt_md5.h,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ */ +#ifndef _MD5CRYPT_H_ +#define _MD5CRYPT_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define MD5_MAGIC "$1$" +#define MD5_MAGIC_LEN 3 + +char *md5_crypt(const char *pw, const char *salt); + +#ifdef __cplusplus +} +#endif + +#endif /* _MD5CRYPT_H_ */ \ No newline at end of file diff --git a/crypt_win32.c b/crypt_win32.c new file mode 100644 index 0000000..c1afe00 --- /dev/null +++ b/crypt_win32.c @@ -0,0 +1,355 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2006 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: crypt_win32.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ */ + +/* This code is distributed under the PHP license with permission from + the author Jochen Obalek */ + +/* encrypt.c - providing 56 bit DES encryption + Copyright (C) 1991 Jochen Obalek + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include "crypt_md5.h" + +#define BS 64 +#define BS2 32 +#define KS 48 +#define KS2 24 +#define IS 56 +#define IS2 28 + +static char schluessel[16][KS]; + + +static char PC1[] = +{ + 56, 48, 40, 32, 24, 16, 8, 0, + 57, 49, 41, 33, 25, 17, 9, 1, + 58, 50, 42, 34, 26, 18, 10, 2, + 59, 51, 43, 35, + 62, 54, 46, 38, 30, 22, 14, 6, + 61, 53, 45, 37, 29, 21, 13, 5, + 60, 52, 44, 36, 28, 20, 12, 4, + 27, 19, 11, 3 +}; + + +static char PC2[] = +{ + 13, 16, 10, 23, 0, 4, 2, 27, + 14, 5, 20, 9, 22, 18, 11, 3, + 25, 7, 15, 6, 26, 19, 12, 1, + 40, 51, 30, 36, 46, 54, 29, 39, + 50, 44, 32, 47, 43, 48, 38, 55, + 33, 52, 45, 41, 49, 35, 28, 31 +}; + + +static char IP[] = +{ + 57, 49, 41, 33, 25, 17, 9, 1, + 59, 51, 43, 35, 27, 19, 11, 3, + 61, 53, 45, 37, 29, 21, 13, 5, + 63, 55, 47, 39, 31, 23, 15, 7, + 56, 48, 40, 32, 24, 16, 8, 0, + 58, 50, 42, 34, 26, 18, 10, 2, + 60, 52, 44, 36, 28, 20, 12, 4, + 62, 54, 46, 38, 30, 22, 14, 6 +}; + + +static char EP[] = +{ + 7, 39, 15, 47, 23, 55, 31, 63, + 6, 38, 14, 46, 22, 54, 30, 62, + 5, 37, 13, 45, 21, 53, 29, 61, + 4, 36, 12, 44, 20, 52, 28, 60, + 3, 35, 11, 43, 19, 51, 27, 59, + 2, 34, 10, 42, 18, 50, 26, 58, + 1, 33, 9, 41, 17, 49, 25, 57, + 0, 32, 8, 40, 16, 48, 24, 56 +}; + + +static char E0[] = +{ + 31, 0, 1, 2, 3, 4, 3, 4, + 5, 6, 7, 8, 7, 8, 9, 10, + 11, 12, 11, 12, 13, 14, 15, 16, + 15, 16, 17, 18, 19, 20, 19, 20, + 21, 22, 23, 24, 23, 24, 25, 26, + 27, 28, 27, 28, 29, 30, 31, 0 +}; + + +static char E[KS]; + + +static char PERM[] = +{ + 15, 6, 19, 20, 28, 11, 27, 16, + 0, 14, 22, 25, 4, 17, 30, 9, + 1, 7, 23, 13, 31, 26, 2, 8, + 18, 12, 29, 5, 21, 10, 3, 24 +}; + + +static char S_BOX[][64] = +{ + { + 14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1, + 3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8, + 4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7, + 15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13 + }, + { + 15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14, + 9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5, + 0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2, + 5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9 + }, + { + 10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10, + 1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1, + 13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7, + 11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12 + }, + { + 7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3, + 1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9, + 10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8, + 15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14 + }, + { + 2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1, + 8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6, + 4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13, + 15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3 + }, + { + 12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5, + 0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8, + 9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10, + 7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13 + }, + { + 4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10, + 3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6, + 1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7, + 10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12 + }, + { + 13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4, + 10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2, + 7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13, + 0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11 + } +}; + +static void +perm (a, e, pc, n) + register char *a, *e; + register char *pc; + int n; +{ + for (; n--; pc++, a++) + *a = e[*pc]; +} + +static void +crypt_main (nachr_l, nachr_r, schl) + register char *nachr_l, *nachr_r; + register char *schl; +{ + char tmp[KS]; + register int sbval; + register char *tp = tmp; + register char *e = E; + register int i, j; + + for (i = 0; i < 8; i++) + { + for (j = 0, sbval = 0; j < 6; j++) + sbval = (sbval << 1) | (nachr_r[*e++] ^ *schl++); + sbval = S_BOX[i][sbval]; + for (tp += 4, j = 4; j--; sbval >>= 1) + *--tp = sbval & 1; + tp += 4; + } + + e = PERM; + for (i = 0; i < BS2; i++) + *nachr_l++ ^= tmp[*e++]; +} + +void +encrypt (char *nachr, int decr) +{ + char (*schl)[KS] = decr ? schluessel + 15 : schluessel; + char tmp[BS]; + int i; + + perm (tmp, nachr, IP, BS); + + for (i = 8; i--;) + { + crypt_main (tmp, tmp + BS2, *schl); + if (decr) + schl--; + else + schl++; + crypt_main (tmp + BS2, tmp, *schl); + if (decr) + schl--; + else + schl++; + } + + perm (nachr, tmp, EP, BS); +} + +void +setkey (char *schl) +{ + char tmp1[IS]; + register unsigned int ls = 0x7efc; + register int i, j, k; + register int shval = 0; + register char *akt_schl; + + memcpy (E, E0, KS); + perm (tmp1, schl, PC1, IS); + + for (i = 0; i < 16; i++) + { + shval += 1 + (ls & 1); + akt_schl = schluessel[i]; + for (j = 0; j < KS; j++) + { + if ((k = PC2[j]) >= IS2) + { + if ((k += shval) >= IS) + k = (k - IS2) % IS2 + IS2; + } + else if ((k += shval) >= IS2) + k %= IS2; + *akt_schl++ = tmp1[k]; + } + ls >>= 1; + } +} + +char * +des_crypt (const char *wort, const char *salt) +{ + static char retkey[14]; + char key[BS + 2]; + char *k; + int tmp, keybyte; + int i, j; + + memset (key, 0, BS + 2); + + for (k = key, i = 0; i < BS; i++) + { + if (!(keybyte = *wort++)) + break; + k += 7; + for (j = 0; j < 7; j++, i++) + { + *--k = keybyte & 1; + keybyte >>= 1; + } + k += 8; + } + + setkey (key); + memset (key, 0, BS + 2); + + for (k = E, i = 0; i < 2; i++) + { + retkey[i] = keybyte = *salt++; + if (keybyte > 'Z') + keybyte -= 'a' - 'Z' - 1; + if (keybyte > '9') + keybyte -= 'A' - '9' - 1; + keybyte -= '.'; + + for (j = 0; j < 6; j++, keybyte >>= 1, k++) + { + if (!(keybyte & 1)) + continue; + tmp = *k; + *k = k[24]; + k[24] = tmp; + } + } + + for (i = 0; i < 25; i++) + encrypt (key, 0); + + for (k = key, i = 0; i < 11; i++) + { + for (j = keybyte = 0; j < 6; j++) + { + keybyte <<= 1; + keybyte |= *k++; + } + + keybyte += '.'; + if (keybyte > '9') + keybyte += 'A' - '9' - 1; + if (keybyte > 'Z') + keybyte += 'a' - 'Z' - 1; + retkey[i + 2] = keybyte; + } + + retkey[i + 2] = 0; + + if (!retkey[1]) + retkey[1] = *retkey; + + return retkey; +} + +char * +crypt (const char *pw, const char *salt) +{ + if (strlen(salt)>MD5_MAGIC_LEN && strncmp(salt, MD5_MAGIC, MD5_MAGIC_LEN)==0) { + return md5_crypt(pw, salt); + } else { + return des_crypt(pw, salt); + } +} diff --git a/crypt_win32.h b/crypt_win32.h new file mode 100644 index 0000000..9dd5ffa --- /dev/null +++ b/crypt_win32.h @@ -0,0 +1,60 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2006 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: crypt_win32.h,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ */ + +/* This code is distributed under the PHP license with permission from + the author Jochen Obalek */ + +/* encrypt.h - API to 56 bit DES encryption via calls + encrypt(3), setkey(3) and crypt(3) + Copyright (C) 1991 Jochen Obalek + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef _ENCRYPT_H_ +#define _ENCRYPT_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include <_ansi.h> + +void _EXFUN(encrypt, (char *block, int edflag)); +void _EXFUN(setkey, (char *key)); +char * _EXFUN(crypt, (const char *key, const char *salt)); + +#ifdef __cplusplus +} +#endif + +#endif /* _ENCRYPT_H_ */ diff --git a/ex_imp.c b/ex_imp.c new file mode 100644 index 0000000..f602860 --- /dev/null +++ b/ex_imp.c @@ -0,0 +1,450 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: ex_imp.c,v 1.2 2008-01-04 11:23:47 sesser Exp $ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "php_suhosin.h" +#include "ext/standard/php_smart_str.h" + + +#define EXTR_OVERWRITE 0 +#define EXTR_SKIP 1 +#define EXTR_PREFIX_SAME 2 +#define EXTR_PREFIX_ALL 3 +#define EXTR_PREFIX_INVALID 4 +#define EXTR_PREFIX_IF_EXISTS 5 +#define EXTR_IF_EXISTS 6 + +#define EXTR_REFS 0x100 + + +static int php_valid_var_name(char *var_name) +{ + int len, i; + + if (!var_name) + return 0; + + len = strlen(var_name); + + if (!isalpha((int)((unsigned char *)var_name)[0]) && var_name[0] != '_') + return 0; + + if (len > 1) { + for (i=1; i EXTR_SKIP && extract_type <= EXTR_PREFIX_IF_EXISTS) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Prefix expected to be specified"); + return; + } + break; + + case 3: + if (zend_get_parameters_ex(3, &var_array, &z_extract_type, &prefix) == FAILURE) { + WRONG_PARAM_COUNT; + } + convert_to_long_ex(z_extract_type); + extract_type = Z_LVAL_PP(z_extract_type); + extract_refs = (extract_type & EXTR_REFS); + extract_type &= 0xff; + convert_to_string_ex(prefix); + break; + + default: + WRONG_PARAM_COUNT; + break; + } + +#if PHP_VERSION_ID >= 50300 + if (!EG(active_symbol_table)) { + zend_rebuild_symbol_table(TSRMLS_C); + } +#endif + + if (extract_type < EXTR_OVERWRITE || extract_type > EXTR_IF_EXISTS) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown extract type"); + return; + } + + if (Z_TYPE_PP(var_array) != IS_ARRAY) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "First argument should be an array"); + return; + } + + zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(var_array), &pos); + while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(var_array), (void **)&entry, &pos) == SUCCESS) { + key_type = zend_hash_get_current_key_ex(Z_ARRVAL_PP(var_array), &var_name, &var_name_len, &num_key, 0, &pos); + var_exists = 0; + + if (key_type == HASH_KEY_IS_STRING) { + var_name_len--; + var_exists = zend_hash_exists(EG(active_symbol_table), var_name, var_name_len + 1); + } else if (extract_type == EXTR_PREFIX_ALL || extract_type == EXTR_PREFIX_INVALID) { + smart_str_appendl(&final_name, Z_STRVAL_PP(prefix), Z_STRLEN_PP(prefix)); + smart_str_appendc(&final_name, '_'); + smart_str_append_long(&final_name, num_key); + } else { + zend_hash_move_forward_ex(Z_ARRVAL_PP(var_array), &pos); + continue; + } + + switch (extract_type) { + case EXTR_IF_EXISTS: + if (!var_exists) break; + /* break omitted intentionally */ + + case EXTR_OVERWRITE: + /* GLOBALS protection */ + if (var_exists && !strcmp(var_name, "GLOBALS")) { + break; + } + smart_str_appendl(&final_name, var_name, var_name_len); + break; + + case EXTR_PREFIX_IF_EXISTS: + if (var_exists) { + smart_str_appendl(&final_name, Z_STRVAL_PP(prefix), Z_STRLEN_PP(prefix)); + smart_str_appendc(&final_name, '_'); + smart_str_appendl(&final_name, var_name, var_name_len); + } + break; + + case EXTR_PREFIX_SAME: + if (!var_exists) + smart_str_appendl(&final_name, var_name, var_name_len); + /* break omitted intentionally */ + + case EXTR_PREFIX_ALL: + if (final_name.len == 0 && var_name_len != 0) { + smart_str_appendl(&final_name, Z_STRVAL_PP(prefix), Z_STRLEN_PP(prefix)); + smart_str_appendc(&final_name, '_'); + smart_str_appendl(&final_name, var_name, var_name_len); + } + break; + + case EXTR_PREFIX_INVALID: + if (final_name.len == 0) { + if (!php_valid_var_name(var_name)) { + smart_str_appendl(&final_name, Z_STRVAL_PP(prefix), Z_STRLEN_PP(prefix)); + smart_str_appendc(&final_name, '_'); + smart_str_appendl(&final_name, var_name, var_name_len); + } else + smart_str_appendl(&final_name, var_name, var_name_len); + } + break; + + default: + if (!var_exists) + smart_str_appendl(&final_name, var_name, var_name_len); + break; + } + + if (final_name.len) { + smart_str_0(&final_name); + if (php_valid_var_name(final_name.c)) { + if (extract_refs) { + zval **orig_var; + + if (zend_hash_find(EG(active_symbol_table), final_name.c, final_name.len+1, (void **) &orig_var) == SUCCESS) { + SEPARATE_ZVAL_TO_MAKE_IS_REF(entry); + zval_add_ref(entry); + + zval_ptr_dtor(orig_var); + + *orig_var = *entry; + } else { + if (Z_REFCOUNT_PP(var_array) > 1) { + SEPARATE_ZVAL_TO_MAKE_IS_REF(entry); + } else { + Z_SET_ISREF_PP(entry); + } + zval_add_ref(entry); + zend_hash_update(EG(active_symbol_table), final_name.c, final_name.len+1, (void **) entry, sizeof(zval *), NULL); + } + } else { + MAKE_STD_ZVAL(data); + *data = **entry; + zval_copy_ctor(data); + + ZEND_SET_SYMBOL_WITH_LENGTH(EG(active_symbol_table), final_name.c, final_name.len+1, data, 1, 0); + } + + count++; + } + final_name.len = 0; + } + + zend_hash_move_forward_ex(Z_ARRVAL_PP(var_array), &pos); + } + + smart_str_free(&final_name); + + RETURN_LONG(count); +} +/* }}} */ + + +static int copy_request_variable(void *pDest, int num_args, va_list args, zend_hash_key *hash_key) +{ + char *prefix, *new_key; + uint prefix_len, new_key_len; + zval **var = (zval **) pDest; + TSRMLS_FETCH(); + + if (num_args != 2) { + return 0; + } + + prefix = va_arg(args, char *); + prefix_len = va_arg(args, uint); + + if (!prefix_len) { + if (!hash_key->nKeyLength) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Numeric key detected - possible security hazard."); + return 0; + } else if (!strcmp(hash_key->arKey, "GLOBALS")) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attempted GLOBALS variable overwrite."); + return 0; + } + } + + if (hash_key->nKeyLength) { + new_key_len = prefix_len + hash_key->nKeyLength; + new_key = (char *) emalloc(new_key_len); + + memcpy(new_key, prefix, prefix_len); + memcpy(new_key+prefix_len, hash_key->arKey, hash_key->nKeyLength); + } else { + new_key_len = spprintf(&new_key, 0, "%s%ld", prefix, hash_key->h); + } + + 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; + } + +#if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0) + zend_delete_global_variable(new_key, new_key_len-1 TSRMLS_CC); +#else + zend_hash_del(&EG(symbol_table), new_key, new_key_len-1); +#endif + ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), new_key, new_key_len, *var, Z_REFCOUNT_PP(var)+1, 0); + + efree(new_key); + return 0; +} + +/* {{{ proto bool import_request_variables(string types [, string prefix]) + Import GET/POST/Cookie variables into the global scope */ +PHP_FUNCTION(suhosin_import_request_variables) +{ + zval **z_types, **z_prefix; + char *types, *prefix; + uint prefix_len; + char *p; + + switch (ZEND_NUM_ARGS()) { + + case 1: + if (zend_get_parameters_ex(1, &z_types) == FAILURE) { + RETURN_FALSE; + } + prefix = ""; + prefix_len = 0; + break; + + case 2: + if (zend_get_parameters_ex(2, &z_types, &z_prefix) == FAILURE) { + RETURN_FALSE; + } + convert_to_string_ex(z_prefix); + prefix = Z_STRVAL_PP(z_prefix); + prefix_len = Z_STRLEN_PP(z_prefix); + break; + + default: + ZEND_WRONG_PARAM_COUNT(); + } + + if (prefix_len == 0) { + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "No prefix specified - possible security hazard"); + } + + convert_to_string_ex(z_types); + types = Z_STRVAL_PP(z_types); + + for (p = types; p && *p; p++) { + switch (*p) { + + case 'g': + case 'G': + zend_hash_apply_with_arguments(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET]), (apply_func_args_t) copy_request_variable, 2, prefix, prefix_len); + break; + + case 'p': + case 'P': + zend_hash_apply_with_arguments(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_POST]), (apply_func_args_t) copy_request_variable, 2, prefix, prefix_len); + zend_hash_apply_with_arguments(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_FILES]), (apply_func_args_t) copy_request_variable, 2, prefix, prefix_len); + break; + + case 'c': + case 'C': + zend_hash_apply_with_arguments(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]), (apply_func_args_t) copy_request_variable, 2, prefix, prefix_len); + break; + } + } +} +/* }}} */ + + +/* {{{ suhosin_ex_imp_functions[] + */ +function_entry suhosin_ex_imp_functions[] = { + PHP_NAMED_FE(extract, PHP_FN(suhosin_extract), NULL) + PHP_NAMED_FE(import_request_variables, PHP_FN(suhosin_import_request_variables), NULL) + {NULL, NULL, NULL} +}; +/* }}} */ + + +void suhosin_hook_ex_imp() +{ + TSRMLS_FETCH(); + + /* replace the extract and import_request_variables functions */ + zend_hash_del(CG(function_table), "extract", sizeof("extract")); + zend_hash_del(CG(function_table), "import_request_variables", sizeof("import_request_variables")); +#ifndef ZEND_ENGINE_2 + zend_register_functions(suhosin_ex_imp_functions, NULL, MODULE_PERSISTENT TSRMLS_CC); +#else + zend_register_functions(NULL, suhosin_ex_imp_functions, NULL, MODULE_PERSISTENT TSRMLS_CC); +#endif + + + + +} + + +/* + * 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 --git a/execute.c b/execute.c new file mode 100644 index 0000000..aaa672b --- /dev/null +++ b/execute.c @@ -0,0 +1,1750 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: execute.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "zend_hash.h" +#include "zend_extensions.h" +#include "ext/standard/info.h" +#include "ext/standard/php_rand.h" +#include "php_suhosin.h" +#include "zend_compile.h" +#include "zend_llist.h" +#include "SAPI.h" + +#include "sha256.h" + + +static void (*old_execute)(zend_op_array *op_array TSRMLS_DC); +static void suhosin_execute(zend_op_array *op_array TSRMLS_DC); +static void (*old_execute_ZO)(zend_op_array *op_array, long dummy TSRMLS_DC); +static void suhosin_execute_ZO(zend_op_array *op_array, long dummy TSRMLS_DC); +static void *(*zo_set_oe_ex)(void *ptr) = NULL; + +/*STATIC zend_op_array* (*old_compile_file)(zend_file_handle* file_handle, int type TSRMLS_DC); + STATIC zend_op_array* suhosin_compile_file(zend_file_handle*, int TSRMLS_DC);*/ + +static void suhosin_execute_internal(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC); +static void (*old_execute_internal)(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC); + +extern zend_extension suhosin_zend_extension_entry; + +/* {{{ suhosin_strcasestr */ +static char *suhosin_strcasestr(char *haystack, char *needle) +{ + unsigned char *t, *h, *n; + h = (unsigned char *) haystack; +conts: + while (*h) { + n = (unsigned char *) needle; + if (toupper(*h++) == toupper(*n++)) { + for (t=h; *n; t++, n++) { + if (toupper(*t) != toupper(*n)) goto conts; + } + return ((char*)h-1); + } + } + + return (NULL); +} +/* }}} */ + + +#define SUHOSIN_CODE_TYPE_UNKNOWN 0 +#define SUHOSIN_CODE_TYPE_COMMANDLINE 1 +#define SUHOSIN_CODE_TYPE_EVAL 2 +#define SUHOSIN_CODE_TYPE_REGEXP 3 +#define SUHOSIN_CODE_TYPE_ASSERT 4 +#define SUHOSIN_CODE_TYPE_CFUNC 5 +#define SUHOSIN_CODE_TYPE_SUHOSIN 6 +#define SUHOSIN_CODE_TYPE_UPLOADED 7 +#define SUHOSIN_CODE_TYPE_0FILE 8 +#define SUHOSIN_CODE_TYPE_BLACKURL 9 +#define SUHOSIN_CODE_TYPE_BADURL 10 +#define SUHOSIN_CODE_TYPE_GOODFILE 11 +#define SUHOSIN_CODE_TYPE_BADFILE 12 +#define SUHOSIN_CODE_TYPE_LONGNAME 13 +#define SUHOSIN_CODE_TYPE_MANYDOTS 14 +#define SUHOSIN_CODE_TYPE_WRITABLE 15 + +static int suhosin_check_filename(char *s, int len TSRMLS_DC) +{ + char fname[MAXPATHLEN+1]; + char *t, *h, *h2, *index, *e; + int tlen, i, count=0; + uint indexlen; + ulong numindex; + zend_bool isOk; + + /* check if filename is too long */ + if (len > MAXPATHLEN) { + return SUHOSIN_CODE_TYPE_LONGNAME; + } + memcpy(fname, s, len); + fname[len] = 0; + s = (char *)&fname; + e = s + len; + + /* check if ASCIIZ attack -> not working yet (and cannot work in PHP4 + ZO) */ + if (len != strlen(s)) { + return SUHOSIN_CODE_TYPE_0FILE; + } + + /* disallow uploaded files */ + if (SG(rfc1867_uploaded_files)) { + if (zend_hash_exists(SG(rfc1867_uploaded_files), (char *) s, e-s+1)) { + return SUHOSIN_CODE_TYPE_UPLOADED; + } + } + + /* count number of directory traversals */ + for (i=0; i < len-3; i++) { + if (s[i] == '.' && s[i+1] == '.' && (s[i+2] == '/' || s[i+2] == '\\')) { + count++; + i+=2; + } + } + if (SUHOSIN_G(executor_include_max_traversal) && SUHOSIN_G(executor_include_max_traversal)<=count) { + return SUHOSIN_CODE_TYPE_MANYDOTS; + } + +SDEBUG("xxx %08x %08x",SUHOSIN_G(include_whitelist),SUHOSIN_G(include_blacklist)); + /* no black or whitelist then disallow all */ + if (SUHOSIN_G(include_whitelist)==NULL && SUHOSIN_G(include_blacklist)==NULL) { + /* disallow all URLs */ + if (strstr(s, "://") != NULL || suhosin_strcasestr(s, "data:") != NULL) { + return SUHOSIN_CODE_TYPE_BADURL; + } + } else + /* whitelist is stronger than blacklist */ + if (SUHOSIN_G(include_whitelist)) { + + do { + isOk = 0; + + h = strstr(s, "://"); + h2 = suhosin_strcasestr(s, "data:"); + h2 = h2 == NULL ? NULL : h2 + 4; + t = h = (h == NULL) ? h2 : ( (h2 == NULL) ? h : ( (h < h2) ? h : h2 ) ); + if (h == NULL) break; + + while (t > s && (isalnum(t[-1]) || t[-1]=='_')) { + t--; + } + + tlen = e-t; + + zend_hash_internal_pointer_reset(SUHOSIN_G(include_whitelist)); + do { + int r = zend_hash_get_current_key_ex(SUHOSIN_G(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 (strncasecmp(t, index, indexlen-1)==0) { + isOk = 1; + break; + } + } + } + + zend_hash_move_forward(SUHOSIN_G(include_whitelist)); + } while (1); + + /* not found in whitelist */ + if (!isOk) { + return SUHOSIN_CODE_TYPE_BADURL; + } + + s = h + 1; + } while (1); + } else { + + do { + int tlen; + + h = strstr(s, "://"); + h2 = suhosin_strcasestr(s, "data:"); + h2 = h2 == NULL ? NULL : h2 + 4; + t = h = (h == NULL) ? h2 : ( (h2 == NULL) ? h : ( (h < h2) ? h : h2 ) ); + if (h == NULL) break; + + while (t > s && (isalnum(t[-1]) || t[-1]=='_')) { + t--; + } + + tlen = e-t; + + zend_hash_internal_pointer_reset(SUHOSIN_G(include_blacklist)); + do { + int r = zend_hash_get_current_key_ex(SUHOSIN_G(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 (strncasecmp(t, index, indexlen-1)==0) { + return SUHOSIN_CODE_TYPE_BLACKURL; + } + } + } + + zend_hash_move_forward(SUHOSIN_G(include_blacklist)); + } while (1); + + s = h + 1; + } while (1); + } + + /* disallow writable files */ + if (!SUHOSIN_G(executor_include_allow_writable_files)) { + /* protection against *REMOTE* attacks, potential + race condition of access() is irrelevant */ + if (access(s, W_OK) == 0) { + return SUHOSIN_CODE_TYPE_WRITABLE; + } + } + + return SUHOSIN_CODE_TYPE_GOODFILE; +} + + +#ifdef ZEND_ENGINE_2 +static int (*old_zend_stream_open)(const char *filename, zend_file_handle *fh TSRMLS_DC); +#else +static zend_bool (*old_zend_open)(const char *filename, zend_file_handle *fh); +#endif + +#ifdef ZEND_ENGINE_2 +static int suhosin_zend_stream_open(const char *filename, zend_file_handle *fh TSRMLS_DC) +{ + zend_execute_data *exd; +#else +static zend_bool suhosin_zend_open(const char *filename, zend_file_handle *fh) +{ + zend_execute_data *exd; + TSRMLS_FETCH(); +#endif + exd=EG(current_execute_data); + if (EG(in_execution) && (exd!=NULL) && (exd->opline != NULL) && (exd->opline->opcode == ZEND_INCLUDE_OR_EVAL)) { + int filetype = suhosin_check_filename((char *)filename, strlen(filename) TSRMLS_CC); + + switch (filetype) { + case SUHOSIN_CODE_TYPE_LONGNAME: + suhosin_log(S_INCLUDE, "Include filename ('%s') is too long", filename); + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_UPLOADED: + suhosin_log(S_INCLUDE, "Include filename is an uploaded file"); + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_0FILE: + suhosin_log(S_INCLUDE, "Include filename contains an ASCIIZ character"); + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_WRITABLE: + suhosin_log(S_INCLUDE, "Include filename ('%s') is writable by PHP process", filename); + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_BLACKURL: + suhosin_log(S_INCLUDE, "Include filename ('%s') is an URL that is forbidden by the blacklist", filename); + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_BADURL: + suhosin_log(S_INCLUDE, "Include filename ('%s') is an URL that is not allowed", filename); + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_MANYDOTS: + suhosin_log(S_INCLUDE, "Include filename ('%s') contains too many '../'", filename); + suhosin_bailout(TSRMLS_C); + break; + } + } +#ifdef ZEND_ENGINE_2 + return old_zend_stream_open(filename, fh TSRMLS_CC); +#else + return old_zend_open(filename, fh); +#endif +} + + +static int suhosin_detect_codetype(zend_op_array *op_array TSRMLS_DC) +{ + char *s; + int r; + + s = op_array->filename; + + /* eval, assert, create_function, preg_replace */ + if (op_array->type == ZEND_EVAL_CODE) { + + if (s == NULL) { + return SUHOSIN_CODE_TYPE_UNKNOWN; + } + + if (strstr(s, "eval()'d code") != NULL) { + return SUHOSIN_CODE_TYPE_EVAL; + } + + if (strstr(s, "regexp code") != NULL) { + return SUHOSIN_CODE_TYPE_REGEXP; + } + + if (strstr(s, "assert code") != NULL) { + return SUHOSIN_CODE_TYPE_ASSERT; + } + + if (strstr(s, "runtime-created function") != NULL) { + return SUHOSIN_CODE_TYPE_CFUNC; + } + + if (strstr(s, "Command line code") != NULL) { + return SUHOSIN_CODE_TYPE_COMMANDLINE; + } + + if (strstr(s, "suhosin internal code") != NULL) { + return SUHOSIN_CODE_TYPE_SUHOSIN; + } + + } else { + + r = suhosin_check_filename(s, strlen(s) TSRMLS_CC); +/* switch (r) { + case SUHOSIN_CODE_TYPE_GOODFILE: + break; + } */ + return r; + + } + + return SUHOSIN_CODE_TYPE_UNKNOWN; +} + +/* {{{ void suhosin_execute_ex(zend_op_array *op_array TSRMLS_DC) + * This function provides a hook for execution */ +static void suhosin_execute_ex(zend_op_array *op_array, int zo, long dummy TSRMLS_DC) +{ + zend_op_array *new_op_array; + int op_array_type, len; + char *fn; + zval cs; + zend_uint orig_code_type; + unsigned long *suhosin_flags = NULL; + + if (SUHOSIN_G(abort_request) && !SUHOSIN_G(simulation) && SUHOSIN_G(filter_action)) { + + char *action = SUHOSIN_G(filter_action); + long code = -1; + + SUHOSIN_G(abort_request) = 0; /* we do not want to endlessloop */ + + while (*action == ' ' || *action == '\t') action++; + + if (*action >= '0' && *action <= '9') { + char *end = action; + while (*end && *end != ',' && *end != ';') end++; + code = zend_atoi(action, end-action); + action = end; + } + + while (*action == ' ' || *action == '\t' || *action == ',' || *action == ';') action++; + + if (*action) { + + if (strncmp("http://", action, sizeof("http://")-1)==0) { + sapi_header_line ctr = {0}; + + if (code == -1) { + code = 302; + } + + ctr.line_len = spprintf(&ctr.line, 0, "Location: %s", action); + ctr.response_code = code; + sapi_header_op(SAPI_HEADER_REPLACE, &ctr TSRMLS_CC); + efree(ctr.line); + } else { + zend_file_handle file_handle; + zend_op_array *new_op_array; + zval *result = NULL; + + if (code == -1) { + code = 200; + } + +#ifdef ZEND_ENGINE_2 + if (zend_stream_open(action, &file_handle TSRMLS_CC) == SUCCESS) { +#else + if (zend_open(action, &file_handle) == SUCCESS && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) { + file_handle.filename = action; + file_handle.free_filename = 0; +#endif + if (!file_handle.opened_path) { + file_handle.opened_path = estrndup(action, strlen(action)); + } + new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC); + zend_destroy_file_handle(&file_handle TSRMLS_CC); + if (new_op_array) { + EG(return_value_ptr_ptr) = &result; + EG(active_op_array) = new_op_array; + zend_execute(new_op_array TSRMLS_CC); +#ifdef ZEND_ENGINE_2 + destroy_op_array(new_op_array TSRMLS_CC); +#else + destroy_op_array(new_op_array); +#endif + efree(new_op_array); +#ifdef ZEND_ENGINE_2 + if (!EG(exception)) +#endif + { + if (EG(return_value_ptr_ptr)) { + zval_ptr_dtor(EG(return_value_ptr_ptr)); + EG(return_value_ptr_ptr) = NULL; + } + } + } else { + code = 500; + } + } else { + code = 500; + } + } + } + + sapi_header_op(SAPI_HEADER_SET_STATUS, (void *)code TSRMLS_CC); + zend_bailout(); + } + + SDEBUG("%s %s", op_array->filename, op_array->function_name); + + SUHOSIN_G(execution_depth)++; + + if (SUHOSIN_G(max_execution_depth) && SUHOSIN_G(execution_depth) > SUHOSIN_G(max_execution_depth)) { + suhosin_log(S_EXECUTOR, "maximum execution depth reached - script terminated"); + suhosin_bailout(TSRMLS_C); + } + + fn = op_array->filename; + len = strlen(fn); + + orig_code_type = SUHOSIN_G(in_code_type); + if (op_array->type == ZEND_EVAL_CODE) { + SUHOSIN_G(in_code_type) = SUHOSIN_EVAL; + } else { + if (suhosin_zend_extension_entry.resource_number != -1) { + suhosin_flags = (unsigned long *) &op_array->reserved[suhosin_zend_extension_entry.resource_number]; + SDEBUG("suhosin flags: %08x", *suhosin_flags); + + if (*suhosin_flags & SUHOSIN_FLAG_CREATED_BY_EVAL) { + SUHOSIN_G(in_code_type) = SUHOSIN_EVAL; + } + if (*suhosin_flags & SUHOSIN_FLAG_NOT_EVALED_CODE) { + goto not_evaled_code; + } + } + + if (strstr(op_array->filename, "eval()'d code")) { + SUHOSIN_G(in_code_type) = SUHOSIN_EVAL; + } else { + if (suhosin_flags) { + *suhosin_flags |= SUHOSIN_FLAG_NOT_EVALED_CODE; + } + } + } +not_evaled_code: + SDEBUG("code type %u", SUHOSIN_G(in_code_type)); + if (op_array->function_name) { + goto continue_execution; + } + +/* if (SUHOSIN_G(deactivate)) { + goto continue_execution; + } +*/ + + op_array_type = suhosin_detect_codetype(op_array TSRMLS_CC); + + switch (op_array_type) { + case SUHOSIN_CODE_TYPE_EVAL: + if (SUHOSIN_G(executor_disable_eval)) { + suhosin_log(S_EXECUTOR, "use of eval is forbidden by configuration"); + if (!SUHOSIN_G(simulation)) { + zend_error(E_ERROR, "SUHOSIN - Use of eval is forbidden by configuration"); + } + } + break; + + case SUHOSIN_CODE_TYPE_REGEXP: + if (SUHOSIN_G(executor_disable_emod)) { + suhosin_log(S_EXECUTOR, "use of preg_replace() with /e modifier is forbidden by configuration"); + if (!SUHOSIN_G(simulation)) { + zend_error(E_ERROR, "SUHOSIN - Use of preg_replace() with /e modifier is forbidden by configuration"); + } + } + break; + + case SUHOSIN_CODE_TYPE_ASSERT: + break; + + case SUHOSIN_CODE_TYPE_CFUNC: + break; + + case SUHOSIN_CODE_TYPE_LONGNAME: + suhosin_log(S_INCLUDE, "Include filename ('%s') is too long", op_array->filename); + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_MANYDOTS: + suhosin_log(S_INCLUDE, "Include filename ('%s') contains too many '../'", op_array->filename); + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_UPLOADED: + suhosin_log(S_INCLUDE, "Include filename is an uploaded file"); + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_0FILE: + suhosin_log(S_INCLUDE, "Include filename contains an ASCIIZ character"); + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_WRITABLE: + suhosin_log(S_INCLUDE, "Include filename ('%s') is writable by PHP process", op_array->filename); + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_BLACKURL: + suhosin_log(S_INCLUDE, "Include filename ('%s') is an URL that is forbidden by the blacklist", op_array->filename); + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_BADURL: + suhosin_log(S_INCLUDE, "Include filename ('%s') is an URL that is not allowed", op_array->filename); + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_BADFILE: + cs.type = IS_STRING; +#define DIE_WITH_MSG "die('disallowed_file'.chr(10).chr(10));" + cs.value.str.val = estrndup(DIE_WITH_MSG, sizeof(DIE_WITH_MSG)-1); + cs.value.str.len = sizeof(DIE_WITH_MSG)-1; + new_op_array = compile_string(&cs, "suhosin internal code" TSRMLS_CC); + if (new_op_array) { + op_array = new_op_array; + goto continue_execution; + } + suhosin_bailout(TSRMLS_C); + break; + + case SUHOSIN_CODE_TYPE_COMMANDLINE: + case SUHOSIN_CODE_TYPE_SUHOSIN: + case SUHOSIN_CODE_TYPE_UNKNOWN: + case SUHOSIN_CODE_TYPE_GOODFILE: + goto continue_execution; + break; + } + +continue_execution: + if (zo) { + old_execute_ZO (op_array, dummy TSRMLS_CC); + } else { + old_execute (op_array TSRMLS_CC); + } + /* nothing to do */ + SUHOSIN_G(in_code_type) = orig_code_type; + SUHOSIN_G(execution_depth)--; +} +/* }}} */ + +/* {{{ void suhosin_execute(zend_op_array *op_array TSRMLS_DC) + * This function provides a hook for execution */ +static void suhosin_execute(zend_op_array *op_array TSRMLS_DC) +{ + suhosin_execute_ex(op_array, 0, 0 TSRMLS_CC); +} + +/* {{{ void suhosin_execute(zend_op_array *op_array, long dummy TSRMLS_DC) + * This function provides a hook for execution */ +static void suhosin_execute_ZO(zend_op_array *op_array, long dummy TSRMLS_DC) +{ + suhosin_execute_ex(op_array, 1, dummy TSRMLS_CC); +} +/* }}} */ + + +#define IH_HANDLER_PARAMS_REST zend_execute_data *execute_data_ptr, int return_value_used, int ht, zval *return_value TSRMLS_DC +#define IH_HANDLER_PARAMS internal_function_handler *ih, IH_HANDLER_PARAMS_REST +#define IH_HANDLER_PARAM_PASSTHRU ih, execute_data_ptr, return_value_used, ht, return_value TSRMLS_CC + +HashTable ihandler_table; + +typedef struct _internal_function_handler { + + char *name; + int (*handler)(struct _internal_function_handler *ih, IH_HANDLER_PARAMS_REST); + void *arg1; + void *arg2; + void *arg3; + +} internal_function_handler; + +int ih_preg_replace(IH_HANDLER_PARAMS) +{ + zval **regex, + **replace, + **subject, + **limit; + + if (ZEND_NUM_ARGS() < 3 || zend_get_parameters_ex(3, ®ex, &replace, &subject, &limit) == FAILURE) { + return (0); + } + + if (Z_TYPE_PP(regex) == IS_ARRAY) { + zval **regex_entry; + + zend_hash_internal_pointer_reset(Z_ARRVAL_PP(regex)); + /* For each entry in the regex array, get the entry */ + while (zend_hash_get_current_data(Z_ARRVAL_PP(regex), (void **)®ex_entry) == SUCCESS) { + + if (Z_TYPE_PP(regex_entry) == IS_STRING) { + if (strlen(Z_STRVAL_PP(regex_entry)) != Z_STRLEN_PP(regex_entry)) { + suhosin_log(S_EXECUTOR, "string termination attack on first preg_replace parameter detected"); + if (!SUHOSIN_G(simulation)) { + RETVAL_FALSE; + return (1); + } + } + } + + zend_hash_move_forward(Z_ARRVAL_PP(regex)); + + } + + } else if (Z_TYPE_PP(regex) == IS_STRING) { + if (strlen(Z_STRVAL_PP(regex)) != Z_STRLEN_PP(regex)) { + suhosin_log(S_EXECUTOR, "string termination attack on first preg_replace parameter detected"); + if (!SUHOSIN_G(simulation)) { + RETVAL_FALSE; + return (1); + } + } + } + + return (0); +} + +int ih_symlink(IH_HANDLER_PARAMS) +{ + if (SUHOSIN_G(executor_allow_symlink)) { + return (0); + } + + if (PG(open_basedir) && PG(open_basedir)[0]) { + suhosin_log(S_EXECUTOR, "symlink called during open_basedir"); + if (!SUHOSIN_G(simulation)) { + RETVAL_FALSE; + return (1); + } + } + + return (0); +} + +int ih_mail(IH_HANDLER_PARAMS) +{ + char *to=NULL, *message=NULL, *headers=NULL; + char *subject=NULL, *extra_cmd=NULL; + char *tmp; + int to_len, message_len, headers_len; + int subject_len, extra_cmd_len; + + if (SUHOSIN_G(mailprotect) == 0) { + return (0); + } + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|ss", + &to, &to_len, + &subject, &subject_len, + &message, &message_len, + &headers, &headers_len, + &extra_cmd, &extra_cmd_len + ) == FAILURE) { + RETVAL_FALSE; + return (1); + } + + if (headers_len > 0 && headers && (strstr(headers,"\n\n") || strstr(headers,"\r\n\r\n")) ) { + suhosin_log(S_MAIL, "mail() - double newline in headers, possible injection, mail dropped"); + if (!SUHOSIN_G(simulation)) { + RETVAL_FALSE; + return (1); + } + } + + /* check for spam attempts with buggy webforms */ + if (to_len > 0 && to) { + do { + tmp = strchr(to, '\n'); + tmp = tmp == NULL ? strchr(to, '\r') : tmp; + if (tmp == NULL) break; + to = tmp+1; + if (isspace(*to)) continue; + } while (1); + if (tmp != NULL) { + suhosin_log(S_MAIL, "mail() - newline in to header, possible injection, mail dropped"); + if (!SUHOSIN_G(simulation)) { + RETVAL_FALSE; + return (1); + } + } + } + + if (subject_len > 0 && subject) { + do { + tmp = strchr(subject, '\n'); + tmp = tmp == NULL ? strchr(subject, '\r') : tmp; + if (tmp == NULL) break; + subject = tmp+1; + if (isspace(*subject)) continue; + } while (1); + if (tmp != NULL) { + suhosin_log(S_MAIL, "mail() - newline in subject header, possible injection, mail dropped"); + if (!SUHOSIN_G(simulation)) { + RETVAL_FALSE; + return (1); + } + } + } + + if (SUHOSIN_G(mailprotect) > 1) { + /* search for to, cc or bcc headers */ + if (headers_len > 0 && headers != NULL) { + if (strncasecmp(headers, "to:", sizeof("to:") - 1) == 0 || suhosin_strcasestr(headers, "\nto:")) { + suhosin_log(S_MAIL, "mail() - To: headers aren't allowed in the headers parameter."); + if (!SUHOSIN_G(simulation)) { + RETVAL_FALSE; + return (1); + } + } + + if (strncasecmp(headers, "cc:", sizeof("cc:") - 1) == 0 || suhosin_strcasestr(headers, "\ncc:")) { + suhosin_log(S_MAIL, "mail() - CC: headers aren't allowed in the headers parameter."); + if (!SUHOSIN_G(simulation)) { + RETVAL_FALSE; + return (1); + } + } + + if (strncasecmp(headers, "bcc:", sizeof("bcc:") - 1) == 0 || suhosin_strcasestr(headers, "\nbcc:")) { + suhosin_log(S_MAIL, "mail() - BCC: headers aren't allowed in the headers parameter."); + if (!SUHOSIN_G(simulation)) { + RETVAL_FALSE; + return (1); + } + } + } + } + + return (0); +} + +#define SQLSTATE_SQL 0 +#define SQLSTATE_IDENTIFIER 1 +#define SQLSTATE_STRING 2 +#define SQLSTATE_COMMENT 3 +#define SQLSTATE_MLCOMMENT 4 + +int ih_querycheck(IH_HANDLER_PARAMS) +{ +#ifdef PHP_ATLEAST_5_3 + void **p = zend_vm_stack_top(TSRMLS_C) - 1; +#else + void **p = EG(argument_stack).top_element-2; +#endif + unsigned long arg_count; + zval **arg; + char *query, *s, *e; + zval *backup; + int len; + char quote; + int state = SQLSTATE_SQL; + int cnt_union = 0, cnt_select = 0, cnt_comment = 0, cnt_opencomment = 0; + int mysql_extension = 0; + + + SDEBUG("function: %s", ih->name); + arg_count = (unsigned long) *p; + + if (ht < (long) ih->arg1) { + return (0); + } + + if ((long) ih->arg1) { + mysql_extension = 1; + } + + arg = (zval **) p - (arg_count - (long) ih->arg1 + 1); /* count from 0 */ + + backup = *arg; + if (Z_TYPE_P(backup) != IS_STRING) { + return (0); + } + len = Z_STRLEN_P(backup); + query = Z_STRVAL_P(backup); + + s = query; + e = s+len; + + while (s < e) { + switch (state) + { + case SQLSTATE_SQL: + switch (s[0]) + { + case '`': + state = SQLSTATE_IDENTIFIER; + quote = '`'; + break; + case '\'': + case '"': + state = SQLSTATE_STRING; + quote = *s; + break; + case '/': + if (s[1]=='*') { + if (mysql_extension == 1 && s[2] == '!') { + s += 2; + break; + } + s++; + state = SQLSTATE_MLCOMMENT; + cnt_comment++; + } + break; + case '-': + if (s[1]=='-') { + s++; + state = SQLSTATE_COMMENT; + cnt_comment++; + } + break; + case '#': + state = SQLSTATE_COMMENT; + cnt_comment++; + break; + case 'u': + case 'U': + if (strncasecmp("union", s, 5)==0) { + s += 4; + cnt_union++; + } + break; + case 's': + case 'S': + if (strncasecmp("select", s, 6)==0) { + s += 5; + cnt_select++; + } + break; + } + break; + case SQLSTATE_STRING: + case SQLSTATE_IDENTIFIER: + if (s[0] == quote) { + if (s[1] == quote) { + s++; + } else { + state = SQLSTATE_SQL; + } + } + if (s[0] == '\\') { + s++; + } + break; + case SQLSTATE_COMMENT: + while (s[0] && s[0] != '\n') { + s++; + } + state = SQLSTATE_SQL; + break; + case SQLSTATE_MLCOMMENT: + while (s[0] && (s[0] != '*' || s[1] != '/')) { + s++; + } + if (s[0]) { + state = SQLSTATE_SQL; + } + break; + } + s++; + } + if (state == SQLSTATE_MLCOMMENT) { + cnt_opencomment = 1; + } + + if (cnt_opencomment && SUHOSIN_G(sql_opencomment)>0) { + suhosin_log(S_SQL, "Open comment in SQL query: '%*s'", len, query); + if (SUHOSIN_G(sql_opencomment)>1) { + suhosin_bailout(TSRMLS_C); + } + } + + if (cnt_comment && SUHOSIN_G(sql_comment)>0) { + suhosin_log(S_SQL, "Comment in SQL query: '%*s'", len, query); + if (SUHOSIN_G(sql_comment)>1) { + suhosin_bailout(TSRMLS_C); + } + } + + if (cnt_union && SUHOSIN_G(sql_union)>0) { + suhosin_log(S_SQL, "UNION in SQL query: '%*s'", len, query); + if (SUHOSIN_G(sql_union)>1) { + suhosin_bailout(TSRMLS_C); + } + } + + if (cnt_select>1 && SUHOSIN_G(sql_mselect)>0) { + suhosin_log(S_SQL, "Multiple SELECT in SQL query: '%*s'", len, query); + if (SUHOSIN_G(sql_mselect)>1) { + suhosin_bailout(TSRMLS_C); + } + } + + return (0); +} + + +int ih_fixusername(IH_HANDLER_PARAMS) +{ +#ifdef PHP_ATLEAST_5_3 + void **p = zend_vm_stack_top(TSRMLS_C) - 1; +#else + void **p = EG(argument_stack).top_element-2; +#endif + unsigned long arg_count; + zval **arg;char *prefix, *postfix, *user; + zval *backup, *my_user; + int prefix_len, postfix_len, len; + + SDEBUG("function: %s", ih->name); + + prefix = SUHOSIN_G(sql_user_prefix); + postfix = SUHOSIN_G(sql_user_postfix); + + if ((prefix == NULL || prefix[0] == 0)&& + (postfix == NULL || postfix[0] == 0)) { + return (0); + } + + if (prefix == NULL) { + prefix = ""; + } + if (postfix == NULL) { + postfix = ""; + } + + prefix_len = strlen(prefix); + postfix_len = strlen(postfix); + + arg_count = (unsigned long) *p; + + if (ht < (long) ih->arg1) { + return (0); + } + + arg = (zval **) p - (arg_count - (long) ih->arg1 + 1); /* count from 0 */ + + backup = *arg; + if (Z_TYPE_P(backup) != IS_STRING) { + user = ""; + len = 0; + } else { + len = Z_STRLEN_P(backup); + user = Z_STRVAL_P(backup); + } + + if (prefix_len && prefix_len <= len) { + if (strncmp(prefix, user, prefix_len)==0) { + prefix = ""; + len -= prefix_len; + } + } + + if (postfix_len && postfix_len <= len) { + if (strncmp(postfix, user+len-postfix_len, postfix_len)==0) { + postfix = ""; + } + } + + MAKE_STD_ZVAL(my_user); + my_user->type = IS_STRING; + my_user->value.str.len = spprintf(&my_user->value.str.val, 0, "%s%s%s", prefix, user, postfix); + + /* XXX: memory_leak? */ + *arg = my_user; + + SDEBUG("function: %s - user: %s", ih->name, user); + + return (0); +} + +static int suhosin_php_body_write(const char *str, uint str_length TSRMLS_DC) +{ +#define P_META_ROBOTS "" +#define S_META_ROBOTS "" + + SDEBUG("bw: %s", str); + + if ((str_length == sizeof("\n")-1) && (strcmp(str, "\n")==0)) { + SUHOSIN_G(old_php_body_write)(S_META_ROBOTS, sizeof(S_META_ROBOTS)-1 TSRMLS_CC); + OG(php_body_write) = SUHOSIN_G(old_php_body_write); + return SUHOSIN_G(old_php_body_write)(str, str_length TSRMLS_CC); + } else if ((str_length == sizeof(P_META_ROBOTS)-1) && (strcmp(str, P_META_ROBOTS)==0)) { + return str_length; + } + return SUHOSIN_G(old_php_body_write)(str, str_length TSRMLS_CC); +} + +static int ih_phpinfo(IH_HANDLER_PARAMS) +{ + int argc = ZEND_NUM_ARGS(); + long flag; + + if (zend_parse_parameters(argc TSRMLS_CC, "|l", &flag) == FAILURE) { + RETVAL_FALSE; + return (1); + } + + if(!argc) { + flag = PHP_INFO_ALL; + } + + /* Andale! Andale! Yee-Hah! */ + php_start_ob_buffer(NULL, 4096, 0 TSRMLS_CC); + if (!sapi_module.phpinfo_as_text) { + SUHOSIN_G(old_php_body_write) = OG(php_body_write); + OG(php_body_write) = suhosin_php_body_write; + } + php_print_info(flag TSRMLS_CC); + php_end_ob_buffer(1, 0 TSRMLS_CC); + + RETVAL_TRUE; + return (1); +} + + +static int ih_function_exists(IH_HANDLER_PARAMS) +{ + zval **function_name; + zend_function *func; + char *lcname; + zend_bool retval; + int func_name_len; + + if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &function_name)==FAILURE) { + ZEND_WRONG_PARAM_COUNT(); + } + convert_to_string_ex(function_name); + func_name_len = Z_STRLEN_PP(function_name); + lcname = estrndup(Z_STRVAL_PP(function_name), func_name_len); + zend_str_tolower(lcname, func_name_len); + + retval = (zend_hash_find(EG(function_table), lcname, func_name_len+1, (void **)&func) == SUCCESS); + + efree(lcname); + + /* + * A bit of a hack, but not a bad one: we see if the handler of the function + * is actually one that displays "function is disabled" message. + */ + if (retval && func->type == ZEND_INTERNAL_FUNCTION && + func->internal_function.handler == zif_display_disabled_function) { + retval = 0; + } + + /* Now check if function is forbidden by Suhosin */ + if (SUHOSIN_G(in_code_type) == SUHOSIN_EVAL) { + if (SUHOSIN_G(eval_whitelist) != NULL) { + if (!zend_hash_exists(SUHOSIN_G(eval_whitelist), lcname, func_name_len+1)) { + retval = 0; + } + } else if (SUHOSIN_G(eval_blacklist) != NULL) { + if (zend_hash_exists(SUHOSIN_G(eval_blacklist), lcname, func_name_len+1)) { + retval = 0; + } + } + } + + if (SUHOSIN_G(func_whitelist) != NULL) { + if (!zend_hash_exists(SUHOSIN_G(func_whitelist), lcname, func_name_len+1)) { + retval = 0; + } + } else if (SUHOSIN_G(func_blacklist) != NULL) { + if (zend_hash_exists(SUHOSIN_G(func_blacklist), lcname, func_name_len+1)) { + retval = 0; + } + } + + RETVAL_BOOL(retval); + return (1); +} + +/* MT RAND FUNCTIONS */ + +/* + The following php_mt_...() functions are based on a C++ class MTRand by + Richard J. Wagner. For more information see the web page at + http://www-personal.engin.umich.edu/~wagnerr/MersenneTwister.html + + Mersenne Twister random number generator -- a C++ class MTRand + Based on code by Makoto Matsumoto, Takuji Nishimura, and Shawn Cokus + Richard J. Wagner v1.0 15 May 2003 rjwagner@writeme.com + + The Mersenne Twister is an algorithm for generating random numbers. It + was designed with consideration of the flaws in various other generators. + The period, 2^19937-1, and the order of equidistribution, 623 dimensions, + are far greater. The generator is also fast; it avoids multiplication and + division, and it benefits from caches and pipelines. For more information + see the inventors' web page at http://www.math.keio.ac.jp/~matumoto/emt.html + + Reference + M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally + Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on + Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3-30. + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + Copyright (C) 2000 - 2003, Richard J. Wagner + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + The original code included the following notice: + + When you use this, send an email to: matumoto@math.keio.ac.jp + with an appropriate reference to your work. + + It would be nice to CC: rjwagner@writeme.com and Cokus@math.washington.edu + when you write. +*/ + +#define N 624 /* length of state vector */ +#define M (397) /* a period parameter */ +#define hiBit(u) ((u) & 0x80000000U) /* mask all but highest bit of u */ +#define loBit(u) ((u) & 0x00000001U) /* mask all but lowest bit of u */ +#define loBits(u) ((u) & 0x7FFFFFFFU) /* mask the highest bit of u */ +#define mixBits(u, v) (hiBit(u)|loBits(v)) /* move hi bit of u to hi bit of v */ + +#define twist(m,u,v) (m ^ (mixBits(u,v)>>1) ^ ((php_uint32)(-(php_int32)(loBit(u))) & 0x9908b0dfU)) + +/* {{{ php_mt_initialize + */ +static inline void suhosin_mt_initialize(php_uint32 seed, php_uint32 *state) +{ + /* Initialize generator state with seed + See Knuth TAOCP Vol 2, 3rd Ed, p.106 for multiplier. + In previous versions, most significant bits (MSBs) of the seed affect + only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto. */ + + register php_uint32 *s = state; + register php_uint32 *r = state; + register int i = 1; + + *s++ = seed & 0xffffffffU; + for( ; i < N; ++i ) { + *s++ = ( 1812433253U * ( *r ^ (*r >> 30) ) + i ) & 0xffffffffU; + r++; + } +} +/* }}} */ + +static inline void suhosin_mt_init_by_array(php_uint32 *key, int keylen, php_uint32 *state) +{ + int i, j, k; + suhosin_mt_initialize(19650218U, state); + i = 1; j = 0; + k = (N > keylen ? N : keylen); + for (; k; k--) { + state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1664525U)) + key[j] + j; + i++; j = (j+1) % keylen; + if (i >= N) { state[0] = state[N-1]; i=1; } + } + for (k=N-1; k; k--) { + state[i] = (state[i] ^ ((state[i-1] ^ (state[i-1] >> 30)) * 1566083941U)) - i; + i++; + if (i >= N) { state[0] = state[N-1]; i=1; } + } + state[0] = 0x80000000U; +} +/* }}} */ + + +/* {{{ suhosin_mt_reload + */ +static inline void suhosin_mt_reload(php_uint32 *state, php_uint32 **next, int *left) +{ + /* Generate N new values in state + Made clearer and faster by Matthew Bellew (matthew.bellew@home.com) */ + + register php_uint32 *p = state; + register int i; + + for (i = N - M; i--; ++p) + *p = twist(p[M], p[0], p[1]); + for (i = M; --i; ++p) + *p = twist(p[M-N], p[0], p[1]); + *p = twist(p[M-N], p[0], state[0]); + *left = N; + *next = state; +} +/* }}} */ + +/* {{{ suhosin_mt_srand + */ +static void suhosin_mt_srand(php_uint32 seed TSRMLS_DC) +{ + /* Seed the generator with a simple uint32 */ + suhosin_mt_initialize(seed, SUHOSIN_G(mt_state)); + suhosin_mt_reload(SUHOSIN_G(mt_state), &SUHOSIN_G(mt_next), &SUHOSIN_G(mt_left)); + + /* Seed only once */ + SUHOSIN_G(mt_is_seeded) = 1; +} +/* }}} */ + +/* {{{ suhosin_mt_rand + */ +static php_uint32 suhosin_mt_rand(TSRMLS_D) +{ + /* Pull a 32-bit integer from the generator state + Every other access function simply transforms the numbers extracted here */ + + register php_uint32 s1; + + if (SUHOSIN_G(mt_left) == 0) { + suhosin_mt_reload(SUHOSIN_G(mt_state), &SUHOSIN_G(mt_next), &SUHOSIN_G(mt_left)); + } + --SUHOSIN_G(mt_left); + + s1 = *SUHOSIN_G(mt_next)++; + s1 ^= (s1 >> 11); + s1 ^= (s1 << 7) & 0x9d2c5680U; + s1 ^= (s1 << 15) & 0xefc60000U; + return ( s1 ^ (s1 >> 18) ); +} +/* }}} */ + +/* {{{ suhosin_gen_entropy + */ +static void suhosin_gen_entropy(php_uint32 *seedbuf TSRMLS_DC) +{ + /* On a modern OS code, stack and heap base are randomized */ + unsigned long code_value = (unsigned long)suhosin_gen_entropy; + unsigned long stack_value = (unsigned long)&code_value; + unsigned long heap_value = (unsigned long)SUHOSIN_G(r_state); + suhosin_SHA256_CTX context; + + code_value ^= code_value >> 32; + stack_value ^= stack_value >> 32; + heap_value ^= heap_value >> 32; + + seedbuf[0] = code_value; + seedbuf[1] = stack_value; + seedbuf[2] = heap_value; + seedbuf[3] = time(0); +#ifdef PHP_WIN32 + seedbuf[4] = GetCurrentProcessId(); +#else + seedbuf[4] = getpid(); +#endif + seedbuf[5] = (php_uint32) 0x7fffffff * php_combined_lcg(TSRMLS_C); + + suhosin_SHA256Init(&context); + suhosin_SHA256Update(&context, (void *) seedbuf, sizeof(php_uint32) * 6); + suhosin_SHA256Final(seedbuf, &context); +} +/* }}} */ + + +/* {{{ suhosin_srand_auto + */ +static void suhosin_srand_auto(TSRMLS_D) +{ + php_uint32 seed[8]; + suhosin_gen_entropy(&seed[0] TSRMLS_CC); + + suhosin_mt_init_by_array(seed, 8, SUHOSIN_G(r_state)); + suhosin_mt_reload(SUHOSIN_G(r_state), &SUHOSIN_G(r_next), &SUHOSIN_G(r_left)); + + /* Seed only once */ + SUHOSIN_G(r_is_seeded) = 1; +} +/* }}} */ + +/* {{{ suhosin_mt_srand_auto + */ +static void suhosin_mt_srand_auto(TSRMLS_D) +{ + php_uint32 seed[8]; + suhosin_gen_entropy(&seed[0] TSRMLS_CC); + + suhosin_mt_init_by_array(seed, 8, SUHOSIN_G(mt_state)); + suhosin_mt_reload(SUHOSIN_G(mt_state), &SUHOSIN_G(mt_next), &SUHOSIN_G(mt_left)); + + /* Seed only once */ + SUHOSIN_G(mt_is_seeded) = 1; +} +/* }}} */ + + +/* {{{ suhosin_srand + */ +static void suhosin_srand(php_uint32 seed TSRMLS_DC) +{ + /* Seed the generator with a simple uint32 */ + suhosin_mt_initialize(seed+0x12345, SUHOSIN_G(r_state)); + suhosin_mt_reload(SUHOSIN_G(r_state), &SUHOSIN_G(r_next), &SUHOSIN_G(r_left)); + + /* Seed only once */ + SUHOSIN_G(r_is_seeded) = 1; +} +/* }}} */ + +/* {{{ suhosin_mt_rand + */ +static php_uint32 suhosin_rand(TSRMLS_D) +{ + /* Pull a 32-bit integer from the generator state + Every other access function simply transforms the numbers extracted here */ + + register php_uint32 s1; + + if (SUHOSIN_G(r_left) == 0) { + suhosin_mt_reload(SUHOSIN_G(r_state), &SUHOSIN_G(r_next), &SUHOSIN_G(r_left)); + } + --SUHOSIN_G(r_left); + + s1 = *SUHOSIN_G(r_next)++; + s1 ^= (s1 >> 11); + s1 ^= (s1 << 7) & 0x9d2c5680U; + s1 ^= (s1 << 15) & 0xefc60000U; + return ( s1 ^ (s1 >> 18) ); +} +/* }}} */ + +static int ih_srand(IH_HANDLER_PARAMS) +{ + int argc = ZEND_NUM_ARGS(); + long seed; + + if (zend_parse_parameters(argc TSRMLS_CC, "|l", &seed) == FAILURE || SUHOSIN_G(srand_ignore)) { + RETVAL_FALSE; + return (1); + } + + if (argc == 0) { + suhosin_srand_auto(TSRMLS_C); + } else { + suhosin_srand(seed TSRMLS_CC); + } + RETVAL_TRUE; + return (1); +} + +static int ih_mt_srand(IH_HANDLER_PARAMS) +{ + int argc = ZEND_NUM_ARGS(); + long seed; + + if (zend_parse_parameters(argc TSRMLS_CC, "|l", &seed) == FAILURE || SUHOSIN_G(mt_srand_ignore)) { + RETVAL_FALSE; + return (1); + } + + if (argc == 0) { + suhosin_mt_srand_auto(TSRMLS_C); + } else { + suhosin_mt_srand(seed TSRMLS_CC); + } + RETVAL_TRUE; + return (1); +} + +static int ih_mt_rand(IH_HANDLER_PARAMS) +{ + int argc = ZEND_NUM_ARGS(); + long min; + long max; + long number; + + if (argc != 0 && zend_parse_parameters(argc TSRMLS_CC, "ll", &min, &max) == FAILURE) { + return (1); + } + + if (!SUHOSIN_G(mt_is_seeded)) { + suhosin_mt_srand_auto(TSRMLS_C); + } + + number = (long) (suhosin_mt_rand(TSRMLS_C) >> 1); + if (argc == 2) { + RAND_RANGE(number, min, max, PHP_MT_RAND_MAX); + } + + RETURN_LONG(number); +} + +static int ih_rand(IH_HANDLER_PARAMS) +{ + int argc = ZEND_NUM_ARGS(); + long min; + long max; + long number; + + if (argc != 0 && zend_parse_parameters(argc TSRMLS_CC, "ll", &min, &max) == FAILURE) { + return (1); + } + + if (!SUHOSIN_G(r_is_seeded)) { + suhosin_srand_auto(TSRMLS_C); + } + + number = (long) (suhosin_rand(TSRMLS_C) >> 1); + if (argc == 2) { + RAND_RANGE(number, min, max, PHP_MT_RAND_MAX); + } + + RETURN_LONG(number); +} + +static int ih_getrandmax(IH_HANDLER_PARAMS) +{ + int argc = ZEND_NUM_ARGS(); + + if (argc != 0) { + ZEND_WRONG_PARAM_COUNT(); + } + + RETVAL_LONG(PHP_MT_RAND_MAX); + return (1); +} + +internal_function_handler ihandlers[] = { + { "preg_replace", ih_preg_replace, NULL, NULL, NULL }, + { "mail", ih_mail, NULL, NULL, NULL }, + { "symlink", ih_symlink, NULL, NULL, NULL }, + { "phpinfo", ih_phpinfo, NULL, NULL, NULL }, + + { "srand", ih_srand, NULL, NULL, NULL }, + { "mt_srand", ih_mt_srand, NULL, NULL, NULL }, + { "rand", ih_rand, NULL, NULL, NULL }, + { "mt_rand", ih_mt_rand, NULL, NULL, NULL }, + { "getrandmax", ih_getrandmax, NULL, NULL, NULL }, + { "mt_getrandmax", ih_getrandmax, NULL, NULL, NULL }, + + { "ocilogon", ih_fixusername, (void *)1, NULL, NULL }, + { "ociplogon", ih_fixusername, (void *)1, NULL, NULL }, + { "ocinlogon", ih_fixusername, (void *)1, NULL, NULL }, + { "oci_connect", ih_fixusername, (void *)1, NULL, NULL }, + { "oci_pconnect", ih_fixusername, (void *)1, NULL, NULL }, + { "oci_new_connect", ih_fixusername, (void *)1, NULL, NULL }, + + { "fbsql_change_user", ih_fixusername, (void *)1, NULL, NULL }, + { "fbsql_connect", ih_fixusername, (void *)2, NULL, NULL }, + { "fbsql_pconnect", ih_fixusername, (void *)2, NULL, NULL }, + + { "function_exists", ih_function_exists, NULL, NULL, NULL }, + + { "ifx_connect", ih_fixusername, (void *)2, NULL, NULL }, + { "ifx_pconnect", ih_fixusername, (void *)2, NULL, NULL }, + + { "ibase_connect", ih_fixusername, (void *)2, NULL, NULL }, + { "ibase_pconnect", ih_fixusername, (void *)2, NULL, NULL }, + + { "maxdb", ih_fixusername, (void *)2, NULL, NULL }, + { "maxdb_change_user", ih_fixusername, (void *)2, NULL, NULL }, + { "maxdb_connect", ih_fixusername, (void *)2, NULL, NULL }, + { "maxdb_pconnect", ih_fixusername, (void *)2, NULL, NULL }, + { "maxdb_real_connect", ih_fixusername, (void *)3, NULL, NULL }, + + { "mssql_connect", ih_fixusername, (void *)2, NULL, NULL }, + { "mssql_pconnect", ih_fixusername, (void *)2, NULL, NULL }, + + { "mysql_query", ih_querycheck, (void *)1, (void *)1, NULL }, + { "mysql_db_query", ih_querycheck, (void *)2, (void *)1, NULL }, + { "mysql_unbuffered_query", ih_querycheck, (void *)1, (void *)1, NULL }, + { "mysqli_query", ih_querycheck, (void *)2, (void *)1, NULL }, + { "mysqli_real_query", ih_querycheck, (void *)2, (void *)1, NULL }, + { "mysqli_send_query", ih_querycheck, (void *)2, (void *)1, NULL }, + { "mysqli_master_query", ih_querycheck, (void *)2, (void *)1, NULL }, + { "mysqli_slave_query", ih_querycheck, (void *)2, (void *)1, NULL }, + + { "mysqli", ih_fixusername, (void *)2, NULL, NULL }, + { "mysql_connect", ih_fixusername, (void *)2, NULL, NULL }, + { "mysql_pconnect", ih_fixusername, (void *)2, NULL, NULL }, + { "mysqli_change_user", ih_fixusername, (void *)2, NULL, NULL }, + { "mysql_real_connect", ih_fixusername, (void *)3, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL } +}; + +#define FUNCTION_WARNING() zend_error(E_WARNING, "%s() has been disabled for security reasons", get_active_function_name(TSRMLS_C)); + +/* {{{ void suhosin_execute_internal(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC) + * This function provides a hook for internal execution */ +static void suhosin_execute_internal(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC) +{ + char *lcname; + int function_name_strlen, free_lcname = 0; + zval *return_value; + zend_class_entry *ce = NULL; + int ht; + internal_function_handler *ih; + +#ifdef ZEND_ENGINE_2 + ce = ((zend_internal_function *) execute_data_ptr->function_state.function)->scope; +#endif + lcname = ((zend_internal_function *) execute_data_ptr->function_state.function)->function_name; + function_name_strlen = strlen(lcname); + + /* handle methodcalls correctly */ + if (ce != NULL) { + char *tmp = (char *) emalloc(function_name_strlen + 2 + ce->name_length + 1); + memcpy(tmp, ce->name, ce->name_length); + memcpy(tmp+ce->name_length, "::", 2); + memcpy(tmp+ce->name_length+2, lcname, function_name_strlen); + lcname = tmp; + free_lcname = 1; + function_name_strlen += ce->name_length + 2; + lcname[function_name_strlen] = 0; + zend_str_tolower(lcname, function_name_strlen); + } + +#ifdef ZEND_ENGINE_2 + return_value = (*(temp_variable *)((char *) execute_data_ptr->Ts + execute_data_ptr->opline->result.u.var)).var.ptr; +#else + return_value = execute_data_ptr->Ts[execute_data_ptr->opline->result.u.var].var.ptr; +#endif + ht = execute_data_ptr->opline->extended_value; + + SDEBUG("function: %s", lcname); + + if (SUHOSIN_G(in_code_type) == SUHOSIN_EVAL) { + + if (SUHOSIN_G(eval_whitelist) != NULL) { + if (!zend_hash_exists(SUHOSIN_G(eval_whitelist), lcname, function_name_strlen+1)) { + suhosin_log(S_EXECUTOR, "function outside of eval whitelist called: %s()", lcname); + goto execute_internal_bailout; + } + } else if (SUHOSIN_G(eval_blacklist) != NULL) { + if (zend_hash_exists(SUHOSIN_G(eval_blacklist), lcname, function_name_strlen+1)) { + suhosin_log(S_EXECUTOR, "function within eval blacklist called: %s()", lcname); + goto execute_internal_bailout; + } + } + } + + if (SUHOSIN_G(func_whitelist) != NULL) { + if (!zend_hash_exists(SUHOSIN_G(func_whitelist), lcname, function_name_strlen+1)) { + suhosin_log(S_EXECUTOR, "function outside of whitelist called: %s()", lcname); + goto execute_internal_bailout; + } + } else if (SUHOSIN_G(func_blacklist) != NULL) { + if (zend_hash_exists(SUHOSIN_G(func_blacklist), lcname, function_name_strlen+1)) { + suhosin_log(S_EXECUTOR, "function within blacklist called: %s()", lcname); + goto execute_internal_bailout; + } + } + + if (zend_hash_find(&ihandler_table, lcname, function_name_strlen+1, (void **)&ih) == SUCCESS) { + + int retval = 0; + void *handler = ((zend_internal_function *) execute_data_ptr->function_state.function)->handler; + + if (handler != ZEND_FN(display_disabled_function)) { + retval = ih->handler(IH_HANDLER_PARAM_PASSTHRU); + } + + if (retval == 0) { + old_execute_internal(execute_data_ptr, return_value_used TSRMLS_CC); + } + } else { + old_execute_internal(execute_data_ptr, return_value_used TSRMLS_CC); + } + if (free_lcname == 1) { + efree(lcname); + } + return; +execute_internal_bailout: + if (free_lcname == 1) { + efree(lcname); + } + FUNCTION_WARNING() + suhosin_bailout(TSRMLS_C); +} +/* }}} */ + + +/* {{{ int function_lookup(zend_extension *extension) + */ +static int function_lookup(zend_extension *extension) +{ + if (zo_set_oe_ex != NULL) { + return ZEND_HASH_APPLY_STOP; + } + + if (extension->handle != NULL) { + + zo_set_oe_ex = (void *)DL_FETCH_SYMBOL(extension->handle, "zend_optimizer_set_oe_ex"); + + } + + return 0; +} +/* }}} */ + + +/* {{{ void suhosin_hook_execute() + */ +void suhosin_hook_execute(TSRMLS_D) +{ + internal_function_handler *ih; + + old_execute = zend_execute; + zend_execute = suhosin_execute; + +/* old_compile_file = zend_compile_file; + zend_compile_file = suhosin_compile_file; */ + + if (zo_set_oe_ex == NULL) { + zo_set_oe_ex = (void *)DL_FETCH_SYMBOL(NULL, "zend_optimizer_set_oe_ex"); + } + if (zo_set_oe_ex == NULL) { + zend_llist_apply(&zend_extensions, (llist_apply_func_t)function_lookup TSRMLS_CC); + } + + if (zo_set_oe_ex != NULL) { + old_execute_ZO = zo_set_oe_ex(suhosin_execute_ZO); + } + + old_execute_internal = zend_execute_internal; + if (old_execute_internal == NULL) { + old_execute_internal = execute_internal; + } + zend_execute_internal = suhosin_execute_internal; + /* register internal function handlers */ + zend_hash_init(&ihandler_table, 16, NULL, NULL, 1); + ih = &ihandlers[0]; + while (ih->name) { + zend_hash_add(&ihandler_table, ih->name, strlen(ih->name)+1, ih, sizeof(internal_function_handler), NULL); + ih++; + } + + + /* Add additional protection layer, that SHOULD + catch ZEND_INCLUDE_OR_EVAL *before* the engine tries + to execute */ +#ifdef ZEND_ENGINE_2 + old_zend_stream_open = zend_stream_open_function; + zend_stream_open_function = suhosin_zend_stream_open; +#else + old_zend_open = zend_open; + zend_open = suhosin_zend_open; +#endif + +} +/* }}} */ + + +/* {{{ void suhosin_unhook_execute() + */ +void suhosin_unhook_execute() +{ + if (zo_set_oe_ex) { + zo_set_oe_ex(old_execute_ZO); + } + + zend_execute = old_execute; + +/* zend_compile_file = old_compile_file; */ + + if (old_execute_internal == execute_internal) { + old_execute_internal = NULL; + } + zend_execute_internal = old_execute_internal; + zend_hash_clean(&ihandler_table); + + /* remove zend_open protection */ +#ifdef ZEND_ENGINE_2 + zend_stream_open_function = old_zend_stream_open; +#else + zend_open = old_zend_open; +#endif + +} +/* }}} */ + + + +/* + * 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 --git a/header.c b/header.c new file mode 100644 index 0000000..9750232 --- /dev/null +++ b/header.c @@ -0,0 +1,353 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: header.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "ext/standard/url.h" +#include "php_suhosin.h" +#include "SAPI.h" +#include "php_variables.h" + +static int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC) = NULL; + +char *suhosin_encrypt_single_cookie(char *name, int name_len, char *value, int value_len, char *key TSRMLS_DC) +{ + char buffer[4096]; + char buffer2[4096]; + char *buf = buffer, *buf2 = buffer2, *d, *d_url; + int l; + + if (name_len > sizeof(buffer)-2) { + buf = estrndup(name, name_len); + } else { + memcpy(buf, name, name_len); + buf[name_len] = 0; + } + + name_len = php_url_decode(buf, name_len); + normalize_varname(buf); + name_len = strlen(buf); + + if (SUHOSIN_G(cookie_plainlist)) { + if (zend_hash_exists(SUHOSIN_G(cookie_plainlist), buf, name_len+1)) { +encrypt_return_plain: + if (buf != buffer) { + efree(buf); + } + return estrndup(value, value_len); + } + } else if (SUHOSIN_G(cookie_cryptlist)) { + if (!zend_hash_exists(SUHOSIN_G(cookie_cryptlist), buf, name_len+1)) { + goto encrypt_return_plain; + } + } + + if (strlen(value) <= sizeof(buffer2)-2) { + memcpy(buf2, value, value_len); + buf2[value_len] = 0; + } else { + buf2 = estrndup(value, value_len); + } + + value_len = php_url_decode(buf2, value_len); + + d = suhosin_encrypt_string(buf2, value_len, buf, name_len, key TSRMLS_CC); + d_url = php_url_encode(d, strlen(d), &l); + efree(d); + if (buf != buffer) { + efree(buf); + } + if (buf2 != buffer2) { + efree(buf2); + } + return d_url; +} + +char *suhosin_decrypt_single_cookie(char *name, int name_len, char *value, int value_len, char *key, char **where TSRMLS_DC) +{ + char buffer[4096]; + char buffer2[4096]; + int o_name_len = name_len; + char *buf = buffer, *buf2 = buffer2, *d, *d_url; + int l; + + if (name_len > sizeof(buffer)-2) { + buf = estrndup(name, name_len); + } else { + memcpy(buf, name, name_len); + buf[name_len] = 0; + } + + name_len = php_url_decode(buf, name_len); + normalize_varname(buf); + name_len = strlen(buf); + + if (SUHOSIN_G(cookie_plainlist)) { + if (zend_hash_exists(SUHOSIN_G(cookie_plainlist), buf, name_len+1)) { +decrypt_return_plain: + if (buf != buffer) { + efree(buf); + } + memcpy(*where, name, o_name_len); + *where += o_name_len; + **where = '='; *where +=1; + memcpy(*where, value, value_len); + *where += value_len; + return *where; + } + } else if (SUHOSIN_G(cookie_cryptlist)) { + if (!zend_hash_exists(SUHOSIN_G(cookie_cryptlist), buf, name_len+1)) { + goto decrypt_return_plain; + } + } + + + if (strlen(value) <= sizeof(buffer2)-2) { + memcpy(buf2, value, value_len); + buf2[value_len] = 0; + } else { + buf2 = estrndup(value, value_len); + } + + value_len = php_url_decode(buf2, value_len); + + d = suhosin_decrypt_string(buf2, value_len, buf, name_len, key, &l, SUHOSIN_G(cookie_checkraddr) TSRMLS_CC); + if (d == NULL) { + goto skip_cookie; + } + d_url = php_url_encode(d, l, &l); + efree(d); + memcpy(*where, name, o_name_len); + *where += o_name_len; + **where = '=';*where += 1; + memcpy(*where, d_url, l); + *where += l; + efree(d_url); +skip_cookie: + if (buf != buffer) { + efree(buf); + } + if (buf2 != buffer2) { + efree(buf2); + } + return *where; +} + +/* {{{ suhosin_cookie_decryptor + */ +char *suhosin_cookie_decryptor(TSRMLS_D) +{ + char *raw_cookie = SG(request_info).cookie_data; + char *decrypted, *ret, *var, *val, *tmp; + int j; + char cryptkey[33]; + + /* + if (...deactivated...) { + return estrdup(raw_cookie); + } + */ + + suhosin_generate_key(SUHOSIN_G(cookie_cryptkey), SUHOSIN_G(cookie_cryptua), SUHOSIN_G(cookie_cryptdocroot), SUHOSIN_G(cookie_cryptraddr), (char *)&cryptkey TSRMLS_CC); + + ret = decrypted = emalloc(strlen(raw_cookie)*4+1); + raw_cookie = estrdup(raw_cookie); + SUHOSIN_G(raw_cookie) = estrdup(raw_cookie); + + + j = 0; tmp = raw_cookie; + while (*tmp) { + char *d_url;int varlen; + while (*tmp == '\t' || *tmp == ' ') tmp++; + var = tmp; + while (*tmp && *tmp != ';' && *tmp != '=') tmp++; + + varlen = tmp-var; + /*memcpy(decrypted, var, varlen); + decrypted += varlen;*/ + if (*tmp == 0) break; + + if (*tmp++ == ';') { + *decrypted++ = ';'; + continue; + } + + /**decrypted++ = '=';*/ + + val = tmp; + while (*tmp && *tmp != ';') tmp++; + + d_url = suhosin_decrypt_single_cookie(var, varlen, val, tmp-val, (char *)&cryptkey, &decrypted TSRMLS_CC); + if (*tmp == ';') { + *decrypted++ = ';'; + } + + if (*tmp == 0) break; + tmp++; + } + *decrypted++ = 0; + ret = erealloc(ret, decrypted-ret); + + SUHOSIN_G(decrypted_cookie) = ret; + efree(raw_cookie); + + return ret; +} +/* }}} */ + +/* {{{ suhosin_header_handler + */ +int suhosin_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC) +{ + int retval = SAPI_HEADER_ADD, i; + char *tmp; + + if (!SUHOSIN_G(allow_multiheader) && sapi_header && sapi_header->header) { + + tmp = sapi_header->header; + + for (i=0; iheader_len; i++, tmp++) { + if (tmp[0] == 0) { + char *fname = get_active_function_name(TSRMLS_C); + + if (!fname) { + fname = "unknown"; + } + + suhosin_log(S_MISC, "%s() - wanted to send a HTTP header with an ASCII NUL in it", fname); + if (!SUHOSIN_G(simulation)) { + sapi_header->header_len = i; + } + } else if ((tmp[0] == '\r' && (tmp[1] != '\n' || i == 0)) || + (tmp[0] == '\n' && (i == sapi_header->header_len-1 || i == 0 || (tmp[1] != ' ' && tmp[1] != '\t')))) { + char *fname = get_active_function_name(TSRMLS_C); + + if (!fname) { + fname = "unknown"; + } + + suhosin_log(S_MISC, "%s() - wanted to send multiple HTTP headers at once", fname); + if (!SUHOSIN_G(simulation)) { + sapi_header->header_len = i; + tmp[0] = 0; + } + } + } + } + + /* Handle a potential cookie */ + + if (SUHOSIN_G(cookie_encrypt) && (strncasecmp("Set-Cookie:", sapi_header->header, sizeof("Set-Cookie:")-1) == 0)) { + + char *start, *end, *rend, *tmp; + char *name, *value; + int nlen, vlen, len, tlen; + char cryptkey[33]; + + suhosin_generate_key(SUHOSIN_G(cookie_cryptkey), SUHOSIN_G(cookie_cryptua), SUHOSIN_G(cookie_cryptdocroot), SUHOSIN_G(cookie_cryptraddr), (char *)&cryptkey TSRMLS_CC); + start = estrndup(sapi_header->header, sapi_header->header_len); + rend = end = start + sapi_header->header_len; + + tmp = memchr(start, ';', end-start); + if (tmp != NULL) { + end = tmp; + } + + tmp = start + sizeof("Set-Cookie:") - 1; + while (tmp < end && tmp[0]==' ') { + tmp++; + } + name = tmp; + nlen = end-name; + tmp = memchr(name, '=', nlen); + if (tmp == NULL) { + value = end; + } else { + value = tmp+1; + nlen = tmp-name; + } + vlen = end-value; + + value = suhosin_encrypt_single_cookie(name, nlen, value, vlen, (char *)&cryptkey TSRMLS_CC); + vlen = strlen(value); + + len = sizeof("Set-Cookie: ")-1 + nlen + 1 + vlen + rend-end; + tmp = emalloc(len + 1); + tlen = sprintf(tmp, "Set-Cookie: %.*s=%s", nlen,name, value); + memcpy(tmp + tlen, end, rend-end); + tmp[len] = 0; + + efree(sapi_header->header); + efree(value); + efree(start); + + sapi_header->header = tmp; + sapi_header->header_len = len; + } + + + /* If existing call the sapi header handler */ + if (orig_header_handler) { + retval = orig_header_handler(sapi_header, sapi_headers TSRMLS_CC); + } + + return retval; +} +/* }}} */ + + +/* {{{ suhosin_hook_header_handler + */ +void suhosin_hook_header_handler() +{ + if (orig_header_handler == NULL) { + orig_header_handler = sapi_module.header_handler; + sapi_module.header_handler = suhosin_header_handler; + } +} +/* }}} */ + +/* {{{ suhosin_unhook_header_handler + */ +void suhosin_unhook_header_handler() +{ + sapi_module.header_handler = orig_header_handler; + orig_header_handler = NULL; +} +/* }}} */ + + +/* + * 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 --git a/ifilter.c b/ifilter.c new file mode 100644 index 0000000..f90173b --- /dev/null +++ b/ifilter.c @@ -0,0 +1,732 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: ifilter.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "php_suhosin.h" +#include "php_variables.h" + + +static void (*orig_register_server_variables)(zval *track_vars_array TSRMLS_DC) = NULL; + +#ifdef ZEND_ENGINE_2 +#define HASH_HTTP_GET_VARS 0x2095733f +#define HASH_HTTP_POST_VARS 0xbfee1265 +#define HASH_HTTP_COOKIE_VARS 0xaaca9d99 +#define HASH_HTTP_ENV_VARS 0x1fe186a8 +#define HASH_HTTP_SERVER_VARS 0xc987afd6 +#define HASH_HTTP_SESSION_VARS 0x7aba0d43 +#define HASH_HTTP_POST_FILES 0x98eb1ddc +#define HASH_HTTP_RAW_POST_DATA 0xdd633fec +#else +#define HASH_HTTP_GET_VARS 0x8d8645bd +#define HASH_HTTP_POST_VARS 0x7c699bf3 +#define HASH_HTTP_COOKIE_VARS 0x93ad0d6f +#define HASH_HTTP_ENV_VARS 0x84da3016 +#define HASH_HTTP_SERVER_VARS 0x6dbf964e +#define HASH_HTTP_SESSION_VARS 0x322906f5 +#define HASH_HTTP_POST_FILES 0xe4e4ce70 +#define HASH_HTTP_RAW_POST_DATA 0xe6137a0e +#endif + + +/* {{{ normalize_varname + */ +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'; +} +/* }}} */ + +static unsigned char suhosin_hexchars[] = "0123456789ABCDEF"; + +static const char suhosin_is_dangerous_char[256] = { + 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, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 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, + 1, 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, + 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, 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 +}; + +/* {{{ suhosin_server_encode + */ +static void suhosin_server_strip(HashTable *arr, char *key, int klen) +{ + zval **tzval; + unsigned char *s, *t; + + if (zend_hash_find(arr, key, klen, (void **) &tzval) == SUCCESS && + Z_TYPE_PP(tzval) == IS_STRING) { + + s = t = Z_STRVAL_PP(tzval); + for (; *t; t++) { + if (suhosin_is_dangerous_char[*t]) { + *t = '?'; + } + } + Z_STRLEN_PP(tzval) = t-s; + } +} +/* }}} */ + +/* {{{ suhosin_server_encode + */ +static void suhosin_server_encode(HashTable *arr, char *key, int klen) +{ + zval **tzval; + unsigned char *temp = NULL, *t, *newv, *n; + int extra = 0; + + if (zend_hash_find(arr, key, klen, (void **) &tzval) == SUCCESS && + Z_TYPE_PP(tzval) == IS_STRING) { + + temp = Z_STRVAL_PP(tzval); + + t = temp; + for (t = temp; *t; t++) { + if (suhosin_is_dangerous_char[*t]) { + extra += 2; + } + } + + /* no extra bytes required */ + if (extra == 0) { + return; + } + + n = newv = emalloc(t - temp + 1 + extra); + t = temp; + for (t = temp; *t; t++, n++) { + if (suhosin_is_dangerous_char[*t]) { + *n++ = '%'; + *n++ = suhosin_hexchars[*t >> 4]; + *n = suhosin_hexchars[*t & 15]; + } else { + *n = *t; + } + } + *n = 0; + + Z_STRVAL_PP(tzval) = newv; + Z_STRLEN_PP(tzval) = n-newv; + } +} +/* }}} */ + +/* {{{ suhosin_register_server_variables + */ +void suhosin_register_server_variables(zval *track_vars_array TSRMLS_DC) +{ + HashTable *svars; + int retval, failure=0; + + orig_register_server_variables(track_vars_array TSRMLS_CC); + + svars = Z_ARRVAL_P(track_vars_array); + + if (!SUHOSIN_G(simulation)) { + retval = zend_hash_del_key_or_index(svars, "HTTP_GET_VARS", sizeof("HTTP_GET_VARS"), HASH_HTTP_GET_VARS, HASH_DEL_INDEX); + if (retval == SUCCESS) failure = 1; + retval = zend_hash_del_key_or_index(svars, "HTTP_POST_VARS", sizeof("HTTP_POST_VARS"), HASH_HTTP_POST_VARS, HASH_DEL_INDEX); + if (retval == SUCCESS) failure = 1; + retval = zend_hash_del_key_or_index(svars, "HTTP_COOKIE_VARS", sizeof("HTTP_COOKIE_VARS"), HASH_HTTP_COOKIE_VARS, HASH_DEL_INDEX); + if (retval == SUCCESS) failure = 1; + retval = zend_hash_del_key_or_index(svars, "HTTP_ENV_VARS", sizeof("HTTP_ENV_VARS"), HASH_HTTP_ENV_VARS, HASH_DEL_INDEX); + if (retval == SUCCESS) failure = 1; + retval = zend_hash_del_key_or_index(svars, "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS"), HASH_HTTP_SERVER_VARS, HASH_DEL_INDEX); + if (retval == SUCCESS) failure = 1; + retval = zend_hash_del_key_or_index(svars, "HTTP_SESSION_VARS", sizeof("HTTP_SESSION_VARS"), HASH_HTTP_SESSION_VARS, HASH_DEL_INDEX); + if (retval == SUCCESS) failure = 1; + retval = zend_hash_del_key_or_index(svars, "HTTP_POST_FILES", sizeof("HTTP_POST_FILES"), HASH_HTTP_POST_FILES, HASH_DEL_INDEX); + if (retval == SUCCESS) failure = 1; + retval = zend_hash_del_key_or_index(svars, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA"), HASH_HTTP_RAW_POST_DATA, HASH_DEL_INDEX); + if (retval == SUCCESS) failure = 1; + } else { + retval = zend_hash_exists(svars, "HTTP_GET_VARS", sizeof("HTTP_GET_VARS")); + retval+= zend_hash_exists(svars, "HTTP_POST_VARS", sizeof("HTTP_POST_VARS")); + retval+= zend_hash_exists(svars, "HTTP_COOKIE_VARS", sizeof("HTTP_COOKIE_VARS")); + retval+= zend_hash_exists(svars, "HTTP_ENV_VARS", sizeof("HTTP_ENV_VARS")); + retval+= zend_hash_exists(svars, "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS")); + retval+= zend_hash_exists(svars, "HTTP_SESSION_VARS", sizeof("HTTP_SESSION_VARS")); + retval+= zend_hash_exists(svars, "HTTP_POST_FILES", sizeof("HTTP_POST_FILES")); + retval+= zend_hash_exists(svars, "HTTP_RAW_POST_DATA", sizeof("HTTP_RAW_POST_DATA")); + if (retval > 0) failure = 1; + } + + if (failure) { + suhosin_log(S_VARS, "Attacker tried to overwrite a superglobal through a HTTP header"); + } + + if (SUHOSIN_G(raw_cookie)) { + zval *z; + MAKE_STD_ZVAL(z); + ZVAL_STRING(z, SUHOSIN_G(raw_cookie), 1); + zend_hash_add(svars, "RAW_HTTP_COOKIE", sizeof("RAW_HTTP_COOKIE"), (void **)&z, sizeof(zval *), NULL); + } + if (SUHOSIN_G(decrypted_cookie)) { + zval *z; + MAKE_STD_ZVAL(z); + ZVAL_STRING(z, SUHOSIN_G(decrypted_cookie), 0); + zend_hash_update(svars, "HTTP_COOKIE", sizeof("HTTP_COOKIE"), (void **)&z, sizeof(zval *), NULL); + SUHOSIN_G(decrypted_cookie) = NULL; + } + + if (SUHOSIN_G(server_encode)) { + /* suhosin_server_encode(svars, "argv", sizeof("argv")); */ + suhosin_server_encode(svars, "REQUEST_URI", sizeof("REQUEST_URI")); + suhosin_server_encode(svars, "QUERY_STRING", sizeof("QUERY_STRING")); + } + if (SUHOSIN_G(server_strip)) { + suhosin_server_strip(svars, "PHP_SELF", sizeof("PHP_SELF")); + suhosin_server_strip(svars, "PATH_INFO", sizeof("PATH_INFO")); + suhosin_server_strip(svars, "PATH_TRANSLATED", sizeof("PATH_TRANSLATED")); + } +} +/* }}} */ + + +#ifdef ZEND_ENGINE_2 + /* Old Input filter */ + unsigned int (*old_input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) = NULL; + +/* {{{ suhosin_input_filter_wrapper + */ +unsigned int suhosin_input_filter_wrapper(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) +{ + zend_bool already_scanned = SUHOSIN_G(already_scanned); + SUHOSIN_G(already_scanned) = 0; + + if (SUHOSIN_G(do_not_scan)) { + if (new_val_len) { + *new_val_len = val_len; + } + return 1; + } + + if (!already_scanned) { + if (suhosin_input_filter(arg, var, val, val_len, new_val_len TSRMLS_CC)==0) { + SUHOSIN_G(abort_request)=1; + return 0; + } + if (new_val_len) { + val_len = *new_val_len; + } + } + if (old_input_filter) { + return old_input_filter(arg, var, val, val_len, new_val_len TSRMLS_CC); + } else { + return 1; + } +} +#endif + +/* {{{ suhosin_input_filter + */ +unsigned int suhosin_input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC) +{ + char *index, *prev_index = NULL; + unsigned int var_len, total_len, depth = 0; + + /* Mark that we were called */ + SUHOSIN_G(already_scanned) = 1; + + if (new_val_len) { + *new_val_len = 0; + } + + /* Drop this variable if the limit was reached */ + switch (arg) { + case PARSE_GET: + if (SUHOSIN_G(no_more_get_variables)) { + return 0; + } + break; + case PARSE_POST: + if (SUHOSIN_G(no_more_post_variables)) { + return 0; + } + break; + case PARSE_COOKIE: + if (SUHOSIN_G(no_more_cookie_variables)) { + return 0; + } + break; + default: /* we do not want to protect parse_str() and friends */ + if (new_val_len) { + *new_val_len = val_len; + } + return 1; + } + + /* Drop this variable if the limit is now reached */ + switch (arg) { + case PARSE_GET: + if (SUHOSIN_G(max_get_vars) && SUHOSIN_G(max_get_vars) <= SUHOSIN_G(cur_get_vars)) { + suhosin_log(S_VARS, "configured GET variable limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + SUHOSIN_G(no_more_get_variables) = 1; + return 0; + } + } + break; + case PARSE_COOKIE: + if (SUHOSIN_G(max_cookie_vars) && SUHOSIN_G(max_cookie_vars) <= SUHOSIN_G(cur_cookie_vars)) { + suhosin_log(S_VARS, "configured COOKIE variable limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + SUHOSIN_G(no_more_cookie_variables) = 1; + return 0; + } + } + break; + case PARSE_POST: + if (SUHOSIN_G(max_post_vars) && SUHOSIN_G(max_post_vars) <= SUHOSIN_G(cur_post_vars)) { + suhosin_log(S_VARS, "configured POST variable limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + SUHOSIN_G(no_more_post_variables) = 1; + return 0; + } + } + break; + } + + /* Drop this variable if it begins with whitespace which is disallowed */ + if (*var == ' ') { + if (SUHOSIN_G(disallow_ws)) { + suhosin_log(S_VARS, "request variable name begins with disallowed whitespace - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + switch (arg) { + case PARSE_GET: + if (SUHOSIN_G(disallow_get_ws)) { + suhosin_log(S_VARS, "GET variable name begins with disallowed whitespace - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + case PARSE_POST: + if (SUHOSIN_G(disallow_post_ws)) { + suhosin_log(S_VARS, "POST variable name begins with disallowed whitespace - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + case PARSE_COOKIE: + if (SUHOSIN_G(disallow_cookie_ws)) { + suhosin_log(S_VARS, "COOKIE variable name begins with disallowed whitespace - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + } + } + + /* Drop this variable if it exceeds the value length limit */ + if (SUHOSIN_G(max_value_length) && SUHOSIN_G(max_value_length) < val_len) { + suhosin_log(S_VARS, "configured request variable value length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + switch (arg) { + case PARSE_GET: + if (SUHOSIN_G(max_get_value_length) && SUHOSIN_G(max_get_value_length) < val_len) { + suhosin_log(S_VARS, "configured GET variable value length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + case PARSE_COOKIE: + if (SUHOSIN_G(max_cookie_value_length) && SUHOSIN_G(max_cookie_value_length) < val_len) { + suhosin_log(S_VARS, "configured COOKIE variable value length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + case PARSE_POST: + if (SUHOSIN_G(max_post_value_length) && SUHOSIN_G(max_post_value_length) < val_len) { + suhosin_log(S_VARS, "configured POST variable value length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + 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 (SUHOSIN_G(max_varname_length) && SUHOSIN_G(max_varname_length) < var_len) { + suhosin_log(S_VARS, "configured request variable name length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + if (SUHOSIN_G(max_totalname_length) && SUHOSIN_G(max_totalname_length) < total_len) { + suhosin_log(S_VARS, "configured request variable total name length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + switch (arg) { + case PARSE_GET: + if (SUHOSIN_G(max_get_name_length) && SUHOSIN_G(max_get_name_length) < var_len) { + suhosin_log(S_VARS, "configured GET variable name length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + if (SUHOSIN_G(max_get_totalname_length) && SUHOSIN_G(max_get_totalname_length) < var_len) { + suhosin_log(S_VARS, "configured GET variable total name length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + case PARSE_COOKIE: + if (SUHOSIN_G(max_cookie_name_length) && SUHOSIN_G(max_cookie_name_length) < var_len) { + suhosin_log(S_VARS, "configured COOKIE variable name length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + if (SUHOSIN_G(max_cookie_totalname_length) && SUHOSIN_G(max_cookie_totalname_length) < var_len) { + suhosin_log(S_VARS, "configured COOKIE variable total name length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + case PARSE_POST: + if (SUHOSIN_G(max_post_name_length) && SUHOSIN_G(max_post_name_length) < var_len) { + suhosin_log(S_VARS, "configured POST variable name length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + if (SUHOSIN_G(max_post_totalname_length) && SUHOSIN_G(max_post_totalname_length) < var_len) { + suhosin_log(S_VARS, "configured POST variable total name length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + 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 (SUHOSIN_G(max_array_index_length) && SUHOSIN_G(max_array_index_length) < index_length) { + suhosin_log(S_VARS, "configured request variable array index length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + switch (arg) { + case PARSE_GET: + if (SUHOSIN_G(max_get_array_index_length) && SUHOSIN_G(max_get_array_index_length) < index_length) { + suhosin_log(S_VARS, "configured GET variable array index length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + case PARSE_COOKIE: + if (SUHOSIN_G(max_cookie_array_index_length) && SUHOSIN_G(max_cookie_array_index_length) < index_length) { + suhosin_log(S_VARS, "configured COOKIE variable array index length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + case PARSE_POST: + if (SUHOSIN_G(max_post_array_index_length) && SUHOSIN_G(max_post_array_index_length) < index_length) { + suhosin_log(S_VARS, "configured POST variable array index length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + } + prev_index = index; + } + + } + + /* Drop this variable if it exceeds the array depth limit */ + if (SUHOSIN_G(max_array_depth) && SUHOSIN_G(max_array_depth) < depth) { + suhosin_log(S_VARS, "configured request variable array depth limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + switch (arg) { + case PARSE_GET: + if (SUHOSIN_G(max_get_array_depth) && SUHOSIN_G(max_get_array_depth) < depth) { + suhosin_log(S_VARS, "configured GET variable array depth limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + case PARSE_COOKIE: + if (SUHOSIN_G(max_cookie_array_depth) && SUHOSIN_G(max_cookie_array_depth) < depth) { + suhosin_log(S_VARS, "configured COOKIE variable array depth limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + case PARSE_POST: + if (SUHOSIN_G(max_post_array_depth) && SUHOSIN_G(max_post_array_depth) < depth) { + suhosin_log(S_VARS, "configured POST variable array depth limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + } + + /* Check if variable value is truncated by a \0 */ + + if (val && *val && val_len != strlen(*val)) { + + if (SUHOSIN_G(disallow_nul)) { + suhosin_log(S_VARS, "ASCII-NUL chars not allowed within request variables - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + switch (arg) { + case PARSE_GET: + if (SUHOSIN_G(disallow_get_nul)) { + suhosin_log(S_VARS, "ASCII-NUL chars not allowed within GET variables - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + case PARSE_COOKIE: + if (SUHOSIN_G(disallow_cookie_nul)) { + suhosin_log(S_VARS, "ASCII-NUL chars not allowed within COOKIE variables - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + return 0; + } + } + break; + case PARSE_POST: + if (SUHOSIN_G(disallow_post_nul)) { + suhosin_log(S_VARS, "ASCII-NUL chars not allowed within POST variables - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + 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 */ + SUHOSIN_G(cur_request_variables)++; + switch (arg) { + case PARSE_GET: + SUHOSIN_G(cur_get_vars)++; + break; + case PARSE_COOKIE: + SUHOSIN_G(cur_cookie_vars)++; + break; + case PARSE_POST: + SUHOSIN_G(cur_post_vars)++; + break; + } + + if (new_val_len) { + *new_val_len = val_len; + } + + return 1; +protected_varname: + suhosin_log(S_VARS, "tried to register forbidden variable '%s' through %s variables", var, arg == PARSE_GET ? "GET" : arg == PARSE_POST ? "POST" : "COOKIE"); + if (!SUHOSIN_G(simulation)) { + return 0; + } else { + return 1; + } +} +/* }}} */ + + + +/* {{{ suhosin_hook_register_server_variables + */ +void suhosin_hook_register_server_variables() +{ + if (sapi_module.register_server_variables) { + orig_register_server_variables = sapi_module.register_server_variables; + sapi_module.register_server_variables = suhosin_register_server_variables; + } +} +/* }}} */ + + +/* + * 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 --git a/log.c b/log.c new file mode 100644 index 0000000..d5e3b50 --- /dev/null +++ b/log.c @@ -0,0 +1,404 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: log.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "php_suhosin.h" +#include +#include "SAPI.h" +#include "ext/standard/datetime.h" +#include "ext/standard/flock_compat.h" + +#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 PHP_WIN32 +static HANDLE log_source = 0; +#endif + + +static 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_MAIL: + return "MAIL"; + case S_SESSION: + return "SESSION"; + case S_SQL: + return "SQL"; + case S_EXECUTOR: + return "EXECUTOR"; + case S_VARS: + return "VARS"; + default: + return "UNKNOWN"; + } +} + +static char *month_names[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +PHP_SUHOSIN_API void suhosin_log(int loglevel, char *fmt, ...) +{ + int s, r, i=0, fd; + long written, towrite; + char *wbuf; + struct timeval tv; + time_t now; + struct tm tm; +#if defined(AF_UNIX) + struct sockaddr_un saun; +#endif +#ifdef PHP_WIN32 + LPTSTR strs[2]; + unsigned short etype; + DWORD evid; +#endif + char buf[4096+64]; + char error[4096+100]; + char *ip_address; + char *fname; + char *alertstring; + int lineno; + va_list ap; + TSRMLS_FETCH(); + + SDEBUG("(suhosin_log) loglevel: %d log_syslog: %u - log_sapi: %u - log_script: %u", loglevel, SUHOSIN_G(log_syslog), SUHOSIN_G(log_sapi), SUHOSIN_G(log_script)); + + /* dump core if wanted */ + if (SUHOSIN_G(coredump) && loglevel == S_MEMORY) { + volatile unsigned int *x = 0; + volatile int y = *x; + } + + if (SUHOSIN_G(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 (SUHOSIN_G(simulation)) { + alertstring = "ALERT-SIMULATION"; + } else { + alertstring = "ALERT"; + } + + if (zend_is_executing(TSRMLS_C)) { + if (EG(current_execute_data)) { + lineno = EG(current_execute_data)->opline->lineno; + fname = EG(current_execute_data)->op_array->filename; + } else { + lineno = zend_get_executed_lineno(TSRMLS_C); + fname = zend_get_executed_filename(TSRMLS_C); + } + ap_php_snprintf(buf, sizeof(buf), "%s - %s (attacker '%s', file '%s', line %u)", alertstring, 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), "%s - %s (attacker '%s', file '%s')", alertstring, error, ip_address, fname); + } + + /* Syslog-Logging disabled? */ + if (((SUHOSIN_G(log_syslog)|S_INTERNAL) & loglevel)==0) { + goto log_file; + } + +#if defined(AF_UNIX) + ap_php_snprintf(error, sizeof(error), "<%u>suhosin[%u]: %s\n", (unsigned int)(SUHOSIN_G(log_syslog_facility)|SUHOSIN_G(log_syslog_priority)),getpid(),buf); + + s = socket(AF_UNIX, SOCK_DGRAM, 0); + if (s == -1) { + goto log_file; + } + + 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_file; + } + + 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_file; + } + } + send(s, error, strlen(error), 0); + + close(s); +#endif +#ifdef PHP_WIN32 + ap_php_snprintf(error, sizeof(error), "suhosin[%u]: %s", getpid(),buf); + + switch (SUHOSIN_G(log_syslog_priority)) { /* translate UNIX type into NT type */ + case 1: /*LOG_ALERT:*/ + etype = EVENTLOG_ERROR_TYPE; + break; + case 6: /*LOG_INFO:*/ + etype = EVENTLOG_INFORMATION_TYPE; + break; + default: + etype = EVENTLOG_WARNING_TYPE; + } + evid = loglevel; + strs[0] = error; + /* report the event */ + if (log_source == NULL) { + log_source = RegisterEventSource(NULL, "Suhosin-" SUHOSIN_EXT_VERSION); + } + ReportEvent(log_source, etype, (unsigned short) SUHOSIN_G(log_syslog_priority), evid, NULL, 1, 0, strs, NULL); + +#endif +log_file: + /* File-Logging disabled? */ + if ((SUHOSIN_G(log_file) & loglevel)==0) { + goto log_sapi; + } + + if (!SUHOSIN_G(log_filename) || !SUHOSIN_G(log_filename)[0]) { + goto log_sapi; + } + fd = open(SUHOSIN_G(log_filename), O_CREAT|O_APPEND|O_WRONLY, 0640); + if (fd == -1) { + suhosin_log(S_INTERNAL, "Unable to open logfile: %s", SUHOSIN_G(log_filename)); + return; + } + + gettimeofday(&tv, NULL); + now = tv.tv_sec; + php_gmtime_r(&now, &tm); + ap_php_snprintf(error, sizeof(error), "%s %2d %02d:%02d:%02d [%u] %s\n", month_names[tm.tm_mon], tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, getpid(),buf); + towrite = strlen(error); + wbuf = error; + php_flock(fd, LOCK_EX); + while (towrite > 0) { + written = write(fd, wbuf, towrite); + if (written < 0) { + break; + } + towrite -= written; + wbuf += written; + } + php_flock(fd, LOCK_UN); + close(fd); + +log_sapi: + /* SAPI Logging activated? */ + SDEBUG("(suhosin_log) log_syslog: %u - log_sapi: %u - log_script: %u - log_phpscript: %u", SUHOSIN_G(log_syslog), SUHOSIN_G(log_sapi), SUHOSIN_G(log_script), SUHOSIN_G(log_phpscript)); + if (((SUHOSIN_G(log_sapi)|S_INTERNAL) & loglevel)!=0) { + sapi_module.log_message(buf); + } + +/*log_script:*/ + /* script logging activaed? */ + if (((SUHOSIN_G(log_script) & loglevel)!=0) && SUHOSIN_G(log_scriptname)!=NULL) { + char cmd[8192], *cmdpos, *bufpos; + FILE *in; + int space; + + char *sname = SUHOSIN_G(log_scriptname); + while (isspace(*sname)) ++sname; + if (*sname == 0) goto log_phpscript; + + ap_php_snprintf(cmd, sizeof(cmd), "%s %s \'", sname, 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) { + suhosin_log(S_INTERNAL, "Unable to execute logging shell script: %s", sname); + return; + } + /* read and forget the result */ + while (1) { + int readbytes = fread(cmd, 1, sizeof(cmd), in); + if (readbytes<=0) { + break; + } + } + pclose(in); + } +log_phpscript: + if ((SUHOSIN_G(log_phpscript) & loglevel)!=0 && EG(in_execution) && SUHOSIN_G(log_phpscriptname) && SUHOSIN_G(log_phpscriptname)[0]) { + zend_file_handle file_handle; + zend_op_array *new_op_array; + zval *result = NULL; + + long orig_execution_depth = SUHOSIN_G(execution_depth); + zend_bool orig_safe_mode = PG(safe_mode); + char *orig_basedir = PG(open_basedir); + + char *phpscript = SUHOSIN_G(log_phpscriptname); +SDEBUG("scriptname %s", SUHOSIN_G(log_phpscriptname)); +#ifdef ZEND_ENGINE_2 + if (zend_stream_open(phpscript, &file_handle TSRMLS_CC) == SUCCESS) { +#else + if (zend_open(phpscript, &file_handle) == SUCCESS && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) { + file_handle.filename = phpscript; + file_handle.free_filename = 0; +#endif + if (!file_handle.opened_path) { + file_handle.opened_path = estrndup(phpscript, strlen(phpscript)); + } + new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC); + zend_destroy_file_handle(&file_handle TSRMLS_CC); + if (new_op_array) { + HashTable *active_symbol_table = EG(active_symbol_table); + zval *zerror, *zerror_class; + + if (active_symbol_table == NULL) { + active_symbol_table = &EG(symbol_table); + } + EG(return_value_ptr_ptr) = &result; + EG(active_op_array) = new_op_array; + + MAKE_STD_ZVAL(zerror); + MAKE_STD_ZVAL(zerror_class); + ZVAL_STRING(zerror, buf, 1); + ZVAL_LONG(zerror_class, loglevel); + + zend_hash_update(active_symbol_table, "SUHOSIN_ERROR", sizeof("SUHOSIN_ERROR"), (void **)&zerror, sizeof(zval *), NULL); + zend_hash_update(active_symbol_table, "SUHOSIN_ERRORCLASS", sizeof("SUHOSIN_ERRORCLASS"), (void **)&zerror_class, sizeof(zval *), NULL); + + SUHOSIN_G(execution_depth) = 0; + if (SUHOSIN_G(log_phpscript_is_safe)) { + PG(safe_mode) = 0; + PG(open_basedir) = NULL; + } + + zend_execute(new_op_array TSRMLS_CC); + + SUHOSIN_G(execution_depth) = orig_execution_depth; + PG(safe_mode) = orig_safe_mode; + PG(open_basedir) = orig_basedir; + +#ifdef ZEND_ENGINE_2 + destroy_op_array(new_op_array TSRMLS_CC); +#else + destroy_op_array(new_op_array); +#endif + efree(new_op_array); +#ifdef ZEND_ENGINE_2 + if (!EG(exception)) +#endif + { + if (EG(return_value_ptr_ptr)) { + zval_ptr_dtor(EG(return_value_ptr_ptr)); + EG(return_value_ptr_ptr) = NULL; + } + } + } else { + suhosin_log(S_INTERNAL, "Unable to execute logging PHP script: %s", SUHOSIN_G(log_phpscriptname)); + return; + } + } else { + suhosin_log(S_INTERNAL, "Unable to execute logging PHP script: %s", SUHOSIN_G(log_phpscriptname)); + return; + } + } + +} + + +/* + * 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 --git a/mbregex.h b/mbregex.h new file mode 100644 index 0000000..014f002 --- /dev/null +++ b/mbregex.h @@ -0,0 +1,26 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: mbregex.h,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ */ + +#if HAVE_MBREGEX + +#include "mbregex/mbregex.h" + +#endif \ No newline at end of file diff --git a/mbregex/COPYING.LIB b/mbregex/COPYING.LIB new file mode 100644 index 0000000..c4792dd --- /dev/null +++ b/mbregex/COPYING.LIB @@ -0,0 +1,515 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. +^L + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. +^L + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. +^L + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. +^L + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. +^L + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. +^L + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. +^L + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS +^L + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper +mail. + +You should also get your employer (if you work as a programmer) or +your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James +Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/mbregex/mbregex.h b/mbregex/mbregex.h new file mode 100644 index 0000000..03292bc --- /dev/null +++ b/mbregex/mbregex.h @@ -0,0 +1,213 @@ +/* Definitions for data structures and routines for the regular + expression library, version 0.12. + Copyright (C) 1985,89,90,91,92,93,95,96,97,98 Free Software Foundation, Inc. + + This file is part of the GNU C Library. Its master source is NOT part of + the C library, however. The master source lives in /gd/gnu/lib. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ +/* Multi-byte extension added May, 1993 by t^2 (Takahiro Tanimoto) + Last change: May 21, 1993 by t^2 */ +/* modified for Ruby by matz@netlab.co.jp */ + +#ifndef __MB_REGEXP_LIBRARY +#define __MB_REGEXP_LIBRARY + +#include + +/* Define number of parens for which we record the beginnings and ends. + This affects how much space the `struct re_registers' type takes up. */ +#ifndef MBRE_NREGS +#define MBRE_NREGS 10 +#endif + +#define MBRE_BYTEWIDTH 8 + +#define MBRE_REG_MAX ((1< | + +----------------------------------------------------------------------+ +*/ +/* + $Id: memory_limit.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "php_suhosin.h" + + +/* {{{ PHP_INI_MH + */ +static PHP_INI_MH(suhosin_OnChangeMemoryLimit) +{ + long hard_memory_limit = 1<<30; + + if (stage == ZEND_INI_STAGE_RUNTIME) { + if (SUHOSIN_G(memory_limit) > 0) { + SUHOSIN_G(hard_memory_limit) = SUHOSIN_G(memory_limit); + } else if (SUHOSIN_G(hard_memory_limit) == 0) { + SUHOSIN_G(hard_memory_limit) = PG(memory_limit); + } + hard_memory_limit = SUHOSIN_G(hard_memory_limit); + } else { + SUHOSIN_G(hard_memory_limit) = 0; + } + if (new_value) { + PG(memory_limit) = zend_atoi(new_value, new_value_length); + if (PG(memory_limit) > hard_memory_limit || PG(memory_limit) < 0) { + suhosin_log(S_MISC, "script tried to increase memory_limit to %u bytes which is above the allowed value", PG(memory_limit)); + if (!SUHOSIN_G(simulation)) { + PG(memory_limit) = hard_memory_limit; + return FAILURE; + } + } + } else { + PG(memory_limit) = hard_memory_limit; + } + return zend_set_memory_limit(PG(memory_limit)); +} +/* }}} */ + + +void suhosin_hook_memory_limit() +{ + zend_ini_entry *ini_entry; + TSRMLS_FETCH(); + + /* check if we are compiled against memory_limit */ + if (zend_hash_find(EG(ini_directives), "memory_limit", sizeof("memory_limit"), (void **) &ini_entry)==FAILURE) { + return; + } + + /* replace OnUpdateMemoryLimit handler */ + ini_entry->on_modify = suhosin_OnChangeMemoryLimit; +} + + +/* + * 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 --git a/php_suhosin.h b/php_suhosin.h new file mode 100644 index 0000000..56869ec --- /dev/null +++ b/php_suhosin.h @@ -0,0 +1,420 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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_suhosin.h,v 1.4 2008-01-13 22:50:37 sesser Exp $ */ + +#ifndef PHP_SUHOSIN_H +#define PHP_SUHOSIN_H + +#define SUHOSIN_EXT_VERSION "0.9.29" + +/*#define SUHOSIN_DEBUG*/ +#define SUHOSIN_LOG "/tmp/suhosin_log.txt" + +#ifdef PHP_WIN32 +#define SDEBUG +#else + +#ifdef SUHOSIN_DEBUG +#define SDEBUG(msg...) \ + {FILE *f;f=fopen(SUHOSIN_LOG, "a+");if(f){fprintf(f,"[%u] ",getpid());fprintf(f, msg);fprintf(f,"\n");fclose(f);}} +#else +#define SDEBUG(...) +#endif +#endif + +extern zend_module_entry suhosin_module_entry; +#define phpext_suhosin_ptr &suhosin_module_entry + +#ifdef PHP_WIN32 +#define PHP_SUHOSIN_API __declspec(dllexport) +#else +#define PHP_SUHOSIN_API +#endif + +#ifdef ZTS +#include "TSRM.h" +#endif + +/*#define STATIC static*/ +#define STATIC + +#define BYTE unsigned char /* 8 bits */ +#define WORD unsigned int /* 32 bits */ + +PHP_MINIT_FUNCTION(suhosin); +PHP_MSHUTDOWN_FUNCTION(suhosin); +PHP_RINIT_FUNCTION(suhosin); +PHP_RSHUTDOWN_FUNCTION(suhosin); +PHP_MINFO_FUNCTION(suhosin); + +#include "ext/standard/basic_functions.h" + +ZEND_BEGIN_MODULE_GLOBALS(suhosin) + zend_uint in_code_type; + long execution_depth; + zend_bool simulation; + zend_bool stealth; + zend_bool protectkey; + zend_bool executor_allow_symlink; + char *filter_action; + char *sql_user_prefix; + char *sql_user_postfix; + long sql_comment; + long sql_opencomment; + long sql_union; + long sql_mselect; + + long max_execution_depth; + zend_bool abort_request; + long executor_include_max_traversal; + zend_bool executor_include_allow_writable_files; + + + HashTable *include_whitelist; + HashTable *include_blacklist; + + HashTable *func_whitelist; + HashTable *func_blacklist; + HashTable *eval_whitelist; + HashTable *eval_blacklist; + + zend_bool executor_disable_eval; + zend_bool executor_disable_emod; + + +/* 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; + zend_bool disallow_nul; + zend_bool disallow_ws; +/* 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; + zend_bool disallow_cookie_nul; + zend_bool disallow_cookie_ws; +/* 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; + zend_bool disallow_get_nul; + zend_bool disallow_get_ws; +/* 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; + zend_bool disallow_post_nul; + zend_bool disallow_post_ws; + +/* fileupload */ + long upload_limit; + long num_uploads; + zend_bool upload_disallow_elf; + zend_bool upload_disallow_binary; + zend_bool upload_remove_binary; + char *upload_verification_script; + + zend_bool no_more_variables; + zend_bool no_more_get_variables; + zend_bool no_more_post_variables; + zend_bool no_more_cookie_variables; + zend_bool no_more_uploads; + + + +/* log */ + zend_bool log_use_x_forwarded_for; + long log_syslog; + long log_syslog_facility; + long log_syslog_priority; + long log_script; + long log_sapi; + char *log_scriptname; + long log_phpscript; + char *log_phpscriptname; + zend_bool log_phpscript_is_safe; + long log_file; + char *log_filename; + +/* header handler */ + zend_bool allow_multiheader; + +/* mailprotect */ + long mailprotect; + +/* memory_limit */ + long memory_limit; + long hard_memory_limit; + +/* sqlprotect */ + zend_bool sql_bailout_on_error; + + int (*old_php_body_write)(const char *str, unsigned int str_length TSRMLS_DC); + +/* session */ + void *s_module; + int (*old_s_read)(void **mod_data, const char *key, char **val, int *vallen TSRMLS_DC); + int (*old_s_write)(void **mod_data, const char *key, const char *val, const int vallen TSRMLS_DC); + int (*old_s_destroy)(void **mod_data, const char *key TSRMLS_DC); + + BYTE fi[24],ri[24]; + WORD fkey[120]; + WORD rkey[120]; + + zend_bool session_encrypt; + char* session_cryptkey; + zend_bool session_cryptua; + zend_bool session_cryptdocroot; + long session_cryptraddr; + long session_checkraddr; + + long session_max_id_length; + + char* decrypted_cookie; + char* raw_cookie; + zend_bool cookie_encrypt; + char* cookie_cryptkey; + zend_bool cookie_cryptua; + zend_bool cookie_cryptdocroot; + long cookie_cryptraddr; + long cookie_checkraddr; + HashTable *cookie_plainlist; + HashTable *cookie_cryptlist; + + zend_bool coredump; + zend_bool apc_bug_workaround; + zend_bool already_scanned; + zend_bool do_not_scan; + + zend_bool server_encode; + zend_bool server_strip; + + zend_bool disable_display_errors; + + php_uint32 r_state[625]; + php_uint32 *r_next; + int r_left; + zend_bool srand_ignore; + zend_bool mt_srand_ignore; + php_uint32 mt_state[625]; + php_uint32 *mt_next; + int mt_left; + + zend_bool r_is_seeded; + zend_bool mt_is_seeded; + + /* PERDIR Handling */ + char *perdir; + zend_bool log_perdir; + zend_bool exec_perdir; + zend_bool get_perdir; + zend_bool post_perdir; + zend_bool cookie_perdir; + zend_bool request_perdir; + zend_bool upload_perdir; + zend_bool sql_perdir; + zend_bool misc_perdir; + +ZEND_END_MODULE_GLOBALS(suhosin) + +#ifdef ZTS +#define SUHOSIN_G(v) TSRMG(suhosin_globals_id, zend_suhosin_globals *, v) +#else +#define SUHOSIN_G(v) (suhosin_globals.v) +#endif + +#ifndef ZEND_INI_STAGE_HTACCESS +#define ZEND_INI_STAGE_HTACCESS (1<<5) +#endif + +#ifndef ZEND_ENGINE_2 +#define OnUpdateLong OnUpdateInt +#define zend_symtable_find zend_hash_find +#define zend_symtable_update zend_hash_update +#define zend_symtable_exists zend_hash_exists +#endif + + +/* Error Constants */ +#ifndef S_MEMORY +#define S_MEMORY (1<<0L) +#define S_MISC (1<<1L) +#define S_VARS (1<<2L) +#define S_FILES (1<<3L) +#define S_INCLUDE (1<<4L) +#define S_SQL (1<<5L) +#define S_EXECUTOR (1<<6L) +#define S_MAIL (1<<7L) +#define S_SESSION (1<<8L) +#define S_INTERNAL (1<<29L) +#define S_ALL (S_MEMORY | S_VARS | S_INCLUDE | S_FILES | S_MAIL | S_SESSION | S_MISC | S_SQL | S_EXECUTOR) +#endif + +#define SUHOSIN_NORMAL 0 +#define SUHOSIN_EVAL 1 + +#define SUHOSIN_FLAG_CREATED_BY_EVAL 1 +#define SUHOSIN_FLAG_NOT_EVALED_CODE 2 + +ZEND_EXTERN_MODULE_GLOBALS(suhosin) + +static inline char * +suhosin_str_tolower_dup(const char *source, unsigned int length) +{ + register char *dup = estrndup(source, length); + zend_str_tolower(dup, length); + return dup; +} + +/* functions */ +PHP_SUHOSIN_API void suhosin_log(int loglevel, char *fmt, ...); +char *suhosin_encrypt_string(char *str, int len, char *var, int vlen, char *key TSRMLS_DC); +char *suhosin_decrypt_string(char *str, int padded_len, char *var, int vlen, char *key, int *orig_len, int check_ra TSRMLS_DC); +char *suhosin_generate_key(char *key, zend_bool ua, zend_bool dr, long raddr, char *cryptkey TSRMLS_DC); +char *suhosin_cookie_decryptor(TSRMLS_D); +void suhosin_hook_post_handlers(TSRMLS_D); +void suhosin_hook_register_server_variables(); +void suhosin_hook_header_handler(); +void suhosin_unhook_header_handler(); +void suhosin_hook_session(TSRMLS_D); +void suhosin_unhook_session(TSRMLS_D); +void suhosin_hook_crypt(); +void suhosin_hook_sha256(); +void suhosin_hook_ex_imp(); +void suhosin_hook_treat_data(); +void suhosin_hook_memory_limit(); +void suhosin_hook_execute(TSRMLS_D); +void suhosin_unhook_execute(); +void suhosin_aes_gentables(); +void suhosin_aes_gkey(int nb,int nk,char *key TSRMLS_DC); +void suhosin_aes_encrypt(char *buff TSRMLS_DC); +void suhosin_aes_decrypt(char *buff TSRMLS_DC); +unsigned int suhosin_input_filter(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); +unsigned int suhosin_input_filter_wrapper(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); +extern unsigned int (*old_input_filter)(int arg, char *var, char **val, unsigned int val_len, unsigned int *new_val_len TSRMLS_DC); +void normalize_varname(char *varname); +int suhosin_rfc1867_filter(unsigned int event, void *event_data, void **extra TSRMLS_DC); +void suhosin_bailout(TSRMLS_D); + +/* Add pseudo refcount macros for PHP version < 5.3 */ +#ifndef Z_REFCOUNT_PP + +#define Z_REFCOUNT_PP(ppz) Z_REFCOUNT_P(*(ppz)) +#define Z_SET_REFCOUNT_PP(ppz, rc) Z_SET_REFCOUNT_P(*(ppz), rc) +#define Z_ADDREF_PP(ppz) Z_ADDREF_P(*(ppz)) +#define Z_DELREF_PP(ppz) Z_DELREF_P(*(ppz)) +#define Z_ISREF_PP(ppz) Z_ISREF_P(*(ppz)) +#define Z_SET_ISREF_PP(ppz) Z_SET_ISREF_P(*(ppz)) +#define Z_UNSET_ISREF_PP(ppz) Z_UNSET_ISREF_P(*(ppz)) +#define Z_SET_ISREF_TO_PP(ppz, isref) Z_SET_ISREF_TO_P(*(ppz), isref) + +#define Z_REFCOUNT_P(pz) zval_refcount_p(pz) +#define Z_SET_REFCOUNT_P(pz, rc) zval_set_refcount_p(pz, rc) +#define Z_ADDREF_P(pz) zval_addref_p(pz) +#define Z_DELREF_P(pz) zval_delref_p(pz) +#define Z_ISREF_P(pz) zval_isref_p(pz) +#define Z_SET_ISREF_P(pz) zval_set_isref_p(pz) +#define Z_UNSET_ISREF_P(pz) zval_unset_isref_p(pz) +#define Z_SET_ISREF_TO_P(pz, isref) zval_set_isref_to_p(pz, isref) + +#define Z_REFCOUNT(z) Z_REFCOUNT_P(&(z)) +#define Z_SET_REFCOUNT(z, rc) Z_SET_REFCOUNT_P(&(z), rc) +#define Z_ADDREF(z) Z_ADDREF_P(&(z)) +#define Z_DELREF(z) Z_DELREF_P(&(z)) +#define Z_ISREF(z) Z_ISREF_P(&(z)) +#define Z_SET_ISREF(z) Z_SET_ISREF_P(&(z)) +#define Z_UNSET_ISREF(z) Z_UNSET_ISREF_P(&(z)) +#define Z_SET_ISREF_TO(z, isref) Z_SET_ISREF_TO_P(&(z), isref) + +#if defined(__GNUC__) +#define zend_always_inline inline __attribute__((always_inline)) +#elif defined(_MSC_VER) +#define zend_always_inline __forceinline +#else +#define zend_always_inline inline +#endif + +static zend_always_inline zend_uint zval_refcount_p(zval* pz) { + return pz->refcount; +} + +static zend_always_inline zend_uint zval_set_refcount_p(zval* pz, zend_uint rc) { + return pz->refcount = rc; +} + +static zend_always_inline zend_uint zval_addref_p(zval* pz) { + return ++pz->refcount; +} + +static zend_always_inline zend_uint zval_delref_p(zval* pz) { + return --pz->refcount; +} + +static zend_always_inline zend_bool zval_isref_p(zval* pz) { + return pz->is_ref; +} + +static zend_always_inline zend_bool zval_set_isref_p(zval* pz) { + return pz->is_ref = 1; +} + +static zend_always_inline zend_bool zval_unset_isref_p(zval* pz) { + return pz->is_ref = 0; +} + +static zend_always_inline zend_bool zval_set_isref_to_p(zval* pz, zend_bool isref) { + return pz->is_ref = isref; +} + +#else + +#define PHP_ATLEAST_5_3 true + +#endif + + +#endif /* PHP_SUHOSIN_H */ + + +/* + * 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 --git a/post_handler.c b/post_handler.c new file mode 100644 index 0000000..a7ac060 --- /dev/null +++ b/post_handler.c @@ -0,0 +1,114 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: post_handler.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "php_suhosin.h" +#include "SAPI.h" +#include "php_variables.h" +#include "php_content_types.h" +#include "suhosin_rfc1867.h" +#include "ext/standard/url.h" + +SAPI_POST_HANDLER_FUNC(suhosin_rfc1867_post_handler); + + +SAPI_POST_HANDLER_FUNC(suhosin_std_post_handler) +{ + char *var, *val, *e, *s, *p; + zval *array_ptr = (zval *) arg; + + if (SG(request_info).post_data==NULL) { + return; + } + + s = SG(request_info).post_data; + e = s + SG(request_info).post_data_length; + + while (s < e && (p = memchr(s, '&', (e - s)))) { +last_value: + if ((val = memchr(s, '=', (p - s)))) { /* have a value */ + unsigned int val_len, new_val_len; + var = s; + + php_url_decode(var, (val - s)); + val++; + val_len = php_url_decode(val, (p - val)); + val = estrndup(val, val_len); + if (suhosin_input_filter(PARSE_POST, var, &val, val_len, &new_val_len TSRMLS_CC)) { +#ifdef ZEND_ENGINE_2 + if (sapi_module.input_filter(PARSE_POST, var, &val, new_val_len, &new_val_len TSRMLS_CC)) { +#endif + php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); +#ifdef ZEND_ENGINE_2 + } +#endif + } else { + SUHOSIN_G(abort_request)=1; + } + efree(val); + } + s = p + 1; + } + if (s < e) { + p = e; + goto last_value; + } +} + +/* {{{ php_post_entries[] + */ +static sapi_post_entry suhosin_post_entries[] = { + { DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data, suhosin_std_post_handler }, + { MULTIPART_CONTENT_TYPE, sizeof(MULTIPART_CONTENT_TYPE)-1, NULL, suhosin_rfc1867_post_handler }, + { NULL, 0, NULL, NULL } +}; +/* }}} */ + +void suhosin_hook_post_handlers(TSRMLS_D) +{ +#if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0) + sapi_unregister_post_entry(&suhosin_post_entries[0] TSRMLS_CC); + sapi_unregister_post_entry(&suhosin_post_entries[1] TSRMLS_CC); + sapi_register_post_entries(suhosin_post_entries TSRMLS_CC); +#else + sapi_unregister_post_entry(&suhosin_post_entries[0]); + sapi_unregister_post_entry(&suhosin_post_entries[1]); + sapi_register_post_entries(suhosin_post_entries); +#endif +} + + +/* + * 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 --git a/rfc1867.c b/rfc1867.c new file mode 100644 index 0000000..9e819c2 --- /dev/null +++ b/rfc1867.c @@ -0,0 +1,1355 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2006 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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. | + +----------------------------------------------------------------------+ + | Authors: Rasmus Lerdorf | + | Jani Taskinen | + +----------------------------------------------------------------------+ + */ + +/* $Id: rfc1867.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ */ + +/* + * This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/). + * + */ + +#include +#include "php.h" +#include "php_open_temporary_file.h" +#include "zend_globals.h" +#include "php_globals.h" +#include "php_variables.h" +#include "php_suhosin.h" +#include "suhosin_rfc1867.h" + +#define DEBUG_FILE_UPLOAD ZEND_DEBUG + +#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) +#include "ext/mbstring/mbstring.h" + +static void safe_php_register_variable(char *var, char *strval, zval *track_vars_array, zend_bool override_protection TSRMLS_DC); + +#define SAFE_RETURN { \ + php_mb_flush_gpc_variables(num_vars, val_list, len_list, array_ptr TSRMLS_CC); \ + if (lbuf) efree(lbuf); \ + if (abuf) efree(abuf); \ + if (array_index) efree(array_index); \ + zend_hash_destroy(&PG(rfc1867_protected_variables)); \ + zend_llist_destroy(&header); \ + if (mbuff->boundary_next) efree(mbuff->boundary_next); \ + if (mbuff->boundary) efree(mbuff->boundary); \ + if (mbuff->buffer) efree(mbuff->buffer); \ + if (mbuff) efree(mbuff); \ + return; } + +static void php_mb_flush_gpc_variables(int num_vars, char **val_list, int *len_list, zval *array_ptr TSRMLS_DC) +{ + int i; + if (php_mb_encoding_translation(TSRMLS_C)) { + if (num_vars > 0 && + php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) { + php_mb_gpc_encoding_converter(val_list, len_list, num_vars, NULL, NULL TSRMLS_CC); + } + for (i=0; i=*num_vars_max){ + php_mb_gpc_realloc_buffer(pval_list, plen_list, num_vars_max, + 16 TSRMLS_CC); + /* in case realloc relocated the buffer */ + val_list = *pval_list; + len_list = *plen_list; + } + + val_list[*num_vars] = (char *)estrdup(param); + len_list[*num_vars] = strlen(param); + (*num_vars)++; + val_list[*num_vars] = (char *)estrdup(value); + len_list[*num_vars] = strlen(value); + (*num_vars)++; +} + +#else + +#define SAFE_RETURN { \ + if (lbuf) efree(lbuf); \ + if (abuf) efree(abuf); \ + if (array_index) efree(array_index); \ + zend_hash_destroy(&PG(rfc1867_protected_variables)); \ + zend_llist_destroy(&header); \ + if (mbuff->boundary_next) efree(mbuff->boundary_next); \ + if (mbuff->boundary) efree(mbuff->boundary); \ + if (mbuff->buffer) efree(mbuff->buffer); \ + if (mbuff) efree(mbuff); \ + return; } +#endif + +/* The longest property name we use in an uploaded file array */ +#define MAX_SIZE_OF_INDEX sizeof("[tmp_name]") + +/* The longest anonymous name */ +#define MAX_SIZE_ANONNAME 33 + +/* Errors */ +#define UPLOAD_ERROR_OK 0 /* File upload succesful */ +#define UPLOAD_ERROR_A 1 /* Uploaded file exceeded upload_max_filesize */ +#define UPLOAD_ERROR_B 2 /* Uploaded file exceeded MAX_FILE_SIZE */ +#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 /* Failed to write file to disk */ +#define UPLOAD_ERROR_X 8 /* File upload stopped by extension */ + +/* +void php_rfc1867_register_constants(TSRMLS_D) +{ + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_OK", UPLOAD_ERROR_OK, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_INI_SIZE", UPLOAD_ERROR_A, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FORM_SIZE", UPLOAD_ERROR_B, CONST_CS | CONST_PERSISTENT); + 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_CANT_WRITE", UPLOAD_ERROR_F, CONST_CS | CONST_PERSISTENT); + REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_EXTENSION", UPLOAD_ERROR_X, CONST_CS | CONST_PERSISTENT); +} +*/ + +static void normalize_protected_variable(char *varname TSRMLS_DC) +{ + 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'; +} + + +static void add_protected_variable(char *varname TSRMLS_DC) +{ + int dummy=1; + + normalize_protected_variable(varname TSRMLS_CC); + zend_hash_add(&PG(rfc1867_protected_variables), varname, strlen(varname)+1, &dummy, sizeof(int), NULL); +} + + +static zend_bool is_protected_variable(char *varname TSRMLS_DC) +{ + normalize_protected_variable(varname TSRMLS_CC); + return zend_hash_exists(&PG(rfc1867_protected_variables), varname, strlen(varname)+1); +} + + +static void safe_php_register_variable(char *var, char *strval, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) +{ + if (override_protection || !is_protected_variable(var TSRMLS_CC)) { + php_register_variable(var, strval, track_vars_array TSRMLS_CC); + } +} + + +static void safe_php_register_variable_ex(char *var, zval *val, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) +{ + if (override_protection || !is_protected_variable(var TSRMLS_CC)) { + php_register_variable_ex(var, val, track_vars_array TSRMLS_CC); + } +} + + +static void register_http_post_files_variable(char *strvar, char *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) +{ + int register_globals = PG(register_globals); + + PG(register_globals) = 0; + safe_php_register_variable(strvar, val, http_post_files, override_protection TSRMLS_CC); + PG(register_globals) = register_globals; +} + + +static void register_http_post_files_variable_ex(char *var, zval *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) +{ + int register_globals = PG(register_globals); + + PG(register_globals) = 0; + safe_php_register_variable_ex(var, val, http_post_files, override_protection TSRMLS_CC); + PG(register_globals) = register_globals; +} + +/* + * Following code is based on apache_multipart_buffer.c from libapreq-0.33 package. + * + */ + +#define FILLUNIT (1024 * 5) + +typedef struct { + + /* read buffer */ + char *buffer; + char *buf_begin; + int bufsize; + int bytes_in_buffer; + + /* boundary info */ + char *boundary; + char *boundary_next; + int boundary_next_len; + +} multipart_buffer; + + +typedef struct { + char *key; + char *value; +} mime_header_entry; + + +/* + fill up the buffer with client data. + returns number of bytes added to buffer. +*/ +static int fill_buffer(multipart_buffer *self TSRMLS_DC) +{ + int bytes_to_read, total_read = 0, actual_read = 0; + + /* shift the existing data if necessary */ + if (self->bytes_in_buffer > 0 && self->buf_begin != self->buffer) { + memmove(self->buffer, self->buf_begin, self->bytes_in_buffer); + } + + self->buf_begin = self->buffer; + + /* calculate the free space in the buffer */ + bytes_to_read = self->bufsize - self->bytes_in_buffer; + + /* read the required number of bytes */ + while (bytes_to_read > 0) { + + char *buf = self->buffer + self->bytes_in_buffer; + + actual_read = sapi_module.read_post(buf, bytes_to_read TSRMLS_CC); + + /* update the buffer length */ + if (actual_read > 0) { + self->bytes_in_buffer += actual_read; + SG(read_post_bytes) += actual_read; + total_read += actual_read; + bytes_to_read -= actual_read; + } else { + break; + } + } + + return total_read; +} + + +/* eof if we are out of bytes, or if we hit the final boundary */ +static int multipart_buffer_eof(multipart_buffer *self TSRMLS_DC) +{ + if ( (self->bytes_in_buffer == 0 && fill_buffer(self TSRMLS_CC) < 1) ) { + return 1; + } else { + return 0; + } +} + + +/* create new multipart_buffer structure */ +static multipart_buffer *multipart_buffer_new(char *boundary, int boundary_len) +{ + multipart_buffer *self = (multipart_buffer *) ecalloc(1, sizeof(multipart_buffer)); + + int minsize = boundary_len + 6; + if (minsize < FILLUNIT) minsize = FILLUNIT; + + self->buffer = (char *) ecalloc(1, minsize + 1); + self->bufsize = minsize; + + self->boundary = (char *) ecalloc(1, boundary_len + 3); + sprintf(self->boundary, "--%s", boundary); + + self->boundary_next = (char *) ecalloc(1, boundary_len + 4); + sprintf(self->boundary_next, "\n--%s", boundary); + self->boundary_next_len = boundary_len + 3; + + self->buf_begin = self->buffer; + self->bytes_in_buffer = 0; + + return self; +} + + +/* + gets the next CRLF terminated line from the input buffer. + if it doesn't find a CRLF, and the buffer isn't completely full, returns + NULL; otherwise, returns the beginning of the null-terminated line, + minus the CRLF. + + note that we really just look for LF terminated lines. this works + around a bug in internet explorer for the macintosh which sends mime + boundaries that are only LF terminated when you use an image submit + button in a multipart/form-data form. + */ +static char *next_line(multipart_buffer *self) +{ + /* look for LF in the data */ + char* line = self->buf_begin; + char* ptr = memchr(self->buf_begin, '\n', self->bytes_in_buffer); + + if (ptr) { /* LF found */ + + /* terminate the string, remove CRLF */ + if ((ptr - line) > 0 && *(ptr-1) == '\r') { + *(ptr-1) = 0; + } else { + *ptr = 0; + } + + /* bump the pointer */ + self->buf_begin = ptr + 1; + self->bytes_in_buffer -= (self->buf_begin - line); + + } else { /* no LF found */ + + /* buffer isn't completely full, fail */ + if (self->bytes_in_buffer < self->bufsize) { + return NULL; + } + /* return entire buffer as a partial line */ + line[self->bufsize] = 0; + self->buf_begin = ptr; + self->bytes_in_buffer = 0; + } + + return line; +} + + +/* returns the next CRLF terminated line from the client */ +static char *get_line(multipart_buffer *self TSRMLS_DC) +{ + char* ptr = next_line(self); + + if (!ptr) { + fill_buffer(self TSRMLS_CC); + ptr = next_line(self); + } + + return ptr; +} + + +/* Free header entry */ +static void php_free_hdr_entry(mime_header_entry *h) +{ + if (h->key) { + efree(h->key); + } + if (h->value) { + efree(h->value); + } +} + + +/* finds a boundary */ +static int find_boundary(multipart_buffer *self, char *boundary TSRMLS_DC) +{ + char *line; + + /* loop thru lines */ + while( (line = get_line(self TSRMLS_CC)) ) + { + /* finished if we found the boundary */ + if (!strcmp(line, boundary)) { + return 1; + } + } + + /* didn't find the boundary */ + return 0; +} + + +/* parse headers */ +static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header TSRMLS_DC) +{ + char *line; + mime_header_entry prev_entry, entry; + int prev_len, cur_len; + + /* didn't find boundary, abort */ + if (!find_boundary(self, self->boundary TSRMLS_CC)) { + return 0; + } + + /* get lines of text, or CRLF_CRLF */ + + while( (line = get_line(self TSRMLS_CC)) && strlen(line) > 0 ) + { + /* add header to table */ + + char *key = line; + char *value = NULL; + + /* space in the beginning means same header */ + if (!isspace(line[0])) { + value = strchr(line, ':'); + } + + if (value) { + *value = 0; + do { value++; } while(isspace(*value)); + + entry.value = estrdup(value); + entry.key = estrdup(key); + + } else if (zend_llist_count(header)) { /* If no ':' on the line, add to previous line */ + + prev_len = strlen(prev_entry.value); + cur_len = strlen(line); + + entry.value = emalloc(prev_len + cur_len + 1); + memcpy(entry.value, prev_entry.value, prev_len); + memcpy(entry.value + prev_len, line, cur_len); + entry.value[cur_len + prev_len] = '\0'; + + entry.key = estrdup(prev_entry.key); + + zend_llist_remove_tail(header); + } else { + continue; + } + + zend_llist_add_element(header, &entry); + prev_entry = entry; + } + + return 1; +} + + +static char *php_mime_get_hdr_value(zend_llist header, char *key) +{ + mime_header_entry *entry; + + if (key == NULL) { + return NULL; + } + + entry = zend_llist_get_first(&header); + while (entry) { + if (!strcasecmp(entry->key, key)) { + return entry->value; + } + entry = zend_llist_get_next(&header); + } + + return NULL; +} + + +static char *php_ap_getword(char **line, char stop) +{ + char *pos = *line, quote; + char *res; + + while (*pos && *pos != stop) { + + if ((quote = *pos) == '"' || quote == '\'') { + ++pos; + while (*pos && *pos != quote) { + if (*pos == '\\' && pos[1] && pos[1] == quote) { + pos += 2; + } else { + ++pos; + } + } + if (*pos) { + ++pos; + } + } else ++pos; + + } + if (*pos == '\0') { + res = estrdup(*line); + *line += strlen(*line); + return res; + } + + res = estrndup(*line, pos - *line); + + while (*pos == stop) { + ++pos; + } + + *line = pos; + return res; +} + + +static char *substring_conf(char *start, int len, char quote TSRMLS_DC) +{ + char *result = emalloc(len + 2); + char *resp = result; + int i; + + for (i = 0; i < len; ++i) { + if (start[i] == '\\' && (start[i + 1] == '\\' || (quote && start[i + 1] == quote))) { + *resp++ = start[++i]; + } else { +#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) + if (php_mb_encoding_translation(TSRMLS_C)) { + size_t j = php_mb_gpc_mbchar_bytes(start+i TSRMLS_CC); + while (j-- > 0 && i < len) { + *resp++ = start[i++]; + } + --i; + } else { + *resp++ = start[i]; + } +#else + *resp++ = start[i]; +#endif + } + } + + *resp++ = '\0'; + return result; +} + + +static char *php_ap_getword_conf(char **line TSRMLS_DC) +{ + char *str = *line, *strend, *res, quote; + +#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) + if (php_mb_encoding_translation(TSRMLS_C)) { + int len=strlen(str); + php_mb_gpc_encoding_detector(&str, &len, 1, NULL TSRMLS_CC); + } +#endif + + while (*str && isspace(*str)) { + ++str; + } + + if (!*str) { + *line = str; + return estrdup(""); + } + + if ((quote = *str) == '"' || quote == '\'') { + strend = str + 1; +look_for_quote: + while (*strend && *strend != quote) { + if (*strend == '\\' && strend[1] && strend[1] == quote) { + strend += 2; + } else { + ++strend; + } + } + if (*strend && *strend == quote) { + char p = *(strend + 1); + if (p != '\r' && p != '\n' && p != '\0') { + strend++; + goto look_for_quote; + } + } + + res = substring_conf(str + 1, strend - str - 1, quote TSRMLS_CC); + + if (*strend == quote) { + ++strend; + } + + } else { + + strend = str; + while (*strend && !isspace(*strend)) { + ++strend; + } + res = substring_conf(str, strend - str, 0 TSRMLS_CC); + } + + while (*strend && isspace(*strend)) { + ++strend; + } + + *line = strend; + return res; +} + + +/* + search for a string in a fixed-length byte string. + if partial is true, partial matches are allowed at the end of the buffer. + returns NULL if not found, or a pointer to the start of the first match. +*/ +static void *php_ap_memstr(char *haystack, int haystacklen, char *needle, int needlen, int partial) +{ + int len = haystacklen; + char *ptr = haystack; + + /* iterate through first character matches */ + while( (ptr = memchr(ptr, needle[0], len)) ) { + + /* calculate length after match */ + len = haystacklen - (ptr - (char *)haystack); + + /* done if matches up to capacity of buffer */ + if (memcmp(needle, ptr, needlen < len ? needlen : len) == 0 && (partial || len >= needlen)) { + break; + } + + /* next character */ + ptr++; len--; + } + + return ptr; +} + + +/* read until a boundary condition */ +static int multipart_buffer_read(multipart_buffer *self, char *buf, int bytes, int *end TSRMLS_DC) +{ + int len, max; + char *bound; + + /* fill buffer if needed */ + if (bytes > self->bytes_in_buffer) { + fill_buffer(self TSRMLS_CC); + } + + /* look for a potential boundary match, only read data up to that point */ + if ((bound = php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 1))) { + max = bound - self->buf_begin; + if (end && php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 0)) { + *end = 1; + } + } else { + max = self->bytes_in_buffer; + } + + /* maximum number of bytes we are reading */ + len = max < bytes-1 ? max : bytes-1; + + /* if we read any data... */ + if (len > 0) { + + /* copy the data */ + memcpy(buf, self->buf_begin, len); + buf[len] = 0; + + if (bound && len > 0 && buf[len-1] == '\r') { + buf[--len] = 0; + } + + /* update the buffer */ + self->bytes_in_buffer -= len; + self->buf_begin += len; + } + + return len; +} + + +/* + XXX: this is horrible memory-usage-wise, but we only expect + to do this on small pieces of form data. +*/ +static char *multipart_buffer_read_body(multipart_buffer *self, unsigned int *len TSRMLS_DC) +{ + char buf[FILLUNIT], *out=NULL; + int total_bytes=0, read_bytes=0; + + while((read_bytes = multipart_buffer_read(self, buf, sizeof(buf), NULL TSRMLS_CC))) { + out = erealloc(out, total_bytes + read_bytes + 1); + memcpy(out + total_bytes, buf, read_bytes); + total_bytes += read_bytes; + } + + if (out) out[total_bytes] = '\0'; + *len = total_bytes; + + return out; +} + + +/* + * The combined READER/HANDLER + * + */ + +SAPI_POST_HANDLER_FUNC(suhosin_rfc1867_post_handler) +{ + char *boundary, *s=NULL, *boundary_end = NULL, *start_arr=NULL, *array_index=NULL; + char *temp_filename=NULL, *lbuf=NULL, *abuf=NULL; + int boundary_len=0, total_bytes=0, cancel_upload=0, is_arr_upload=0, array_len=0; + int max_file_size=0, skip_upload=0, anonindex=0, is_anonymous; + zval *http_post_files=NULL; HashTable *uploaded_files=NULL; +#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) + int str_len = 0, num_vars = 0, num_vars_max = 2*10, *len_list = NULL; + char **val_list = NULL; +#endif + zend_bool magic_quotes_gpc; + multipart_buffer *mbuff; + zval *array_ptr = (zval *) arg; + int fd=-1; + zend_llist header; + void *event_extra_data = NULL; + + SDEBUG("suhosin_rfc1867_handler"); + + if (SG(request_info).content_length > SG(post_max_size)) { + sapi_module.sapi_error(E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes", SG(request_info).content_length, SG(post_max_size)); + return; + } + + /* Get the boundary */ + boundary = strstr(content_type_dup, "boundary"); + if (!boundary || !(boundary=strchr(boundary, '='))) { + sapi_module.sapi_error(E_WARNING, "Missing boundary in multipart/form-data POST data"); + return; + } + + boundary++; + boundary_len = strlen(boundary); + + if (boundary[0] == '"') { + boundary++; + boundary_end = strchr(boundary, '"'); + if (!boundary_end) { + sapi_module.sapi_error(E_WARNING, "Invalid boundary in multipart/form-data POST data"); + return; + } + } else { + /* search for the end of the boundary */ + boundary_end = strchr(boundary, ','); + } + if (boundary_end) { + boundary_end[0] = '\0'; + boundary_len = boundary_end-boundary; + } + + /* Initialize the buffer */ + if (!(mbuff = multipart_buffer_new(boundary, boundary_len))) { + sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer"); + return; + } + + /* Initialize $_FILES[] */ + zend_hash_init(&PG(rfc1867_protected_variables), 5, NULL, NULL, 0); + + ALLOC_HASHTABLE(uploaded_files); + zend_hash_init(uploaded_files, 5, NULL, (dtor_func_t) free_estring, 0); + SG(rfc1867_uploaded_files) = uploaded_files; + + ALLOC_ZVAL(http_post_files); + array_init(http_post_files); + INIT_PZVAL(http_post_files); + PG(http_globals)[TRACK_VARS_FILES] = http_post_files; + +#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) + if (php_mb_encoding_translation(TSRMLS_C)) { + val_list = (char **)ecalloc(num_vars_max+2, sizeof(char *)); + len_list = (int *)ecalloc(num_vars_max+2, sizeof(int)); + } +#endif + zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0); + + + { + multipart_event_start event_start; + + event_start.content_length = SG(request_info).content_length; + if (suhosin_rfc1867_filter(MULTIPART_EVENT_START, &event_start, &event_extra_data TSRMLS_CC) == FAILURE) { + goto fileupload_done; + } + } + + while (!multipart_buffer_eof(mbuff TSRMLS_CC)) + { + char buff[FILLUNIT]; + char *cd=NULL,*param=NULL,*filename=NULL, *tmp=NULL; + size_t blen=0, wlen=0; + off_t offset; + + zend_llist_clean(&header); + + if (!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) { + goto fileupload_done; + } + + if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) { + char *pair=NULL; + int end=0; + + while (isspace(*cd)) { + ++cd; + } + + while (*cd && (pair = php_ap_getword(&cd, ';'))) + { + char *key=NULL, *word = pair; + + while (isspace(*cd)) { + ++cd; + } + + if (strchr(pair, '=')) { + key = php_ap_getword(&pair, '='); + + if (!strcasecmp(key, "name")) { + if (param) { + efree(param); + } + param = php_ap_getword_conf(&pair TSRMLS_CC); + } else if (!strcasecmp(key, "filename")) { + if (filename) { + efree(filename); + } + filename = php_ap_getword_conf(&pair TSRMLS_CC); + } + } + if (key) { + efree(key); + } + efree(word); + } + + /* Normal form variable, safe to read all data into memory */ + if (!filename && param) { + + unsigned int value_len; + char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC); + unsigned int new_val_len; /* Dummy variable */ + + if (!value) { + value = estrdup(""); + } +SDEBUG("calling inputfilter"); + if (suhosin_input_filter(PARSE_POST, param, &value, strlen(value), &new_val_len TSRMLS_CC) == 0) { + efree(param); + efree(value); + continue; + } + +#ifdef ZEND_ENGINE_2 + if (sapi_module.input_filter(PARSE_POST, param, &value, new_val_len, &new_val_len TSRMLS_CC)) { +#endif + { + multipart_event_formdata event_formdata; + size_t newlength = 0; + + event_formdata.post_bytes_processed = SG(read_post_bytes); + event_formdata.name = param; + event_formdata.value = &value; + event_formdata.length = new_val_len; + event_formdata.newlength = &newlength; + if (suhosin_rfc1867_filter(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC) == FAILURE) { + efree(param); + efree(value); + continue; + } + new_val_len = newlength; + } + +#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); + } +#else + safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC); +#endif +#ifdef ZEND_ENGINE_2 + } else { + multipart_event_formdata event_formdata; + + event_formdata.post_bytes_processed = SG(read_post_bytes); + event_formdata.name = param; + event_formdata.value = &value; + event_formdata.length = value_len; + event_formdata.newlength = NULL; + suhosin_rfc1867_filter(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC); + } +#endif + if (!strcasecmp(param, "MAX_FILE_SIZE")) { + max_file_size = atol(value); + } + + efree(param); + efree(value); + continue; + } + + /* If file_uploads=off, skip the file part */ + if (!PG(file_uploads)) { + skip_upload = 1; + } + + /* Return with an error if the posted data is garbled */ + if (!param && !filename) { + sapi_module.sapi_error(E_WARNING, "File Upload Mime headers garbled"); + goto fileupload_done; + } + + if (!param) { + is_anonymous = 1; + param = emalloc(MAX_SIZE_ANONNAME); + snprintf(param, MAX_SIZE_ANONNAME, "%u", anonindex++); + } else { + is_anonymous = 0; + } + + /* New Rule: never repair potential malicious user input */ + if (!skip_upload) { + char *tmp = param; + long c = 0; + + while (*tmp) { + if (*tmp == '[') { + c++; + } else if (*tmp == ']') { + c--; + if (tmp[1] && tmp[1] != '[') { + skip_upload = 1; + break; + } + } + if (c < 0) { + skip_upload = 1; + break; + } + tmp++; + } + } + + total_bytes = cancel_upload = 0; + + if (!skip_upload) { + multipart_event_file_start event_file_start; + + /* Handle file */ + fd = php_open_temporary_fd(PG(upload_tmp_dir), "php", &temp_filename TSRMLS_CC); + if (fd==-1) { + sapi_module.sapi_error(E_WARNING, "File upload error - unable to create a temporary file"); + cancel_upload = UPLOAD_ERROR_E; + } + + event_file_start.post_bytes_processed = SG(read_post_bytes); + event_file_start.name = param; + event_file_start.filename = &filename; + if (suhosin_rfc1867_filter(MULTIPART_EVENT_FILE_START, &event_file_start, &event_extra_data TSRMLS_CC) == FAILURE) { + if (temp_filename) { + if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */ + close(fd); + unlink(temp_filename); + } + efree(temp_filename); + } + temp_filename = NULL; + efree(param); + efree(filename); + continue; + } + } + + + if (skip_upload) { + efree(param); + efree(filename); + continue; + } + + if(strlen(filename) == 0) { +#if DEBUG_FILE_UPLOAD + sapi_module.sapi_error(E_NOTICE, "No file uploaded"); +#endif + cancel_upload = UPLOAD_ERROR_D; + } + + offset = 0; + end = 0; + while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC))) + { + { + multipart_event_file_data event_file_data; + + event_file_data.post_bytes_processed = SG(read_post_bytes); + event_file_data.offset = offset; + event_file_data.data = buff; + event_file_data.length = blen; + event_file_data.newlength = &blen; + if (suhosin_rfc1867_filter(MULTIPART_EVENT_FILE_DATA, &event_file_data, &event_extra_data TSRMLS_CC) == FAILURE) { + cancel_upload = UPLOAD_ERROR_X; + continue; + } + } + + + if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize)) { +#if DEBUG_FILE_UPLOAD + sapi_module.sapi_error(E_NOTICE, "upload_max_filesize of %ld bytes exceeded - file [%s=%s] not saved", PG(upload_max_filesize), param, filename); +#endif + cancel_upload = UPLOAD_ERROR_A; + } else if (max_file_size && (total_bytes > max_file_size)) { +#if DEBUG_FILE_UPLOAD + sapi_module.sapi_error(E_NOTICE, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename); +#endif + cancel_upload = UPLOAD_ERROR_B; + } else if (blen > 0) { + + wlen = write(fd, buff, blen); + + if (wlen < blen) { +#if DEBUG_FILE_UPLOAD + sapi_module.sapi_error(E_NOTICE, "Only %d bytes were written, expected to write %d", wlen, blen); +#endif + cancel_upload = UPLOAD_ERROR_F; + } else { + total_bytes += wlen; + } + + offset += wlen; + } + } + if (fd!=-1) { /* may not be initialized if file could not be created */ + close(fd); + } + if (!cancel_upload && !end) { +#if DEBUG_FILE_UPLOAD + sapi_module.sapi_error(E_NOTICE, "Missing mime boundary at the end of the data for file %s", strlen(filename) > 0 ? filename : ""); +#endif + cancel_upload = UPLOAD_ERROR_C; + } +#if DEBUG_FILE_UPLOAD + if(strlen(filename) > 0 && total_bytes == 0 && !cancel_upload) { + sapi_module.sapi_error(E_WARNING, "Uploaded file size 0 - file [%s=%s] not saved", param, filename); + cancel_upload = 5; + } +#endif + + { + multipart_event_file_end event_file_end; + + event_file_end.post_bytes_processed = SG(read_post_bytes); + event_file_end.temp_filename = temp_filename; + event_file_end.cancel_upload = cancel_upload; + if (suhosin_rfc1867_filter(MULTIPART_EVENT_FILE_END, &event_file_end, &event_extra_data TSRMLS_CC) == FAILURE) { + cancel_upload = UPLOAD_ERROR_X; + } + } + + if (cancel_upload) { + if (temp_filename) { + if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */ + unlink(temp_filename); + } + efree(temp_filename); + } + temp_filename=""; + } else { + zend_hash_add(SG(rfc1867_uploaded_files), temp_filename, strlen(temp_filename) + 1, &temp_filename, sizeof(char *), NULL); + } + + /* is_arr_upload is true when name of file upload field + * ends in [.*] + * start_arr is set to point to 1st [ + */ + is_arr_upload = (start_arr = strchr(param,'[')) && (param[strlen(param)-1] == ']'); + + if (is_arr_upload) { + array_len = strlen(start_arr); + if (array_index) { + efree(array_index); + } + array_index = estrndup(start_arr+1, array_len-2); + } + + /* Add $foo_name */ + if (lbuf) { + efree(lbuf); + } + lbuf = (char *) emalloc(strlen(param) + MAX_SIZE_OF_INDEX + 1); + + if (is_arr_upload) { + if (abuf) efree(abuf); + abuf = estrndup(param, strlen(param)-array_len); + sprintf(lbuf, "%s_name[%s]", abuf, array_index); + } else { + sprintf(lbuf, "%s_name", param); + } + +#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) + if (php_mb_encoding_translation(TSRMLS_C)) { + if (num_vars>=num_vars_max){ + php_mb_gpc_realloc_buffer(&val_list, &len_list, &num_vars_max, + 1 TSRMLS_CC); + } + val_list[num_vars] = filename; + len_list[num_vars] = strlen(filename); + num_vars++; + if(php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) { + str_len = strlen(filename); + php_mb_gpc_encoding_converter(&filename, &str_len, 1, NULL, NULL TSRMLS_CC); + } + s = php_mb_strrchr(filename, '\\' TSRMLS_CC); + if ((tmp = php_mb_strrchr(filename, '/' TSRMLS_CC)) > s) { + s = tmp; + } + num_vars--; + goto filedone; + } +#endif + /* The \ check should technically be needed for win32 systems only where + * it is a valid path separator. However, IE in all it's wisdom always sends + * the full path of the file on the user's filesystem, which means that unless + * the user does basename() they get a bogus file name. Until IE's user base drops + * to nill or problem is fixed this code must remain enabled for all systems. + */ + s = strrchr(filename, '\\'); + if ((tmp = strrchr(filename, '/')) > s) { + s = tmp; + } +#ifdef PHP_WIN32 + if (PG(magic_quotes_gpc)) { + s = s ? s : filename; + tmp = strrchr(s, '\''); + s = tmp > s ? tmp : s; + tmp = strrchr(s, '"'); + s = tmp > s ? tmp : s; + } +#endif + +#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING) +filedone: +#endif + + if (!is_anonymous) { + if (s && s > filename) { + safe_php_register_variable(lbuf, s+1, NULL, 0 TSRMLS_CC); + } else { + safe_php_register_variable(lbuf, filename, NULL, 0 TSRMLS_CC); + } + } + + /* Add $foo[name] */ + if (is_arr_upload) { + sprintf(lbuf, "%s[name][%s]", abuf, array_index); + } else { + sprintf(lbuf, "%s[name]", param); + } + if (s && s > filename) { + register_http_post_files_variable(lbuf, s+1, http_post_files, 0 TSRMLS_CC); + } else { + register_http_post_files_variable(lbuf, filename, http_post_files, 0 TSRMLS_CC); + } + efree(filename); + s = NULL; + + /* Possible Content-Type: */ + if (cancel_upload || !(cd = php_mime_get_hdr_value(header, "Content-Type"))) { + cd = ""; + } else { + /* fix for Opera 6.01 */ + s = strchr(cd, ';'); + if (s != NULL) { + *s = '\0'; + } + } + + /* Add $foo_type */ + if (is_arr_upload) { + sprintf(lbuf, "%s_type[%s]", abuf, array_index); + } else { + sprintf(lbuf, "%s_type", param); + } + if (!is_anonymous) { + safe_php_register_variable(lbuf, cd, NULL, 0 TSRMLS_CC); + } + + /* Add $foo[type] */ + if (is_arr_upload) { + sprintf(lbuf, "%s[type][%s]", abuf, array_index); + } else { + sprintf(lbuf, "%s[type]", param); + } + register_http_post_files_variable(lbuf, cd, http_post_files, 0 TSRMLS_CC); + + /* Restore Content-Type Header */ + if (s != NULL) { + *s = ';'; + } + s = ""; + + /* Initialize variables */ + add_protected_variable(param TSRMLS_CC); + + magic_quotes_gpc = PG(magic_quotes_gpc); + PG(magic_quotes_gpc) = 0; + /* if param is of form xxx[.*] this will cut it to xxx */ + if (!is_anonymous) { + safe_php_register_variable(param, temp_filename, NULL, 1 TSRMLS_CC); + } + + /* Add $foo[tmp_name] */ + if (is_arr_upload) { + sprintf(lbuf, "%s[tmp_name][%s]", abuf, array_index); + } else { + sprintf(lbuf, "%s[tmp_name]", param); + } + add_protected_variable(lbuf TSRMLS_CC); + register_http_post_files_variable(lbuf, temp_filename, http_post_files, 1 TSRMLS_CC); + + PG(magic_quotes_gpc) = magic_quotes_gpc; + + { + zval file_size, error_type; + + error_type.value.lval = cancel_upload; + error_type.type = IS_LONG; + + /* Add $foo[error] */ + if (cancel_upload) { + file_size.value.lval = 0; + file_size.type = IS_LONG; + } else { + file_size.value.lval = total_bytes; + file_size.type = IS_LONG; + } + + if (is_arr_upload) { + sprintf(lbuf, "%s[error][%s]", abuf, array_index); + } else { + sprintf(lbuf, "%s[error]", param); + } + register_http_post_files_variable_ex(lbuf, &error_type, http_post_files, 0 TSRMLS_CC); + + /* Add $foo_size */ + if (is_arr_upload) { + sprintf(lbuf, "%s_size[%s]", abuf, array_index); + } else { + sprintf(lbuf, "%s_size", param); + } + if (!is_anonymous) { + safe_php_register_variable_ex(lbuf, &file_size, NULL, 0 TSRMLS_CC); + } + + /* Add $foo[size] */ + if (is_arr_upload) { + sprintf(lbuf, "%s[size][%s]", abuf, array_index); + } else { + sprintf(lbuf, "%s[size]", param); + } + register_http_post_files_variable_ex(lbuf, &file_size, http_post_files, 0 TSRMLS_CC); + } + efree(param); + } + } +fileupload_done: + { + multipart_event_end event_end; + + event_end.post_bytes_processed = SG(read_post_bytes); + suhosin_rfc1867_filter(MULTIPART_EVENT_END, &event_end, &event_extra_data TSRMLS_CC); + } + + SAFE_RETURN; +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/session.c b/session.c new file mode 100644 index 0000000..b784d9b --- /dev/null +++ b/session.c @@ -0,0 +1,714 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: session.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "TSRM.h" +#include "SAPI.h" +#include "php_ini.h" +#include "php_suhosin.h" +#include "ext/standard/base64.h" +#include "sha256.h" + +#define PS_OPEN_ARGS void **mod_data, const char *save_path, const char *session_name TSRMLS_DC +#define PS_CLOSE_ARGS void **mod_data TSRMLS_DC +#define PS_READ_ARGS void **mod_data, const char *key, char **val, int *vallen TSRMLS_DC +#define PS_WRITE_ARGS void **mod_data, const char *key, const char *val, const int vallen TSRMLS_DC +#define PS_DESTROY_ARGS void **mod_data, const char *key TSRMLS_DC +#define PS_GC_ARGS void **mod_data, int maxlifetime, int *nrdels TSRMLS_DC +#define PS_CREATE_SID_ARGS void **mod_data, int *newlen TSRMLS_DC + +typedef struct ps_module_struct { + const char *s_name; + int (*s_open)(PS_OPEN_ARGS); + int (*s_close)(PS_CLOSE_ARGS); + int (*s_read)(PS_READ_ARGS); + int (*s_write)(PS_WRITE_ARGS); + int (*s_destroy)(PS_DESTROY_ARGS); + int (*s_gc)(PS_GC_ARGS); + char *(*s_create_sid)(PS_CREATE_SID_ARGS); +} ps_module; + +typedef enum { + php_session_disabled, + php_session_none, + php_session_active +} php_session_status; + +#define PS_SERIALIZER_ENCODE_ARGS char **newstr, int *newlen TSRMLS_DC +#define PS_SERIALIZER_DECODE_ARGS const char *val, int vallen TSRMLS_DC + +typedef struct ps_serializer_struct { + const char *name; + int (*encode)(PS_SERIALIZER_ENCODE_ARGS); + int (*decode)(PS_SERIALIZER_DECODE_ARGS); +} ps_serializer; + +typedef struct _php_ps_globals_43_44 { + char *save_path; + char *session_name; + char *id; + char *extern_referer_chk; + char *entropy_file; + char *cache_limiter; + long entropy_length; + long cookie_lifetime; + char *cookie_path; + char *cookie_domain; + zend_bool cookie_secure; + ps_module *mod; + void *mod_data; + php_session_status session_status; + long gc_probability; + long gc_divisor; + long gc_maxlifetime; + int module_number; + long cache_expire; + zend_bool bug_compat; /* Whether to behave like PHP 4.2 and earlier */ + zend_bool bug_compat_warn; /* Whether to warn about it */ + const struct ps_serializer_struct *serializer; + zval *http_session_vars; + zend_bool auto_start; + zend_bool use_cookies; + zend_bool use_only_cookies; + zend_bool use_trans_sid; /* contains the INI value of whether to use trans-sid */ + zend_bool apply_trans_sid; /* whether or not to enable trans-sid for the current request */ + int send_cookie; + int define_sid; +} php_ps_globals_43_44; + +typedef struct _php_ps_globals_50_51 { + char *save_path; + char *session_name; + char *id; + char *extern_referer_chk; + char *entropy_file; + char *cache_limiter; + long entropy_length; + long cookie_lifetime; + char *cookie_path; + char *cookie_domain; + zend_bool cookie_secure; + ps_module *mod; + void *mod_data; + php_session_status session_status; + long gc_probability; + long gc_divisor; + long gc_maxlifetime; + int module_number; + long cache_expire; + zend_bool bug_compat; /* Whether to behave like PHP 4.2 and earlier */ + zend_bool bug_compat_warn; /* Whether to warn about it */ + const struct ps_serializer_struct *serializer; + zval *http_session_vars; + zend_bool auto_start; + zend_bool use_cookies; + zend_bool use_only_cookies; + zend_bool use_trans_sid; /* contains the INI value of whether to use trans-sid */ + zend_bool apply_trans_sid; /* whether or not to enable trans-sid for the current request */ + + long hash_func; + long hash_bits_per_character; + int send_cookie; + int define_sid; +} php_ps_globals_50_51; + +typedef struct _php_ps_globals_52_60 { + char *save_path; + char *session_name; + char *id; + char *extern_referer_chk; + char *entropy_file; + char *cache_limiter; + long entropy_length; + long cookie_lifetime; + char *cookie_path; + char *cookie_domain; + zend_bool cookie_secure; + zend_bool cookie_httponly; + ps_module *mod; + void *mod_data; + php_session_status session_status; + long gc_probability; + long gc_divisor; + long gc_maxlifetime; + int module_number; + long cache_expire; + zend_bool bug_compat; /* Whether to behave like PHP 4.2 and earlier */ + zend_bool bug_compat_warn; /* Whether to warn about it */ + const struct ps_serializer_struct *serializer; + zval *http_session_vars; + zend_bool auto_start; + zend_bool use_cookies; + zend_bool use_only_cookies; + zend_bool use_trans_sid; /* contains the INI value of whether to use trans-sid */ + zend_bool apply_trans_sid; /* whether or not to enable trans-sid for the current request */ + + long hash_func; + long hash_bits_per_character; + int send_cookie; + int define_sid; + zend_bool invalid_session_id; /* allows the driver to report about an invalid session id and request id regeneration */ +} php_ps_globals_52_60; + + +#ifdef ZTS +static ts_rsrc_id session_globals_id = 0; +# if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 2) +# define SESSION_G(v) TSRMG(session_globals_id, php_ps_globals_52_60 *, v) +# elif (PHP_MAJOR_VERSION == 5) +# define SESSION_G(v) TSRMG(session_globals_id, php_ps_globals_50_51 *, v) +# elif (PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION >= 3) +# define SESSION_G(v) TSRMG(session_globals_id, php_ps_globals_43_44 *, v) +# else + UNSUPPORTED PHP VERSION +# endif +#else +# if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 2) +static php_ps_globals_52_60 *session_globals = NULL; +# elif (PHP_MAJOR_VERSION == 5) +static php_ps_globals_50_51 *session_globals = NULL; +# elif (PHP_MAJOR_VERSION == 4 && PHP_MINOR_VERSION >= 3) +static php_ps_globals_43_44 *session_globals = NULL; +# else + UNSUPPORTED PHP VERSION +# endif +#define SESSION_G(v) (session_globals->v) +#endif + +void suhosin_get_ipv4(char *buf TSRMLS_DC) +{ + char *raddr = sapi_getenv("REMOTE_ADDR", sizeof("REMOTE_ADDR")-1 TSRMLS_CC); + int i; + + + if (raddr == NULL) { + memset(buf, 0, 4); + return; + } + + for (i=0; i<4; i++) { + if (raddr[0] == 0) { + buf[i] = 0; + } else { + buf[i] = strtol(raddr, &raddr, 10); + if (raddr[0] == '.') { + raddr++; + } + } + } +} + +char *suhosin_encrypt_string(char *str, int len, char *var, int vlen, char *key TSRMLS_DC) +{ + int padded_len, i, slen; + unsigned char *crypted, *tmp; + unsigned int check = 0x13579BDF; + + if (str == NULL) { + return NULL; + } + if (len == 0) { + return estrndup("", 0); + } + + + suhosin_aes_gkey(4,8,key TSRMLS_CC); + + padded_len = ((len+15) & ~0xF); + crypted = emalloc(16+padded_len+1); + memset(crypted, 0xff, 16+padded_len+1); + memcpy(crypted+16, str, len+1); + + /* calculate check value */ + for (i = 0; i> (32-3)); + check += check << 1; + check ^= (unsigned char)var[i]; + } + for (i = 0; i> (32-3)); + check += check << 1; + check ^= (unsigned char)str[i]; + } + + /* store ip value */ + suhosin_get_ipv4(crypted+4 TSRMLS_CC); + + /* store check value */ + crypted[8] = check & 0xff; + crypted[9] = (check >> 8) & 0xff; + crypted[10] = (check >> 16) & 0xff; + crypted[11] = (check >> 24) & 0xff; + + /* store original length */ + crypted[12] = len & 0xff; + crypted[13] = (len >> 8) & 0xff; + crypted[14] = (len >> 16) & 0xff; + crypted[15] = (len >> 24) & 0xff; + + for (i=0, tmp=crypted; i 0) { + int j; + for (j=0; j<16; j++) tmp[j] ^= tmp[j-16]; + } + suhosin_aes_encrypt((char *)tmp TSRMLS_CC); + } + + tmp = php_base64_encode(crypted, padded_len+16, NULL); + efree(crypted); + slen=strlen((char *)tmp); + for (i=0; i=0; i-=16, tmp-=16) { + suhosin_aes_decrypt((char *)tmp TSRMLS_CC); + if (i > 0) { + int j; + for (j=0; j<16; j++) tmp[j] ^= tmp[j-16]; + } + } + + /* retrieve orig_len */ + o_len = decrypted[15]; + o_len <<= 8; + o_len |= decrypted[14]; + o_len <<= 8; + o_len |= decrypted[13]; + o_len <<= 8; + o_len |= decrypted[12]; + + if (o_len < 0 || o_len > len-16) { + goto error_out; + } + + /* calculate check value */ + for (i = 0; i> (32-3)); + check += check << 1; + check ^= (unsigned char)var[i]; + } + for (i = 0; i> (32-3)); + check += check << 1; + check ^= decrypted[16+i]; + } + + /* check value */ + invalid = (decrypted[8] != (check & 0xff)) || + (decrypted[9] != ((check >> 8) & 0xff)) || + (decrypted[10] != ((check >> 16) & 0xff)) || + (decrypted[11] != ((check >> 24) & 0xff)); + + /* check IP */ + if (check_ra > 0) { + if (check_ra > 4) { + check_ra = 4; + } + suhosin_get_ipv4(&buf TSRMLS_CC); + if (memcmp(buf, decrypted+4, check_ra) != 0) { + goto error_out; + } + } + + if (invalid) { + goto error_out; + } + + if (orig_len) { + *orig_len = o_len; + } + + memmove(decrypted, decrypted+16, o_len); + decrypted[o_len] = 0; + /* we do not realloc() here because 16 byte less + is simply not worth the overhead */ + return (char *)decrypted; +} + +char *suhosin_generate_key(char *key, zend_bool ua, zend_bool dr, long raddr, char *cryptkey TSRMLS_DC) +{ + char *_ua = NULL; + char *_dr = NULL; + char *_ra = NULL; + suhosin_SHA256_CTX ctx; + + if (ua) { + _ua = sapi_getenv("HTTP_USER_AGENT", sizeof("HTTP_USER_AGENT")-1 TSRMLS_CC); + } + + if (dr) { + _dr = sapi_getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT")-1 TSRMLS_CC); + } + + if (raddr > 0) { + _ra = sapi_getenv("REMOTE_ADDR", sizeof("REMOTE_ADDR")-1 TSRMLS_CC); + } + + SDEBUG("(suhosin_generate_key) KEY: %s - UA: %s - DR: %s - RA: %s", key,_ua,_dr,_ra); + + suhosin_SHA256Init(&ctx); + if (key == NULL) { + suhosin_SHA256Update(&ctx, (unsigned char*)"D3F4UL7", sizeof("D3F4UL7")); + } else { + suhosin_SHA256Update(&ctx, (unsigned char*)key, strlen(key)); + } + if (_ua) { + suhosin_SHA256Update(&ctx, (unsigned char*)_ua, strlen(_ua)); + } + if (_dr) { + suhosin_SHA256Update(&ctx, (unsigned char*)_dr, strlen(_dr)); + } + if (_ra) { + if (raddr >= 4) { + suhosin_SHA256Update(&ctx, (unsigned char*)_ra, strlen(_ra)); + } else { + long dots = 0; + char *tmp = _ra; + + while (*tmp) { + if (*tmp == '.') { + dots++; + if (dots == raddr) { + break; + } + } + tmp++; + } + suhosin_SHA256Update(&ctx, (unsigned char*)_ra, tmp-_ra); + } + } + suhosin_SHA256Final((unsigned char *)cryptkey, &ctx); + cryptkey[32] = 0; /* uhmm... not really a string */ + + return cryptkey; +} + + +static int (*old_OnUpdateSaveHandler)(zend_ini_entry *entry, char *new_value, uint new_value_length, void *mh_arg1, void *mh_arg2, void *mh_arg3, int stage TSRMLS_DC) = NULL; +static int (*old_SessionRINIT)(INIT_FUNC_ARGS) = NULL; + +static int suhosin_hook_s_read(void **mod_data, const char *key, char **val, int *vallen TSRMLS_DC) +{ + int r; + + int i;char *v,*KEY=(char *)key; + + /* protect session vars */ +/* if (SESSION_G(http_session_vars) && SESSION_G(http_session_vars)->type == IS_ARRAY) { + SESSION_G(http_session_vars)->refcount++; + }*/ + + /* protect dumb session handlers */ + if (key == NULL || !key[0] || *mod_data == NULL) { +regenerate: + SDEBUG("regenerating key is %s", key); + KEY = SESSION_G(id) = SESSION_G(mod)->s_create_sid(&SESSION_G(mod_data), NULL TSRMLS_CC); + SESSION_G(send_cookie) = 1; + } else if (strlen(key) > SUHOSIN_G(session_max_id_length)) { + suhosin_log(S_SESSION, "session id ('%s') exceeds maximum length - regenerating", KEY); + if (!SUHOSIN_G(simulation)) { + goto regenerate; + } + } +#if (PHP_MAJOR_VERSION < 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 2) + else if (strpbrk(KEY, "\r\n\t <>'\"\\")) { + suhosin_log(S_SESSION, "session id ('%s') contains invalid chars - regenerating", KEY); + if (!SUHOSIN_G(simulation)) { + goto regenerate; + } + } +#endif + + r = SUHOSIN_G(old_s_read)(mod_data, KEY, val, vallen TSRMLS_CC); + + if (r == SUCCESS && SUHOSIN_G(session_encrypt) && *vallen > 0) { + char cryptkey[33]; + + SUHOSIN_G(do_not_scan) = 1; + suhosin_generate_key(SUHOSIN_G(session_cryptkey), SUHOSIN_G(session_cryptua), SUHOSIN_G(session_cryptdocroot), SUHOSIN_G(session_cryptraddr), (char *)&cryptkey TSRMLS_CC); + + v = *val; + i = *vallen; + *val = suhosin_decrypt_string(v, i, "", 0, (char *)&cryptkey, vallen, SUHOSIN_G(session_checkraddr) TSRMLS_CC); + SUHOSIN_G(do_not_scan) = 0; + if (*val == NULL) { + *val = estrndup("", 0); + *vallen = 0; + } + efree(v); + } + + return r; +} + +static int suhosin_hook_s_write(void **mod_data, const char *key, const char *val, const int vallen TSRMLS_DC) +{ + int r; +/* int nullify = 0;*/ + char *v = (char *)val; + + /* protect dumb session handlers */ + if (key == NULL || !key[0] || val == NULL || strlen(key) > SUHOSIN_G(session_max_id_length) || *mod_data == NULL) { + r = FAILURE; + goto return_write; + } + + r = vallen; + + if (r > 0 && SUHOSIN_G(session_encrypt)) { + char cryptkey[33]; + + SUHOSIN_G(do_not_scan) = 1; + + suhosin_generate_key(SUHOSIN_G(session_cryptkey), SUHOSIN_G(session_cryptua), SUHOSIN_G(session_cryptdocroot), SUHOSIN_G(session_cryptraddr), (char *)&cryptkey TSRMLS_CC); + + v = suhosin_encrypt_string(v, vallen, "", 0, (char *)&cryptkey TSRMLS_CC); + + SUHOSIN_G(do_not_scan) = 0; + r = strlen(v); + } + + r = SUHOSIN_G(old_s_write)(mod_data, key, v, r TSRMLS_CC); + +return_write: + /* protect session vars */ +/* if (SESSION_G(http_session_vars) && SESSION_G(http_session_vars)->type == IS_ARRAY) { + if (SESSION_G(http_session_vars)->refcount==1) { + nullify = 1; + } + zval_ptr_dtor(&SESSION_G(http_session_vars)); + if (nullify) { + suhosin_log(S_SESSION, "possible session variables double free attack stopped"); + SESSION_G(http_session_vars) = NULL; + } + }*/ + + return r; +} + +static int suhosin_hook_s_destroy(void **mod_data, const char *key TSRMLS_DC) +{ + int r; + + /* protect dumb session handlers */ + if (key == NULL || !key[0] || strlen(key) > SUHOSIN_G(session_max_id_length) || *mod_data == NULL) { + return FAILURE; + } + + r = SUHOSIN_G(old_s_destroy)(mod_data, key TSRMLS_CC); + + return r; +} + +static void suhosin_hook_session_module(TSRMLS_D) +{ + ps_module *old_mod = SESSION_G(mod), *mod; + + if (old_mod == NULL || SUHOSIN_G(s_module) == old_mod) { + return; + } + if (SUHOSIN_G(s_module) == NULL) { + SUHOSIN_G(s_module) = mod = malloc(sizeof(ps_module)); + if (mod == NULL) { + return; + } + } + mod = SUHOSIN_G(s_module); + memcpy(mod, old_mod, sizeof(ps_module)); + + SUHOSIN_G(old_s_read) = mod->s_read; + mod->s_read = suhosin_hook_s_read; + SUHOSIN_G(old_s_write) = mod->s_write; + mod->s_write = suhosin_hook_s_write; + SUHOSIN_G(old_s_destroy) = mod->s_destroy; + mod->s_destroy = suhosin_hook_s_destroy; + + SESSION_G(mod) = mod; +} + +static PHP_INI_MH(suhosin_OnUpdateSaveHandler) +{ + int r; + + r = old_OnUpdateSaveHandler(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC); + + suhosin_hook_session_module(TSRMLS_C); + + return r; +} + + +static int suhosin_hook_session_RINIT(INIT_FUNC_ARGS) +{ + if (SESSION_G(mod) == NULL) { + char *value = zend_ini_string("session.save_handler", sizeof("session.save_handler"), 0); + + if (value) { + suhosin_OnUpdateSaveHandler(NULL, value, strlen(value), NULL, NULL, NULL, 0 TSRMLS_CC); + } + } + return old_SessionRINIT(INIT_FUNC_ARGS_PASSTHRU); +} + +void suhosin_hook_session(TSRMLS_D) +{ + zend_ini_entry *ini_entry; + zend_module_entry *module; +#ifdef ZTS + ts_rsrc_id *ps_globals_id_ptr; +#endif + + if (zend_hash_find(&module_registry, "session", sizeof("session"), (void**)&module) == FAILURE) { + return; + } + /* retrieve globals from module entry struct if possible */ +#if PHP_VERSION_ID >= 50200 +#ifdef ZTS + if (session_globals_id == 0) { + session_globals_id = *module->globals_id_ptr; + } +#else + if (session_globals == NULL) { + session_globals = module->globals_ptr; + } +#endif +#else + /* retrieve globals from symbols if PHP version is old */ +#ifdef ZTS + if (session_globals_id == 0) { + ps_globals_id_ptr = DL_FETCH_SYMBOL(module->handle, "ps_globals_id"); + if (ps_globals_id_ptr == NULL) { + ps_globals_id_ptr = DL_FETCH_SYMBOL(module->handle, "_ps_globals_id"); + } + if (ps_globals_id_ptr == NULL) { + return; + } + + session_globals_id = *ps_globals_id_ptr; + } +#else + if (session_globals == NULL) { + session_globals = DL_FETCH_SYMBOL(module->handle, "ps_globals"); + if (session_globals == NULL) { + session_globals = DL_FETCH_SYMBOL(module->handle, "_ps_globals"); + } + if (session_globals == NULL) { + return; + } + } +#endif +#endif + if (old_OnUpdateSaveHandler != NULL) { + return; + } + + /* hook request startup function of session module */ + old_SessionRINIT = module->request_startup_func; + module->request_startup_func = suhosin_hook_session_RINIT; + + /* retrieve pointer to session.save_handler ini entry */ + if (zend_hash_find(EG(ini_directives), "session.save_handler", sizeof("session.save_handler"), (void **) &ini_entry) == FAILURE) { + return; + } + SUHOSIN_G(s_module) = NULL; + + /* replace OnUpdateMemoryLimit handler */ + old_OnUpdateSaveHandler = ini_entry->on_modify; + ini_entry->on_modify = suhosin_OnUpdateSaveHandler; + + suhosin_hook_session_module(TSRMLS_C); +} + +void suhosin_unhook_session(TSRMLS_D) +{ + if (old_OnUpdateSaveHandler != NULL) { + zend_ini_entry *ini_entry; + + /* retrieve pointer to session.save_handler ini entry */ + if (zend_hash_find(EG(ini_directives), "session.save_handler", sizeof("session.save_handler"), (void **) &ini_entry) == FAILURE) { + return; + } + ini_entry->on_modify = old_OnUpdateSaveHandler; + + old_OnUpdateSaveHandler = NULL; + } + +} + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ diff --git a/sha256.c b/sha256.c new file mode 100644 index 0000000..35715e9 --- /dev/null +++ b/sha256.c @@ -0,0 +1,432 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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.1.1.1 2007-11-28 01:15:35 sesser Exp $ */ + +#include +#include "php.h" + +/* This code is heavily based on the PHP md5/sha1 implementations */ + +#include "sha256.h" + +static 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 */ +static PHP_FUNCTION(suhosin_sha256) +{ + char *arg; + int arg_len; + zend_bool raw_output = 0; + char sha256str[65]; + suhosin_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'; + suhosin_SHA256Init(&context); + suhosin_SHA256Update(&context, (unsigned char *)arg, (unsigned int)arg_len); + suhosin_SHA256Final(digest, &context); + if (raw_output) { + RETURN_STRINGL((char *)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 */ +static PHP_FUNCTION(suhosin_sha256_file) +{ + char *arg; + int arg_len; + zend_bool raw_output = 0; + char sha256str[65]; + unsigned char buf[1024]; + unsigned char digest[32]; + suhosin_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; + } + + suhosin_SHA256Init(&context); + + while ((n = fread(buf, 1, sizeof(buf), fp)) > 0) { + suhosin_SHA256Update(&context, buf, n); + } + + suhosin_SHA256Final(digest, &context); + + if (ferror(fp)) { + fclose(fp); + RETURN_FALSE; + } + + fclose(fp); + + if (raw_output) { + RETURN_STRINGL((char *)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; \ + } + + +/* {{{ suhosin_SHA256Init + * SHA256 initialization. Begins an SHA256 operation, writing a new context. + */ +void suhosin_SHA256Init(suhosin_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; +} +/* }}} */ + +/* {{{ suhosin_SHA256Update + SHA256 block update operation. Continues an SHA256 message-digest + operation, processing another message block, and updating the + context. + */ +void suhosin_SHA256Update(suhosin_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); +} +/* }}} */ + +/* {{{ suhosin_SHA256Final + SHA256 finalization. Ends an SHA256 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void suhosin_SHA256Final(unsigned char digest[32], suhosin_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); + suhosin_SHA256Update(context, PADDING, padLen); + + /* Append length (before padding) */ + suhosin_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); +} +/* }}} */ + + +/* {{{ suhosin_sha256_functions[] + */ +static function_entry suhosin_sha256_functions[] = { + PHP_NAMED_FE(sha256, PHP_FN(suhosin_sha256), NULL) + PHP_NAMED_FE(sha256_file, PHP_FN(suhosin_sha256_file), NULL) + {NULL, NULL, NULL} +}; +/* }}} */ + + +void suhosin_hook_sha256() +{ + TSRMLS_FETCH(); + + /* check if we already have sha256 support */ + if (zend_hash_exists(CG(function_table), "sha256", sizeof("sha256"))) { + return; + } + + /* add the sha256 functions */ +#ifndef ZEND_ENGINE_2 + zend_register_functions(suhosin_sha256_functions, NULL, MODULE_PERSISTENT TSRMLS_CC); +#else + zend_register_functions(NULL, suhosin_sha256_functions, NULL, MODULE_PERSISTENT TSRMLS_CC); +#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 --git a/sha256.h b/sha256.h new file mode 100644 index 0000000..a078221 --- /dev/null +++ b/sha256.h @@ -0,0 +1,38 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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.1.1.1 2007-11-28 01:15:35 sesser 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 */ +} suhosin_SHA256_CTX; + +void suhosin_SHA256Init(suhosin_SHA256_CTX *); +void suhosin_SHA256Update(suhosin_SHA256_CTX *, const unsigned char *, unsigned int); +void suhosin_SHA256Final(unsigned char[32], suhosin_SHA256_CTX *); + +#endif diff --git a/suhosin.c b/suhosin.c new file mode 100644 index 0000000..202011f --- /dev/null +++ b/suhosin.c @@ -0,0 +1,1248 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: suhosin.c,v 1.2 2007-11-28 16:01:50 sesser Exp $ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "zend_extensions.h" +#include "ext/standard/info.h" +#include "php_syslog.h" +#include "php_suhosin.h" +#include "zend_llist.h" +#include "zend_operators.h" +#include "SAPI.h" +#include "php_logos.h" +#include "suhosin_logo.h" +#include "ext/standard/php_string.h" +#include "ext/standard/url.h" +#include "ext/standard/base64.h" + +ZEND_DECLARE_MODULE_GLOBALS(suhosin) + +static zend_llist_position lp = NULL; +static int (*old_startup)(zend_extension *extension) = NULL; +static zend_extension *ze = NULL; + +static int suhosin_module_startup(zend_extension *extension); +static void suhosin_shutdown(zend_extension *extension); + + +static void (*orig_op_array_ctor)(zend_op_array *op_array) = NULL; +static void (*orig_op_array_dtor)(zend_op_array *op_array) = NULL; +static void (*orig_module_shutdown)(zend_extension *extension) = NULL; +static int (*orig_module_startup)(zend_extension *extension) = NULL; + + +static void suhosin_op_array_ctor(zend_op_array *op_array); +static void suhosin_op_array_dtor(zend_op_array *op_array); + +STATIC zend_extension suhosin_zend_extension_entry = { + "Suhosin", + SUHOSIN_EXT_VERSION, + "SektionEins GmbH", + "http://www.suhosin.org", + "Copyright (c) 2007", + suhosin_module_startup, + suhosin_shutdown, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + suhosin_op_array_ctor, + suhosin_op_array_dtor, + + STANDARD_ZEND_EXTENSION_PROPERTIES +}; + +static void suhosin_op_array_ctor(zend_op_array *op_array) +{ + TSRMLS_FETCH(); + + if (suhosin_zend_extension_entry.resource_number != -1) { + + unsigned long suhosin_flags = 0; + + if (SUHOSIN_G(in_code_type) == SUHOSIN_EVAL) { + suhosin_flags |= SUHOSIN_FLAG_CREATED_BY_EVAL; + } + + op_array->reserved[suhosin_zend_extension_entry.resource_number] = (void *)suhosin_flags; + + } +} + + + +static void suhosin_op_array_dtor(zend_op_array *op_array) +{ + if (suhosin_zend_extension_entry.resource_number != -1) { + op_array->reserved[suhosin_zend_extension_entry.resource_number] = NULL; + } +} + +/* Stealth Mode functions */ + +static void stealth_op_array_ctor(zend_op_array *op_array) +{ + if (orig_op_array_ctor != NULL) { + orig_op_array_ctor(op_array); + } + suhosin_op_array_ctor(op_array); +} + +static void stealth_op_array_dtor(zend_op_array *op_array) +{ + if (orig_op_array_dtor != NULL) { + orig_op_array_dtor(op_array); + } + suhosin_op_array_dtor(op_array); +} + +static int stealth_module_startup(zend_extension *extension) +{ + int r = orig_module_startup == NULL ? SUCCESS : orig_module_startup(extension); + suhosin_module_startup(extension); + return r; +} + +static void stealth_module_shutdown(zend_extension *extension) +{ + if (orig_module_shutdown != NULL) { + orig_module_shutdown(extension); + } + suhosin_shutdown(extension); +} + + +static int suhosin_module_startup(zend_extension *extension) +{ + zend_module_entry *module_entry_ptr; + int resid; + TSRMLS_FETCH(); + +/* zend_register_module(&suhosin_module_entry TSRMLS_CC); */ + + if (zend_hash_find(&module_registry, "suhosin", sizeof("suhosin"), (void **)&module_entry_ptr)==SUCCESS) { + + if (extension) { + extension->handle = module_entry_ptr->handle; + } else { + zend_extension ext; + ext = suhosin_zend_extension_entry; + ext.handle = module_entry_ptr->handle; + /* + zend_llist_add_element(&zend_extensions, &ext); + extension = zend_llist_get_last(&zend_extensions); + */ + extension = &suhosin_zend_extension_entry; + } + module_entry_ptr->handle = NULL; + + } else { + return FAILURE; + } + + + + if (SUHOSIN_G(apc_bug_workaround)) { + resid = zend_get_resource_handle(extension); + } + resid = zend_get_resource_handle(extension); + suhosin_zend_extension_entry.resource_number = resid; + + suhosin_hook_treat_data(); + suhosin_hook_post_handlers(TSRMLS_C); + suhosin_aes_gentables(); + suhosin_hook_register_server_variables(); + suhosin_hook_header_handler(); + suhosin_hook_execute(TSRMLS_C); + suhosin_hook_session(TSRMLS_C); + + + return SUCCESS; +} + + +static void suhosin_shutdown(zend_extension *extension) +{ + suhosin_unhook_execute(); + suhosin_unhook_header_handler(); + + if (ze != NULL) { + ze->startup = orig_module_startup; + ze->shutdown = orig_module_shutdown; + ze->op_array_ctor = orig_op_array_ctor; + ze->op_array_dtor = orig_op_array_dtor; + } + +} + + +static int suhosin_startup_wrapper(zend_extension *ext) +{ + int res; + zend_extension *ex = &suhosin_zend_extension_entry; + char *new_info; + int new_info_length; + TSRMLS_FETCH(); + + /* Ugly but working hack */ + new_info_length = sizeof("%s\n with %s v%s, %s, by %s\n") + + strlen(ext->author) + + strlen(ex->name) + + strlen(ex->version) + + strlen(ex->copyright) + + strlen(ex->author); + + new_info = (char *) malloc(new_info_length+1); + sprintf(new_info, "%s\n with %s v%s, %s, by %s", ext->author, ex->name, ex->version, ex->copyright, ex->author); + ext->author = new_info; + + ze->startup = old_startup; + + /* Stealth Mode */ + orig_module_startup = ze->startup; + orig_module_shutdown = ze->shutdown; + orig_op_array_ctor = ze->op_array_ctor; + orig_op_array_dtor = ze->op_array_dtor; + + /*if (SUHOSIN_G(stealth) != 0) {*/ + ze->startup = stealth_module_startup; + ze->shutdown = stealth_module_shutdown; + ze->op_array_ctor = stealth_op_array_ctor; + ze->op_array_dtor = stealth_op_array_dtor; + /*}*/ + + res = old_startup(ext); + +/* ex->name = NULL; + ex->author = NULL; + ex->copyright = NULL; + ex->version = NULL;*/ + + /*zend_extensions.head=NULL;*/ + + suhosin_module_startup(NULL); + + + return res; +} + +/*static zend_extension_version_info extension_version_info = { ZEND_EXTENSION_API_NO, ZEND_VERSION, ZTS_V, ZEND_DEBUG };*/ + +#define PERDIR_CHECK(upper, lower) \ + if (!SUHOSIN_G(lower ## _perdir) && stage == ZEND_INI_STAGE_HTACCESS) { \ + return FAILURE; \ + } + +#define LOG_PERDIR_CHECK() PERDIR_CHECK(LOG, log) +#define EXEC_PERDIR_CHECK() PERDIR_CHECK(EXEC, exec) +#define MISC_PERDIR_CHECK() PERDIR_CHECK(MISC, misc) +#define GET_PERDIR_CHECK() PERDIR_CHECK(GET, get) +#define POST_PERDIR_CHECK() PERDIR_CHECK(POST, post) +#define COOKIE_PERDIR_CHECK() PERDIR_CHECK(COOKIE, cookie) +#define REQUEST_PERDIR_CHECK() PERDIR_CHECK(REQUEST, request) +#define UPLOAD_PERDIR_CHECK() PERDIR_CHECK(UPLOAD, upload) +#define SQL_PERDIR_CHECK() PERDIR_CHECK(SQL, sql) + +#define ZEND_INI_MH_PASSTHRU entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC + + +static ZEND_INI_MH(OnUpdateSuhosin_perdir) +{ + char *tmp; + + if (SUHOSIN_G(perdir)) { + pefree(SUHOSIN_G(perdir), 1); + } + SUHOSIN_G(perdir) = NULL; + + /* Initialize the perdir flags */ + SUHOSIN_G(log_perdir) = 0; + SUHOSIN_G(exec_perdir) = 0; + SUHOSIN_G(get_perdir) = 0; + SUHOSIN_G(cookie_perdir) = 0; + SUHOSIN_G(post_perdir) = 0; + SUHOSIN_G(request_perdir) = 0; + SUHOSIN_G(sql_perdir) = 0; + SUHOSIN_G(upload_perdir) = 0; + SUHOSIN_G(misc_perdir) = 0; + + if (new_value == NULL) { + return SUCCESS; + } + + tmp = SUHOSIN_G(perdir) = pestrdup(new_value,1); + + /* trim the whitespace */ + while (isspace(*tmp)) tmp++; + + /* should we deactivate perdir completely? */ + if (*tmp == 0 || *tmp == '0') { + return SUCCESS; + } + + /* no deactivation so check the flags */ + while (*tmp) { + switch (*tmp) { + case 'l': + case 'L': + SUHOSIN_G(log_perdir) = 1; + break; + case 'e': + case 'E': + SUHOSIN_G(exec_perdir) = 1; + break; + case 'g': + case 'G': + SUHOSIN_G(get_perdir) = 1; + break; + case 'c': + case 'C': + SUHOSIN_G(cookie_perdir) = 1; + break; + case 'p': + case 'P': + SUHOSIN_G(post_perdir) = 1; + break; + case 'r': + case 'R': + SUHOSIN_G(request_perdir) = 1; + break; + case 's': + case 'S': + SUHOSIN_G(sql_perdir) = 1; + break; + case 'u': + case 'U': + SUHOSIN_G(upload_perdir) = 1; + break; + case 'm': + case 'M': + SUHOSIN_G(misc_perdir) = 1; + break; + } + tmp++; + } + return SUCCESS; +} + +#define dohandler(handler, name, upper, lower) \ + static ZEND_INI_MH(OnUpdate ## name ## handler) \ + { \ + PERDIR_CHECK(upper, lower) \ + return OnUpdate ## handler (ZEND_INI_MH_PASSTHRU); \ + } \ + +#define dohandlers(name, upper, lower) \ + dohandler(Bool, name, upper, lower) \ + dohandler(String, name, upper, lower) \ + dohandler(Long, name, upper, lower) \ + +dohandlers(Log, LOG, log) +dohandlers(Exec, EXEC, exec) +dohandlers(Misc, MISC, misc) +dohandlers(Get, GET, get) +dohandlers(Post, POST, post) +dohandlers(Cookie, COOKIE, cookie) +dohandlers(Request, REQUEST, request) +dohandlers(Upload, UPLOAD, upload) +dohandlers(SQL, SQL, sql) + +static ZEND_INI_MH(OnUpdateSuhosin_log_syslog) +{ + LOG_PERDIR_CHECK() + if (!new_value) { + SUHOSIN_G(log_syslog) = (S_ALL & ~S_SQL) | S_MEMORY; + } else { + SUHOSIN_G(log_syslog) = atoi(new_value) | S_MEMORY; + } + return SUCCESS; +} +static ZEND_INI_MH(OnUpdateSuhosin_log_syslog_facility) +{ + LOG_PERDIR_CHECK() + if (!new_value) { + SUHOSIN_G(log_syslog_facility) = LOG_USER; + } else { + SUHOSIN_G(log_syslog_facility) = atoi(new_value); + } + return SUCCESS; +} +static ZEND_INI_MH(OnUpdateSuhosin_log_syslog_priority) +{ + LOG_PERDIR_CHECK() + if (!new_value) { + SUHOSIN_G(log_syslog_priority) = LOG_ALERT; + } else { + SUHOSIN_G(log_syslog_priority) = atoi(new_value); + } + return SUCCESS; +} +static ZEND_INI_MH(OnUpdateSuhosin_log_sapi) +{ + LOG_PERDIR_CHECK() + if (!new_value) { + SUHOSIN_G(log_sapi) = (S_ALL & ~S_SQL); + } else { + SUHOSIN_G(log_sapi) = atoi(new_value); + } + return SUCCESS; +} +static ZEND_INI_MH(OnUpdateSuhosin_log_script) +{ + LOG_PERDIR_CHECK() + if (!new_value) { + SUHOSIN_G(log_script) = S_ALL & ~S_MEMORY; + } else { + SUHOSIN_G(log_script) = atoi(new_value) & (~S_MEMORY) & (~S_INTERNAL); + } + return SUCCESS; +} +static ZEND_INI_MH(OnUpdateSuhosin_log_scriptname) +{ + LOG_PERDIR_CHECK() + if (SUHOSIN_G(log_scriptname)) { + pefree(SUHOSIN_G(log_scriptname),1); + } + SUHOSIN_G(log_scriptname) = NULL; + if (new_value) { + SUHOSIN_G(log_scriptname) = pestrdup(new_value,1); + } + return SUCCESS; +} +static ZEND_INI_MH(OnUpdateSuhosin_log_phpscript) +{ + LOG_PERDIR_CHECK() + if (!new_value) { + SUHOSIN_G(log_phpscript) = S_ALL & ~S_MEMORY; + } else { + SUHOSIN_G(log_phpscript) = atoi(new_value) & (~S_MEMORY) & (~S_INTERNAL); + } + return SUCCESS; +} +static ZEND_INI_MH(OnUpdateSuhosin_log_file) +{ + LOG_PERDIR_CHECK() + if (!new_value) { + SUHOSIN_G(log_file) = S_ALL & ~S_MEMORY; + } else { + SUHOSIN_G(log_file) = atoi(new_value) & (~S_MEMORY) & (~S_INTERNAL); + } + return SUCCESS; +} + +static void parse_list(HashTable **ht, char *list, zend_bool lc) +{ + char *s = NULL, *e, *val; + unsigned long dummy = 1; + + if (list == NULL) { +list_destroy: + if (*ht) { + zend_hash_destroy(*ht); + pefree(*ht, 1); + } + *ht = NULL; + return; + } + while (*list == ' ' || *list == '\t') list++; + if (*list == 0) { + goto list_destroy; + } + + *ht = pemalloc(sizeof(HashTable), 1); + zend_hash_init(*ht, 5, NULL, NULL, 1); + + if (lc) { + val = suhosin_str_tolower_dup(list, strlen(list)); + } else { + val = estrndup(list, strlen(list)); + } + e = val; + + while (*e) { + switch (*e) { + case ' ': + case ',': + if (s) { + *e = '\0'; + zend_hash_add(*ht, s, e-s+1, &dummy, sizeof(unsigned long), NULL); + s = NULL; + } + break; + default: + if (!s) { + s = e; + } + break; + } + e++; + } + if (s) { + zend_hash_add(*ht, s, e-s+1, &dummy, sizeof(unsigned long), NULL); + } + efree(val); + +} + +static ZEND_INI_MH(OnUpdate_include_blacklist) +{ + EXEC_PERDIR_CHECK() + parse_list(&SUHOSIN_G(include_blacklist), new_value, 1); + return SUCCESS; +} + +static ZEND_INI_MH(OnUpdate_include_whitelist) +{ + EXEC_PERDIR_CHECK() + parse_list(&SUHOSIN_G(include_whitelist), new_value, 1); + return SUCCESS; +} + +static ZEND_INI_MH(OnUpdate_func_blacklist) +{ + EXEC_PERDIR_CHECK() + parse_list(&SUHOSIN_G(func_blacklist), new_value, 1); + return SUCCESS; +} + +static ZEND_INI_MH(OnUpdate_func_whitelist) +{ + EXEC_PERDIR_CHECK() + parse_list(&SUHOSIN_G(func_whitelist), new_value, 1); + return SUCCESS; +} + +static ZEND_INI_MH(OnUpdate_eval_blacklist) +{ + EXEC_PERDIR_CHECK() + parse_list(&SUHOSIN_G(eval_blacklist), new_value, 1); + return SUCCESS; +} + +static ZEND_INI_MH(OnUpdate_eval_whitelist) +{ + EXEC_PERDIR_CHECK() + parse_list(&SUHOSIN_G(eval_whitelist), new_value, 1); + return SUCCESS; +} + + +static ZEND_INI_MH(OnUpdate_cookie_cryptlist) +{ + parse_list(&SUHOSIN_G(cookie_cryptlist), new_value, 0); + return SUCCESS; +} + +static ZEND_INI_MH(OnUpdate_cookie_plainlist) +{ + parse_list(&SUHOSIN_G(cookie_plainlist), new_value, 0); + return SUCCESS; +} + +/* {{{ proto void suhosin_register_cookie_variable(char *var, zval *val, zval *track_vars_array TSRMLS_DC) + Registers a cookie in the RAW cookie array */ +static void suhosin_register_cookie_variable(char *var, zval *val, zval *track_vars_array TSRMLS_DC) +{ + char *p = NULL; + char *ip; /* index pointer */ + char *index, *escaped_index = NULL; + int var_len, index_len; + zval *gpc_element, **gpc_element_p; + zend_bool is_array = 0; + HashTable *symtable1 = NULL; + + assert(var != NULL); + + symtable1 = Z_ARRVAL_P(track_vars_array); + + /* + * Prepare variable name + */ + + /* ignore leading spaces in the variable name */ + while (*var && *var==' ') { + var++; + } + + /* ensure that we don't have spaces or dots in the variable name (not binary safe) */ + for (p = var; *p; p++) { + if (*p == ' ' || *p == '.') { + *p='_'; + } else if (*p == '[') { + is_array = 1; + ip = p; + *p = 0; + break; + } + } + var_len = p - var; + + if (var_len==0) { /* empty variable name, or variable name with a space in it */ + zval_dtor(val); + return; + } + + index = var; + index_len = var_len; + + if (is_array) { + while (1) { + char *index_s; + int new_idx_len = 0; + + ip++; + index_s = ip; + if (isspace(*ip)) { + ip++; + } + if (*ip==']') { + index_s = NULL; + } else { + ip = strchr(ip, ']'); + if (!ip) { + /* PHP variables cannot contain '[' in their names, so we replace the character with a '_' */ + *(index_s - 1) = '_'; + + index_len = var_len = 0; + if (index) { + index_len = var_len = strlen(index); + } + goto plain_var; + return; + } + *ip = 0; + new_idx_len = strlen(index_s); + } + + if (!index) { + MAKE_STD_ZVAL(gpc_element); + array_init(gpc_element); + zend_hash_next_index_insert(symtable1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); + } else { + if (PG(magic_quotes_gpc) && (index != var)) { + /* no need to addslashes() the index if it's the main variable name */ + escaped_index = php_addslashes(index, index_len, &index_len, 0 TSRMLS_CC); + } else { + escaped_index = index; + } + if (zend_symtable_find(symtable1, escaped_index, index_len + 1, (void **) &gpc_element_p) == FAILURE + || Z_TYPE_PP(gpc_element_p) != IS_ARRAY) { + MAKE_STD_ZVAL(gpc_element); + array_init(gpc_element); + zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); + } + if (index != escaped_index) { + efree(escaped_index); + } + } + symtable1 = Z_ARRVAL_PP(gpc_element_p); + /* ip pointed to the '[' character, now obtain the key */ + index = index_s; + index_len = new_idx_len; + + ip++; + if (*ip == '[') { + is_array = 1; + *ip = 0; + } else { + goto plain_var; + } + } + } else { +plain_var: + MAKE_STD_ZVAL(gpc_element); + gpc_element->value = val->value; + Z_TYPE_P(gpc_element) = Z_TYPE_P(val); + if (!index) { + zend_hash_next_index_insert(symtable1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); + } else { + if (PG(magic_quotes_gpc)) { + escaped_index = php_addslashes(index, index_len, &index_len, 0 TSRMLS_CC); + } else { + escaped_index = index; + } + /* + * According to rfc2965, more specific paths are listed above the less specific ones. + * If we encounter a duplicate cookie name, we should skip it, since it is not possible + * to have the same (plain text) cookie name for the same path and we should not overwrite + * more specific cookies with the less specific ones. + */ + if (zend_symtable_exists(symtable1, escaped_index, index_len + 1)) { + zval_ptr_dtor(&gpc_element); + } else { + zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p); + } + if (escaped_index != index) { + efree(escaped_index); + } + } + } +} +/* }}} */ + +static void suhosin_register_cookie_variable_safe(char *var, char *strval, int str_len, zval *track_vars_array TSRMLS_DC) +{ + zval new_entry; + assert(strval != NULL); + + /* Prepare value */ + Z_STRLEN(new_entry) = str_len; + if (PG(magic_quotes_gpc)) { + Z_STRVAL(new_entry) = php_addslashes(strval, Z_STRLEN(new_entry), &Z_STRLEN(new_entry), 0 TSRMLS_CC); + } else { + Z_STRVAL(new_entry) = estrndup(strval, Z_STRLEN(new_entry)); + } + Z_TYPE(new_entry) = IS_STRING; + + suhosin_register_cookie_variable(var, &new_entry, track_vars_array TSRMLS_CC); +} + + +/* {{{ proto string suhosin_encrypt_cookie(string name, string value) + Encrypts a cookie value according to current cookie encrpytion setting */ +static PHP_FUNCTION(suhosin_encrypt_cookie) +{ + char *name, *value; + int name_len, value_len; + char cryptkey[33]; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &name, &name_len, &value, &value_len) == FAILURE) { + return; + } + + if (!SUHOSIN_G(cookie_encrypt)) { +return_plain: + RETURN_STRINGL(value, value_len, 1); + } + + if (SUHOSIN_G(cookie_plainlist)) { + if (zend_hash_exists(SUHOSIN_G(cookie_plainlist), name, name_len+1)) { + goto return_plain; + } + } else if (SUHOSIN_G(cookie_cryptlist)) { + if (!zend_hash_exists(SUHOSIN_G(cookie_cryptlist), name, name_len+1)) { + goto return_plain; + } + } + + suhosin_generate_key(SUHOSIN_G(cookie_cryptkey), SUHOSIN_G(cookie_cryptua), SUHOSIN_G(cookie_cryptdocroot), SUHOSIN_G(cookie_cryptraddr), (char *)&cryptkey TSRMLS_CC); + value = suhosin_encrypt_string(value, value_len, name, name_len, (char *)&cryptkey TSRMLS_CC); + + RETVAL_STRING(value, 0); +} +/* }}} */ + +/* {{{ proto mixed suhosin_get_raw_cookies() + Returns an array containing the raw cookie values */ +static PHP_FUNCTION(suhosin_get_raw_cookies) +{ + char *var, *val, *res; + zval *array_ptr = return_value; + char *strtok_buf = NULL; + int val_len; + + array_init(array_ptr); + + if (SUHOSIN_G(raw_cookie)) { + res = estrdup(SUHOSIN_G(raw_cookie)); + } else { + return; + } + + var = php_strtok_r(res, ";", &strtok_buf); + + while (var) { + val = strchr(var, '='); + if (val) { /* have a value */ + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); + suhosin_register_cookie_variable_safe(var, val, val_len, array_ptr TSRMLS_CC); + } else { + php_url_decode(var, strlen(var)); + val_len = 0; + val = ""; + suhosin_register_cookie_variable_safe(var, "", 0, array_ptr TSRMLS_CC); + } + var = php_strtok_r(NULL, ";", &strtok_buf); + } + + efree(res); +} +/* }}} */ + + + +/* {{{ suhosin_functions[] + */ +zend_function_entry suhosin_functions[] = { + PHP_NAMED_FE(suhosin_encrypt_cookie, PHP_FN(suhosin_encrypt_cookie), NULL) + PHP_NAMED_FE(suhosin_get_raw_cookies, PHP_FN(suhosin_get_raw_cookies), NULL) + {NULL, NULL, NULL} /* Must be the last line in suhosin_functions[] */ +}; +/* }}} */ + +/* {{{ suhosin_module_entry + */ +zend_module_entry suhosin_module_entry = { +#if ZEND_MODULE_API_NO >= 20010901 + STANDARD_MODULE_HEADER, +#endif + "suhosin", + suhosin_functions, + PHP_MINIT(suhosin), + PHP_MSHUTDOWN(suhosin), + PHP_RINIT(suhosin), + PHP_RSHUTDOWN(suhosin), + PHP_MINFO(suhosin), +#if ZEND_MODULE_API_NO >= 20010901 + SUHOSIN_EXT_VERSION, /* Replace with version number for your extension */ +#endif + STANDARD_MODULE_PROPERTIES +}; +/* }}} */ + +#ifdef COMPILE_DL_SUHOSIN +ZEND_GET_MODULE(suhosin) +#endif + +/* {{{ PHP_INI + */ +static zend_ini_entry shared_ini_entries[] = { + ZEND_INI_ENTRY("suhosin.log.syslog", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_syslog) + ZEND_INI_ENTRY("suhosin.log.syslog.facility", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_syslog_facility) + ZEND_INI_ENTRY("suhosin.log.syslog.priority", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_syslog_priority) + ZEND_INI_ENTRY("suhosin.log.sapi", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_sapi) + ZEND_INI_ENTRY("suhosin.log.script", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_script) + ZEND_INI_ENTRY("suhosin.log.script.name", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_scriptname) + STD_ZEND_INI_BOOLEAN("suhosin.log.use-x-forwarded-for", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateLogBool, log_use_x_forwarded_for, zend_suhosin_globals, suhosin_globals) + ZEND_INI_ENTRY("suhosin.log.phpscript", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_phpscript) + STD_ZEND_INI_ENTRY("suhosin.log.phpscript.name", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateLogString, log_phpscriptname, zend_suhosin_globals, suhosin_globals) + ZEND_INI_ENTRY("suhosin.log.file", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSuhosin_log_file) + STD_ZEND_INI_ENTRY("suhosin.log.file.name", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateLogString, log_filename, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.log.phpscript.is_safe", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateLogBool, log_phpscript_is_safe, zend_suhosin_globals, suhosin_globals) +ZEND_INI_END() + +PHP_INI_BEGIN() + ZEND_INI_ENTRY("suhosin.perdir", "0", ZEND_INI_SYSTEM, OnUpdateSuhosin_perdir) + STD_ZEND_INI_ENTRY("suhosin.executor.include.max_traversal", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateExecLong, executor_include_max_traversal, zend_suhosin_globals, suhosin_globals) + ZEND_INI_ENTRY("suhosin.executor.include.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdate_include_whitelist) + ZEND_INI_ENTRY("suhosin.executor.include.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdate_include_blacklist) + STD_ZEND_INI_BOOLEAN("suhosin.executor.include.allow_writable_files", "1", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateExecBool, executor_include_allow_writable_files, zend_suhosin_globals, suhosin_globals) + ZEND_INI_ENTRY("suhosin.executor.eval.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdate_eval_whitelist) + ZEND_INI_ENTRY("suhosin.executor.eval.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdate_eval_blacklist) + ZEND_INI_ENTRY("suhosin.executor.func.whitelist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdate_func_whitelist) + ZEND_INI_ENTRY("suhosin.executor.func.blacklist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdate_func_blacklist) + STD_ZEND_INI_BOOLEAN("suhosin.executor.disable_eval", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateExecBool, executor_disable_eval, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.executor.disable_emodifier", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateExecBool, executor_disable_emod, zend_suhosin_globals, suhosin_globals) + + STD_ZEND_INI_BOOLEAN("suhosin.executor.allow_symlink", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateExecBool, executor_allow_symlink, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_ENTRY("suhosin.executor.max_depth", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateExecLong, max_execution_depth, zend_suhosin_globals, suhosin_globals) + + + STD_ZEND_INI_BOOLEAN("suhosin.multiheader", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateMiscBool, allow_multiheader, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_ENTRY("suhosin.mail.protect", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateMiscLong, mailprotect, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_ENTRY("suhosin.memory_limit", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateMiscLong, memory_limit, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.simulation", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateMiscBool, simulation, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.filter.action", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateMiscString, filter_action, zend_suhosin_globals, suhosin_globals) + + STD_ZEND_INI_BOOLEAN("suhosin.protectkey", "1", ZEND_INI_SYSTEM, OnUpdateBool, protectkey, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.coredump", "0", ZEND_INI_SYSTEM, OnUpdateBool, coredump, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.stealth", "1", ZEND_INI_SYSTEM, OnUpdateBool, stealth, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.apc_bug_workaround", "0", ZEND_INI_SYSTEM, OnUpdateBool, apc_bug_workaround, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.disable.display_errors", "0", ZEND_INI_SYSTEM, OnUpdateBool, disable_display_errors, zend_suhosin_globals, suhosin_globals) + + + + STD_PHP_INI_ENTRY("suhosin.request.max_vars", "1000", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateRequestLong, max_request_variables, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.request.max_varname_length", "64", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateRequestLong, max_varname_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.request.max_value_length", "1000000", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateRequestLong, max_value_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.request.max_array_depth", "50", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateRequestLong, max_array_depth, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.request.max_totalname_length", "256", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateRequestLong, max_totalname_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.request.max_array_index_length", "64", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateRequestLong, max_array_index_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.request.disallow_nul", "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateRequestBool, disallow_nul, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.request.disallow_ws", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateRequestBool, disallow_ws, zend_suhosin_globals, suhosin_globals) + + STD_PHP_INI_ENTRY("suhosin.cookie.max_vars", "100", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateCookieLong, max_cookie_vars, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.cookie.max_name_length", "64", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateCookieLong, max_cookie_name_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.cookie.max_totalname_length", "256", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateCookieLong, max_cookie_totalname_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.cookie.max_value_length", "10000", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateCookieLong, max_cookie_value_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.cookie.max_array_depth", "50", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateCookieLong, max_cookie_array_depth, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.cookie.max_array_index_length", "64", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateCookieLong, max_cookie_array_index_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.cookie.disallow_nul", "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateCookieBool, disallow_cookie_nul, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.cookie.disallow_ws", "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateCookieBool, disallow_cookie_ws, zend_suhosin_globals, suhosin_globals) + + STD_PHP_INI_ENTRY("suhosin.get.max_vars", "100", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateGetLong, max_get_vars, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.get.max_name_length", "64", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateGetLong, max_get_name_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.get.max_totalname_length", "256", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateGetLong, max_get_totalname_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.get.max_value_length", "512", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateGetLong, max_get_value_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.get.max_array_depth", "50", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateGetLong, max_get_array_depth, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.get.max_array_index_length", "64", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateGetLong, max_get_array_index_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.get.disallow_nul", "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateGetBool, disallow_get_nul, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.get.disallow_ws", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateGetBool, disallow_get_ws, zend_suhosin_globals, suhosin_globals) + + STD_PHP_INI_ENTRY("suhosin.post.max_vars", "1000", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdatePostLong, max_post_vars, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.post.max_name_length", "64", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdatePostLong, max_post_name_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.post.max_totalname_length", "256", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdatePostLong, max_post_totalname_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.post.max_value_length", "1000000", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdatePostLong, max_post_value_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.post.max_array_depth", "50", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdatePostLong, max_post_array_depth, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.post.max_array_index_length", "64", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdatePostLong, max_post_array_index_length, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.post.disallow_nul", "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdatePostBool, disallow_post_nul, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.post.disallow_ws", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdatePostBool, disallow_post_ws, zend_suhosin_globals, suhosin_globals) + + STD_PHP_INI_ENTRY("suhosin.upload.max_uploads", "25", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadLong, upload_limit, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.upload.disallow_elf", "1", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadBool, upload_disallow_elf, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.upload.disallow_binary", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadBool, upload_disallow_binary, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.upload.remove_binary", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadBool, upload_remove_binary, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.upload.verification_script", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateUploadString, upload_verification_script, zend_suhosin_globals, suhosin_globals) + + + STD_ZEND_INI_BOOLEAN("suhosin.sql.bailout_on_error", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateSQLBool, sql_bailout_on_error, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.sql.user_prefix", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLString, sql_user_prefix, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.sql.user_postfix", NULL, PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLString, sql_user_postfix, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.sql.comment", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_comment, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.sql.opencomment", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_opencomment, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.sql.multiselect", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_mselect, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.sql.union", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateSQLLong, sql_union, zend_suhosin_globals, suhosin_globals) + + STD_ZEND_INI_BOOLEAN("suhosin.session.encrypt", "1", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, session_encrypt, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.session.cryptkey", "", PHP_INI_ALL, OnUpdateString, session_cryptkey, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.session.cryptua", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, session_cryptua, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.session.cryptdocroot", "1", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, session_cryptdocroot, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.session.cryptraddr", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLong, session_cryptraddr, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.session.checkraddr", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLong, session_checkraddr, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.session.max_id_length", "128", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLong, session_max_id_length, zend_suhosin_globals, suhosin_globals) + + + STD_ZEND_INI_BOOLEAN("suhosin.cookie.encrypt", "0", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, cookie_encrypt, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.cookie.cryptkey", "", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateString, cookie_cryptkey, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.cookie.cryptua", "1", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, cookie_cryptua, zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.cookie.cryptdocroot", "1", ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdateBool, cookie_cryptdocroot, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.cookie.cryptraddr", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLong, cookie_cryptraddr, zend_suhosin_globals, suhosin_globals) + STD_PHP_INI_ENTRY("suhosin.cookie.checkraddr", "0", PHP_INI_SYSTEM|PHP_INI_PERDIR, OnUpdateLong, cookie_checkraddr, zend_suhosin_globals, suhosin_globals) + ZEND_INI_ENTRY("suhosin.cookie.cryptlist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdate_cookie_cryptlist) + ZEND_INI_ENTRY("suhosin.cookie.plainlist", NULL, ZEND_INI_PERDIR|ZEND_INI_SYSTEM, OnUpdate_cookie_plainlist) + + + STD_ZEND_INI_BOOLEAN("suhosin.server.encode", "1", ZEND_INI_SYSTEM, OnUpdateBool, server_encode,zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.server.strip", "1", ZEND_INI_SYSTEM, OnUpdateBool, server_strip,zend_suhosin_globals, suhosin_globals) + + STD_ZEND_INI_BOOLEAN("suhosin.srand.ignore", "1", ZEND_INI_SYSTEM|ZEND_INI_PERDIR, OnUpdateMiscBool, srand_ignore,zend_suhosin_globals, suhosin_globals) + STD_ZEND_INI_BOOLEAN("suhosin.mt_srand.ignore", "1", ZEND_INI_SYSTEM|ZEND_INI_PERDIR, OnUpdateMiscBool, mt_srand_ignore,zend_suhosin_globals, suhosin_globals) + +PHP_INI_END() +/* }}} */ + + +/* {{{ php_suhosin_init_globals + */ +void suhosin_bailout(TSRMLS_D) +{ + if (!SUHOSIN_G(simulation)) { + zend_bailout(); + } +} +/* }}} */ + +/* {{{ php_suhosin_init_globals + */ +STATIC void php_suhosin_init_globals(zend_suhosin_globals *suhosin_globals) +{ + memset(suhosin_globals, 0, sizeof(zend_suhosin_globals)); +} +/* }}} */ + +/* {{{ PHP_MINIT_FUNCTION + */ +PHP_MINIT_FUNCTION(suhosin) +{ + SDEBUG("(MINIT)"); + ZEND_INIT_MODULE_GLOBALS(suhosin, php_suhosin_init_globals, NULL); + + /* only register constants if they have not previously been registered by a possible patched PHP */ + + if (zend_hash_exists(EG(zend_constants), "S_MEMORY", sizeof("S_MEMORY"))==0) { + 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_MAIL", S_MAIL, CONST_PERSISTENT | CONST_CS); + REGISTER_MAIN_LONG_CONSTANT("S_SESSION", S_SESSION, 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); + } + + /* check if shared ini directives are already known (maybe a patched PHP) */ + if (zend_hash_exists(EG(ini_directives), "suhosin.log.syslog", sizeof("suhosin.log.syslog"))) { + + /* and update them */ + zend_ini_entry *p = (zend_ini_entry *)&shared_ini_entries; + + while (p->name) { + + zend_ini_entry *i; + + if (zend_hash_find(EG(ini_directives), p->name, p->name_length, (void **) &i)==FAILURE) { + /* continue registering them */ + zend_register_ini_entries(p, module_number TSRMLS_CC); + break; + } + + SDEBUG("updating ini %s=%s", i->name, i->value); + +#ifdef ZEND_ENGINE_2 + i->modifiable = p->modifiable; +#else + i->modifyable = p->modifyable; +#endif + i->module_number = module_number; + i->on_modify = p->on_modify; + i->mh_arg1 = p->mh_arg1; + i->mh_arg2 = p->mh_arg2; + i->mh_arg3 = p->mh_arg3; + i->on_modify(i, i->value, i->value_length, i->mh_arg1, i->mh_arg2, i->mh_arg3, ZEND_INI_STAGE_STARTUP TSRMLS_CC); + p++; + } + } else { + + /* not registered yet, then simply use the API */ + zend_register_ini_entries((zend_ini_entry *)&shared_ini_entries, module_number TSRMLS_CC); + + } + + /* and register the rest of the ini entries */ + REGISTER_INI_ENTRIES(); + + /* Force display_errors=off */ + if (SUHOSIN_G(disable_display_errors)) { + zend_ini_entry *i; + if (zend_hash_find(EG(ini_directives), "display_errors", sizeof("display_errors"), (void **) &i) == SUCCESS) { + if (i->on_modify) { + i->on_modify(i, "0", sizeof("0"), i->mh_arg1, i->mh_arg2, i->mh_arg3, ZEND_INI_STAGE_STARTUP TSRMLS_CC); + i->on_modify = NULL; + } + } + } + + /* Load invisible to other Zend Extensions */ + if (zend_llist_count(&zend_extensions)==0 || SUHOSIN_G(stealth)==0) { + zend_extension extension; + extension = suhosin_zend_extension_entry; + extension.handle = NULL; + zend_llist_add_element(&zend_extensions, &extension); + ze = NULL; + } else { + ze = (zend_extension *)zend_llist_get_last_ex(&zend_extensions, &lp); + old_startup = ze->startup; + ze->startup = suhosin_startup_wrapper; + } + + /* now hook a bunch of stuff */ + suhosin_hook_memory_limit(); + suhosin_hook_crypt(); + suhosin_hook_sha256(); + suhosin_hook_ex_imp(); + + /* register the logo for phpinfo */ + php_register_info_logo(SUHOSIN_LOGO_GUID, "image/jpeg", suhosin_logo, sizeof(suhosin_logo)); + +#if PHP_MAJOR_VERSION > 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1) + /* perform LFS check */ +/* time_t check = sapi_get_request_time(TSRMLS_C); + if (SG(global_request_time) != check) { + zend_error(E_ERROR, "It seems that PHP and Suhosin were compiled with different binary layouts. " + "This will cause problems like POST not working. Please tell your distributor to fix this."); + }*/ +#endif + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_MSHUTDOWN_FUNCTION + */ +PHP_MSHUTDOWN_FUNCTION(suhosin) +{ + SDEBUG("(MSHUTDOWN)"); + UNREGISTER_INI_ENTRIES(); + return SUCCESS; +} +/* }}} */ + + +/* {{{ PHP_RINIT_FUNCTION + */ +PHP_RINIT_FUNCTION(suhosin) +{ + SDEBUG("(RINIT)"); + SUHOSIN_G(in_code_type) = SUHOSIN_NORMAL; + SUHOSIN_G(execution_depth) = 0; + + return SUCCESS; +} +/* }}} */ + + +/* {{{ PHP_RSHUTDOWN_FUNCTION + */ +PHP_RSHUTDOWN_FUNCTION(suhosin) +{ + SDEBUG("(RSHUTDOWN)"); + + /* We need to clear the input filtering + variables in the request shutdown + because input filtering is done before + RINIT */ + + SUHOSIN_G(cur_request_variables) = 0; + SUHOSIN_G(cur_cookie_vars) = 0; + SUHOSIN_G(cur_get_vars) = 0; + SUHOSIN_G(cur_post_vars) = 0; + SUHOSIN_G(num_uploads) = 0; + + SUHOSIN_G(no_more_variables) = 0; + SUHOSIN_G(no_more_get_variables) = 0; + SUHOSIN_G(no_more_post_variables) = 0; + SUHOSIN_G(no_more_cookie_variables) = 0; + SUHOSIN_G(no_more_uploads) = 0; + + SUHOSIN_G(abort_request) = 0; + + if (SUHOSIN_G(decrypted_cookie)) { + efree(SUHOSIN_G(decrypted_cookie)); + SUHOSIN_G(decrypted_cookie)=NULL; + } + if (SUHOSIN_G(raw_cookie)) { + efree(SUHOSIN_G(raw_cookie)); + SUHOSIN_G(raw_cookie)=NULL; + } + + return SUCCESS; +} +/* }}} */ + +/* {{{ suhosin_ini_displayer(zend_ini_entry *ini_entry, int type) + */ +static void suhosin_ini_displayer(zend_ini_entry *ini_entry, int type) +{ + TSRMLS_FETCH(); + + PHPWRITE("[ protected ]", strlen("[ protected ]")); +} +/* }}} */ + +/* {{{ PHP_MINFO_FUNCTION + */ +PHP_MINFO_FUNCTION(suhosin) +{ + php_info_print_box_start(0); + if (!sapi_module.phpinfo_as_text) { + if (PG(expose_php)) { + PUTS("\"Suhosin\n"); + } else do { + char *enc_logo; + int ret; + zval **agent_name; + +#ifdef ZEND_ENGINE_2 + zend_is_auto_global("_SERVER", sizeof("_SERVER")-1 TSRMLS_CC); +#endif + if (!PG(http_globals)[TRACK_VARS_SERVER] || + zend_hash_find(PG(http_globals)[TRACK_VARS_SERVER]->value.ht, "HTTP_USER_AGENT", sizeof("HTTP_USER_AGENT"), (void **) &agent_name)==FAILURE) { + break; + } + if (Z_TYPE_PP(agent_name) != IS_STRING) { + break; + } + if (strstr(Z_STRVAL_PP(agent_name), "Gecko") == NULL && strstr(Z_STRVAL_PP(agent_name), "Opera") == NULL) { + break; + } + PUTS("\"Suhosin\n"); + } while(0); + } + PUTS("This server is protected with the Suhosin Extension " SUHOSIN_EXT_VERSION); + PUTS(!sapi_module.phpinfo_as_text?"

":"\n\n"); + if (sapi_module.phpinfo_as_text) { + PUTS("Copyright (c) 2006-2007 Hardened-PHP Project\n"); + PUTS("Copyright (c) 2007-2008 SektionEins GmbH\n"); + } else { + PUTS("Copyright (c) 2006-2007 Hardened-PHP Project
\n"); + PUTS("Copyright (c) 2007-2008 SektionEins GmbH\n"); + } + php_info_print_box_end(); + + if (SUHOSIN_G(protectkey)) { + zend_ini_entry *i; + + if (zend_hash_find(EG(ini_directives), "suhosin.cookie.cryptkey", sizeof("suhosin.cookie.cryptkey"), (void **) &i)==SUCCESS) { + i->displayer = suhosin_ini_displayer; + } + if (zend_hash_find(EG(ini_directives), "suhosin.session.cryptkey", sizeof("suhosin.session.cryptkey"), (void **) &i)==SUCCESS) { + i->displayer = suhosin_ini_displayer; + } + } + + DISPLAY_INI_ENTRIES(); + + if (SUHOSIN_G(protectkey)) { + zend_ini_entry *i; + + if (zend_hash_find(EG(ini_directives), "suhosin.cookie.cryptkey", sizeof("suhosin.cookie.cryptkey"), (void **) &i)==SUCCESS) { + i->displayer = NULL; + } + if (zend_hash_find(EG(ini_directives), "suhosin.session.cryptkey", sizeof("suhosin.session.cryptkey"), (void **) &i)==SUCCESS) { + i->displayer = NULL; + } + } + +} +/* }}} */ + +/* + * 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 --git a/suhosin.ini b/suhosin.ini new file mode 100644 index 0000000..9696e7b --- /dev/null +++ b/suhosin.ini @@ -0,0 +1,444 @@ +extension = suhosin.so + +; ----------------------------------------------------------------------------- +; This file was taken from Mandriva Linux with their permission +; ----------------------------------------------------------------------------- + +[suhosin] + +; ----------------------------------------------------------------------------- +; Logging Options + +; Defines what classes of security alerts are logged to the syslog daemon. +; Logging of errors of the class S_MEMORY are always logged to syslog, no +; matter what this configuration says, because a corrupted heap could mean that +; the other logging options will malfunction during the logging process. +;suhosin.log.syslog = + +; Defines the syslog facility that is used when ALERTs are logged to syslog. +;suhosin.log.syslog.facility = + +; Defines the syslog priority that is used when ALERTs are logged to syslog. +;suhosin.log.syslog.priority = + +; Defines what classes of security alerts are logged through the SAPI error log. +;suhosin.log.sapi = + +; Defines what classes of security alerts are logged through the external +; logging. +;suhosin.log.script = + +; Defines what classes of security alerts are logged through the defined PHP +; script. +;suhosin.log.phpscript = 0 + +; Defines the full path to a external logging script. The script is called with +; 2 parameters. The first one is the alert class in string notation and the +; second parameter is the log message. This can be used for example to mail +; failing MySQL queries to your email address, because on a production system +; these things should never happen. +;suhosin.log.script.name = + +; Defines the full path to a PHP logging script. The script is called with 2 +; variables registered in the current scope: SUHOSIN_ERRORCLASS and +; SUHOSIN_ERROR. The first one is the alert class and the second variable is +; the log message. This can be used for example to mail attempted remote URL +; include attacks to your email address. +;suhosin.log.phpscript.name = + +; Undocumented +;suhosin.log.phpscript.is_safe = Off + +; When the Hardening-Patch logs an error the log message also contains the IP +; of the attacker. Usually this IP is retrieved from the REMOTE_ADDR SAPI +; environment variable. With this switch it is possible to change this behavior +; to read the IP from the X-Forwarded-For HTTP header. This is f.e. necessary +; when your PHP server runs behind a reverse proxy. +;suhosin.log.use-x-forwarded-for = Off + +; ----------------------------------------------------------------------------- +; Executor Options + +; Defines the maximum stack depth allowed by the executor before it stops the +; script. Without this function an endless recursion in a PHP script could +; crash the PHP executor or trigger the configured memory_limit. A value of +; "0" disables this feature. +;suhosin.executor.max_depth = 0 + +; Defines how many "../" an include filename needs to contain to be considered +; an attack and stopped. A value of "2" will block "../../etc/passwd", while a +; value of "3" will allow it. Most PHP applications should work flawlessly with +; values "4" or "5". A value of "0" disables this feature. +;suhosin.executor.include.max_traversal = 0 + +; Comma separated whitelist of URL schemes that are allowed to be included from +; include or require statements. Additionally to URL schemes it is possible to +; specify the beginning of allowed URLs. (f.e.: php://stdin) If no whitelist is +; specified, then the blacklist is evaluated. +;suhosin.executor.include.whitelist = + +; Comma separated blacklist of URL schemes that are not allowed to be included +; from include or require statements. Additionally to URL schemes it is +; possible to specify the beginning of allowed URLs. (f.e.: php://stdin) If no +; blacklist and no whitelist is specified all URL schemes are forbidden. +;suhosin.executor.include.blacklist = + +; Defines if PHP is allows to run code from files that are writable by the +; current process. If a file is created or modified by a PHP process, there +; is a potential danger of code injection. Only turn this on if you are sure +; that your application does not require writable PHP files. +;suhosin.executor.include.allow_writable_files = On + +; Comma separated whitelist of functions that are allowed to be called. If the +; whitelist is empty the blacklist is evaluated, otherwise calling a function +; not in the whitelist will terminate the script and get logged. +;suhosin.executor.func.whitelist = + +; Comma separated blacklist of functions that are not allowed to be called. If +; no whitelist is given, calling a function within the blacklist will terminate +; the script and get logged. +;suhosin.executor.func.blacklist = + +; Comma separated whitelist of functions that are allowed to be called from +; within eval(). If the whitelist is empty the blacklist is evaluated, +; otherwise calling a function not in the whitelist will terminate the script +; and get logged. +;suhosin.executor.eval.whitelist = + +; Comma separated blacklist of functions that are not allowed to be called from +; within eval(). If no whitelist is given, calling a function within the +; blacklist will terminate the script and get logged. +;suhosin.executor.eval.blacklist = + +; eval() is a very dangerous statement and therefore you might want to disable +; it completely. Deactivating it will however break lots of scripts. Because +; every violation is logged, this allows finding all places where eval() is +; used. +;suhosin.executor.disable_eval = Off + +; The /e modifier inside preg_replace() allows code execution. Often it is the +; cause for remote code execution exploits. It is wise to deactivate this +; feature and test where in the application it is used. The developer using the +; /e modifier should be made aware that he should use preg_replace_callback() +; instead. +;suhosin.executor.disable_emodifier = Off + +; This flag reactivates symlink() when open_basedir is used, which is disabled +; by default in Suhosin >= 0.9.6. Allowing symlink() while open_basedir is used +; is actually a security risk. +;suhosin.executor.allow_symlink = Off + +; ----------------------------------------------------------------------------- +; Misc Options + +; If you fear that Suhosin breaks your application, you can activate Suhosin's +; simulation mode with this flag. When Suhosin runs in simulation mode, +; violations are logged as usual, but nothing is blocked or removed from the +; request. (Transparent Encryptions are NOT deactivated in simulation mode.) +;suhosin.simulation = Off + +; APC 3.0.12(p1/p2) uses reserved resources without requesting a resource slot +; first. It always uses resource slot 0. If Suhosin got this slot assigned APC +; will overwrite the information Suhosin stores in this slot. When this flag is +; set Suhosin will request 2 Slots and use the second one. This allows working +; correctly with these buggy APC versions. +;suhosin.apc_bug_workaround = Off + +; When a SQL Query fails scripts often spit out a bunch of useful information +; for possible attackers. When this configuration directive is turned on, the +; script will silently terminate, after the problem has been logged. (This is +; not yet supported) +;suhosin.sql.bailout_on_error = Off + +; This is an experimental feature for shared environments. With this +; configuration option it is possible to specify a prefix that is automatically +; prepended to the database username, whenever a database connection is made. +; (Unless the username starts with the prefix) +;suhosin.sql.user_prefix = + +; This is an experimental feature for shared environments. With this +; configuration option it is possible to specify a postfix that is +; automatically appended to the database username, whenever a database +; connection is made. (Unless the username end with the postfix) +; +; With this feature it is possible for shared hosters to disallow customers to +; connect with the usernames of other customers. This feature is experimental, +; because support for PDO and PostgreSQL are not yet implemented. +;suhosin.sql.user_postfix = + +; This directive controls if multiple headers are allowed or not in a header() +; call. By default the Hardening-Patch forbids this. (HTTP headers spanning +; multiple lines are still allowed). +;suhosin.multiheader = Off + +; This directive controls if the mail() header protection is activated or not +; and to what degree it is activated. The appended table lists the possible +; activation levels. +suhosin.mail.protect = 1 + +; As long scripts are not running within safe_mode they are free to change the +; memory_limit to whatever value they want. Suhosin changes this fact and +; disallows setting the memory_limit to a value greater than the one the script +; started with, when this option is left at 0. A value greater than 0 means +; that Suhosin will disallows scripts setting the memory_limit to a value above +; this configured hard limit. This is for example usefull if you want to run +; the script normaly with a limit of 16M but image processing scripts may raise +; it to 20M. +;suhosin.memory_limit = 0 + +; ----------------------------------------------------------------------------- +; Transparent Encryption Options + +; Flag that decides if the transparent session encryption is activated or not. +;suhosin.session.encrypt = On + +; Session data can be encrypted transparently. The encryption key used consists +; of this user defined string (which can be altered by a script via ini_set()) +; and optionally the User-Agent, the Document-Root and 0-4 Octects of the +; REMOTE_ADDR. +;suhosin.session.cryptkey = + +; Flag that decides if the transparent session encryption key depends on the +; User-Agent field. (When activated this feature transparently adds a little +; bit protection against session fixation/hijacking attacks) +;suhosin.session.cryptua = On + +; Flag that decides if the transparent session encryption key depends on the +; Documentroot field. +;suhosin.session.cryptdocroot = On + +; Number of octets (0-4) from the REMOTE_ADDR that the transparent session +; encryption key depends on. Keep in mind that this should not be used on sites +; that have visitors from big ISPs, because their IP address often changes +; during a session. But this feature might be interesting for admin interfaces +; or intranets. When used wisely this is a transparent protection against +; session hijacking/fixation. +;suhosin.session.cryptraddr = 0 + +; Number of octets (0-4) from the REMOTE_ADDR that have to match to decrypt the +; session. The difference to suhosin.session.cryptaddr is, that the IP is not +; part of the encryption key, so that the same session can be used for +; different areas with different protection levels on the site. +;suhosin.session.checkraddr = 0 + +; Flag that decides if the transparent cookie encryption is activated or not. +;suhosin.cookie.encrypt = 0 + +; Cookies can be encrypted transparently. The encryption key used consists of +; this user defined string and optionally the User-Agent, the Document-Root and +; 0-4 Octects of the REMOTE_ADDR. +;suhosin.cookie.cryptkey = + +; Flag that decides if the transparent session encryption key depends on the +; User-Agent field. (When activated this feature transparently adds a little +; bit protection against session fixation/hijacking attacks (if only session +; cookies are allowed)) +;suhosin.cookie.cryptua = On + +; Flag that decides if the transparent cookie encryption key depends on the +; Documentroot field. +;suhosin.cookie.cryptdocroot = On + +; Number of octets (0-4) from the REMOTE_ADDR that the transparent cookie +; encryption key depends on. Keep in mind that this should not be used on sites +; that have visitors from big ISPs, because their IP address often changes +; during a session. But this feature might be interesting for admin interfaces +; or intranets. When used wisely this is a transparent protection against +; session hijacking/fixation. +;suhosin.cookie.cryptraddr = 0 + +; Number of octets (0-4) from the REMOTE_ADDR that have to match to decrypt the +; cookie. The difference to suhosin.cookie.cryptaddr is, that the IP is not +; part of the encryption key, so that the same cookie can be used for different +; areas with different protection levels on the site. +;suhosin.cookie.checkraddr = 0 + +; In case not all cookies are supposed to get encrypted this is a comma +; separated list of cookie names that should get encrypted. All other cookies +; will not get touched. +;suhosin.cookie.cryptlist = + +; In case some cookies should not be crypted this is a comma separated list of +; cookies that do not get encrypted. All other cookies will be encrypted. +;suhosin.cookie.plainlist = + +; ----------------------------------------------------------------------------- +; Filtering Options + +; Defines the reaction of Suhosin on a filter violation. +;suhosin.filter.action = + +; Defines the maximum depth an array variable may have, when registered through +; the COOKIE. +;suhosin.cookie.max_array_depth = 50 + +; Defines the maximum length of array indices for variables registered through +; the COOKIE. +;suhosin.cookie.max_array_index_length = 64 + +; Defines the maximum length of variable names for variables registered through +; the COOKIE. For array variables this is the name in front of the indices. +;suhosin.cookie.max_name_length = 64 + +; Defines the maximum length of the total variable name when registered through +; the COOKIE. For array variables this includes all indices. +;suhosin.cookie.max_totalname_length = 256 + +; Defines the maximum length of a variable that is registered through the +; COOKIE. +;suhosin.cookie.max_value_length = 10000 + +; Defines the maximum number of variables that may be registered through the +; COOKIE. +;suhosin.cookie.max_vars = 100 + +; When set to On ASCIIZ chars are not allowed in variables. +;suhosin.cookie.disallow_nul = 1 + +; Defines the maximum depth an array variable may have, when registered through +; the URL +;suhosin.get.max_array_depth = 50 + +; Defines the maximum length of array indices for variables registered through +; the URL +;suhosin.get.max_array_index_length = 64 + +; Defines the maximum length of variable names for variables registered through +; the URL. For array variables this is the name in front of the indices. +;suhosin.get.max_name_length = 64 + +; Defines the maximum length of the total variable name when registered through +; the URL. For array variables this includes all indices. +;suhosin.get.max_totalname_length = 256 + +; Defines the maximum length of a variable that is registered through the URL. +;suhosin.get.max_value_length = 512 + +; Defines the maximum number of variables that may be registered through the +; URL. +;suhosin.get.max_vars = 100 + +; When set to On ASCIIZ chars are not allowed in variables. +;suhosin.get.disallow_nul = 1 + +; Defines the maximum depth an array variable may have, when registered through +; a POST request. +;suhosin.post.max_array_depth = 50 + +; Defines the maximum length of array indices for variables registered through +; a POST request. +;suhosin.post.max_array_index_length = 64 + +; Defines the maximum length of variable names for variables registered through +; a POST request. For array variables this is the name in front of the indices. +;suhosin.post.max_name_length = 64 + +; Defines the maximum length of the total variable name when registered through +; a POST request. For array variables this includes all indices. +;suhosin.post.max_totalname_length = 256 + +; Defines the maximum length of a variable that is registered through a POST +; request. +;suhosin.post.max_value_length = 1000000 + +; Defines the maximum number of variables that may be registered through a POST +; request. +;suhosin.post.max_vars = 1000 + +; When set to On ASCIIZ chars are not allowed in variables. +;suhosin.post.disallow_nul = 1 + +; Defines the maximum depth an array variable may have, when registered through +; GET , POST or COOKIE. This setting is also an upper limit for the separate +; GET, POST, COOKIE configuration directives. +;suhosin.request.max_array_depth = 50 + +; Defines the maximum length of array indices for variables registered through +; GET, POST or COOKIE. This setting is also an upper limit for the separate +; GET, POST, COOKIE configuration directives. +;suhosin.request.max_array_index_length = 64 + +; Defines the maximum length of variable names for variables registered through +; the COOKIE, the URL or through a POST request. This is the complete name +; string, including all indicies. This setting is also an upper limit for the +; separate GET, POST, COOKIE configuration directives. +;suhosin.request.max_totalname_length = 256 + +; Defines the maximum length of a variable that is registered through the +; COOKIE, the URL or through a POST request. This setting is also an upper +; limit for the variable origin specific configuration directives. +;suhosin.request.max_value_length = 1000000 + +; Defines the maximum number of variables that may be registered through the +; COOKIE, the URL or through a POST request. This setting is also an upper +; limit for the variable origin specific configuration directives. +;suhosin.request.max_vars = 1000 + +; Defines the maximum name length (excluding possible array indicies) of +; variables that may be registered through the COOKIE, the URL or through a +; POST request. This setting is also an upper limit for the variable origin +; specific configuration directives. +;suhosin.request.max_varname_length = 64 + +; When set to On ASCIIZ chars are not allowed in variables. +;suhosin.request.disallow_nul = 1 + +; When set to On the dangerous characters <>"'` are urlencoded when found +; not encoded in the server variables REQUEST_URI and QUERY_STRING. This +; will protect against some XSS vulnerabilities. +;suhosin.server.encode = 1 + +; When set to On the dangerous characters <>"'` are replaced with ? in +; the server variables PHP_SELF, PATH_TRANSLATED and PATH_INFO. This will +; protect against some XSS vulnerabilities. +;suhosin.server.strip = 1 + +; Defines the maximum number of files that may be uploaded with one request. +;suhosin.upload.max_uploads = 25 + +; When set to On it is not possible to upload ELF executables. +;suhosin.upload.disallow_elf = 1 + +; When set to On it is not possible to upload binary files. +;suhosin.upload.disallow_binary = 0 + +; When set to On binary content is removed from the uploaded files. +;suhosin.upload.remove_binary = 0 + +; This defines the full path to a verification script for uploaded files. The +; script gets the temporary filename supplied and has to decide if the upload +; is allowed. A possible application for this is to scan uploaded files for +; viruses. The called script has to write a 1 as first line to standard output +; to allow the upload. Any other value or no output at all will result in the +; file being deleted. +;suhosin.upload.verification_script = + +; Specifies the maximum length of the session identifier that is allowed. When +; a longer session identifier is passed a new session identifier will be +; created. This feature is important to fight bufferoverflows in 3rd party +; session handlers. +;suhosin.session.max_id_length = 128 + +; Undocumented: Controls if suhosin coredumps when the optional suhosin patch +; detects a bufferoverflow, memory corruption or double free. This is only +; for debugging purposes and should not be activated. +;suhosin.coredump = Off + +; Undocumented: Controls if the encryption keys specified by the configuration +; are shown in the phpinfo() output or if they are hidden from it +;suhosin.protectkey = 1 + +; Controls if suhosin loads in stealth mode when it is not the only +; zend_extension (Required for full compatibility with certain encoders +; that consider open source untrusted. e.g. ionCube, Zend) +;suhosin.stealth = 1 + +; Controls if suhosin's ini directives are changeable per directory +; because the admin might want to allow some features to be controlable +; by .htaccess and some not. For example the logging capabilities can +; break safemode and open_basedir restrictions when .htaccess support is +; allowed and the admin forgot to fix their values in httpd.conf +; An empty value or a 0 will result in all directives not allowed in +; .htaccess. The string "legcprsum" will allow logging, execution, get, +; post, cookie, request, sql, upload, misc features in .htaccess +;suhosin.perdir = "0" diff --git a/suhosin_logo.h b/suhosin_logo.h new file mode 100644 index 0000000..455bd59 --- /dev/null +++ b/suhosin_logo.h @@ -0,0 +1,180 @@ +#define SUHOSIN_LOGO_GUID "SUHO8567F54-D428-14d2-A769-00DA302A5F18" + +static unsigned char suhosin_logo[] = + "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x01\x00\x48" + "\x00\x48\x00\x00\xff\xe1\x00\x16\x45\x78\x69\x66\x00\x00\x4d\x4d" + "\x00\x2a\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\xff\xdb\x00\x43" + "\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01" + "\x01\xff\xc0\x00\x0b\x08\x00\x27\x00\x71\x01\x01\x22\x00\xff\xc4" + "\x00\x1e\x00\x00\x02\x02\x02\x03\x01\x01\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x09\x06\x08\x05\x07\x02\x03\x0a\x01\x04\xff\xc4" + "\x00\x32\x10\x00\x01\x04\x03\x00\x02\x00\x05\x01\x05\x09\x01\x00" + "\x00\x00\x00\x05\x02\x03\x04\x06\x01\x07\x08\x00\x09\x11\x12\x13" + "\x14\x21\x15\x0a\x16\x31\x56\x96\x17\x18\x19\x23\x32\x41\x58\x98" + "\xd4\xd6\xff\xda\x00\x08\x01\x01\x00\x00\x3f\x00\xf4\xc1\xe1\xe5" + "\x69\xe9\x3e\xb9\xd1\x7c\x8a\x2e\x9d\x66\xe8\x3b\x29\x4d\x7f\x46" + "\xba\x58\x55\x54\x8d\xb1\x5f\xaa\xd9\x8d\x51\x2b\xb6\x27\x5a\x69" + "\xd1\x43\xaf\x16\x1a\xf0\xb2\xb1\xe9\x6d\x9f\xc2\xa4\x36\x18\xb5" + "\x85\x10\x41\xbe\xfc\x09\xac\x49\x29\x11\xd4\x32\x97\xec\x08\x13" + "\xc1\x2d\x20\xc3\x59\xeb\x26\x05\xd8\x6b\x76\x31\x43\x8f\x57\xcf" + "\x84\x9f\x14\xa8\x53\x81\x0b\xc3\x64\x80\xa3\x02\x0a\x41\x75\xf8" + "\x44\x85\x93\x81\x22\x3c\xd8\x13\xe1\xbe\xf4\x59\x91\x1f\x6a\x44" + "\x77\x5c\x69\xc4\x2f\x39\x5f\x0f\x2a\x8d\xeb\xba\xf8\xc3\x56\x6c" + "\x3b\x36\xa7\xda\xbd\x4d\xa1\xb5\x4e\xc6\xa7\xa4\x3a\xec\x15\x2d" + "\xa5\xb3\xea\x5a\xdc\xac\x46\xac\x01\x60\xd8\x43\xc8\x8e\x8b\xb1" + "\x40\x4c\x95\x8b\x34\x41\x28\x52\x91\x28\x43\xd3\xa3\xb6\xa7\x55" + "\x15\xe7\x5a\x96\xcb\xf1\xda\xe5\x55\xee\xfe\x1e\xbd\xd9\x41\xd3" + "\x28\xfd\x97\xca\x57\x2b\x85\x9c\xa4\x30\x95\xaa\xa5\x57\xa2\x35" + "\x15\x86\xcb\x61\x34\x41\xe4\xc7\x80\x20\x18\x21\x17\x09\x85\x0b" + "\x14\x9d\x21\x68\x62\x1c\x08\x11\x64\x4b\x92\xf2\xd2\xd3\x2d\x2d" + "\x6a\xc2\x73\x6b\x3c\x3c\x8b\x9e\xbc\x52\xaa\xa4\xab\x81\x6c\xf6" + "\xfa\xbd\x70\xc5\xc6\x7b\xc2\xaa\x22\x4f\x58\x04\x87\x25\x6a\x27" + "\x1d\xa4\x3d\x20\x75\x72\x01\x09\x71\xe5\x1c\x9e\xc3\x2e\x36\xf3" + "\xd0\xc6\x35\x2a\x43\x4d\x2d\x0e\x2d\xb4\xa1\x49\xce\x65\x1e\x52" + "\x9e\xa1\xf6\x09\xcc\xdc\x63\x66\xa8\x01\xe9\x3b\x0d\xd7\x5a\x85" + "\xbb\xc5\x65\xc0\x7b\x2e\x46\xa9\xd9\x56\x1d\x4c\x92\x72\x26\x4e" + "\x86\xd5\x68\xae\xc4\xaa\x55\xce\xd7\x83\x59\xb3\x81\xee\xce\x74" + "\x39\x39\x31\x9f\x8a\x25\xe8\xa5\xa5\xe5\x81\xf2\x11\x23\xcb\xa1" + "\x1e\x43\x12\xe3\xb1\x2a\x2b\xcd\xc8\x8d\x25\x96\xa4\x47\x7d\x95" + "\xa5\xc6\x9f\x61\xe4\x25\xc6\x5e\x69\xc4\xe7\x29\x5b\x6e\xb6\xa4" + "\xad\x0b\x4e\x72\x95\x25\x58\x56\x33\x9c\x67\xce\xef\x0f\x17\xbf" + "\x4c\x7b\x2d\xe6\xfe\x76\x35\x27\x5a\x07\x97\x67\xe8\xae\x8d\x71" + "\x0f\xb2\x13\x99\xb9\xbc\x14\xad\xb3\xb7\xe6\x11\x6f\xe0\xda\x58" + "\xb1\x08\xac\xa6\x6c\x2d\x7f\x05\xb7\x56\xd2\xe6\xcf\xbb\x4d\x0c" + "\xe3\x50\xb2\xec\x91\xf0\x4a\xb8\xd6\x22\xb8\xa7\xf6\x67\xaf\xcf" + "\x63\x7e\xd7\xe7\x42\xd8\xbd\xc3\x71\xa1\xf2\x7e\x9b\xa8\x97\x83" + "\x6e\xd1\xdc\x4b\x06\x11\x2d\xae\x26\x61\x98\x72\x10\xf4\x42\x5d" + "\x20\x4a\xa3\x73\xd7\xf2\xcd\x3c\x48\x32\xe4\x03\x9f\x80\x37\x08" + "\x36\x11\xd0\xcb\x97\x6c\x08\xed\x6d\x33\x24\xa2\x1b\xb4\x77\xdf" + "\x61\x5d\x5f\xc1\x43\xc2\x82\xeb\x0f\x5d\x84\x08\x68\xaa\xa4\x01" + "\xe1\x19\xdf\xbc\x31\x65\xfe\xd1\xf5\x7d\x7a\xb2\x2a\x33\x50\x21" + "\x2a\x56\x9d\xb1\x81\xab\xdb\x35\x78\x30\x83\xd9\x89\x1d\x31\xac" + "\x96\x14\x07\x61\xbc\x20\x68\x42\x85\x33\x19\xac\xbe\xdb\x34\x56" + "\xf1\xd5\xfd\x29\xa9\x28\xdb\xcb\x4c\x5a\x23\xdc\xf5\x96\xc5\x10" + "\xa3\x35\x5b\x14\x68\xd3\x61\x62\x64\x76\x26\xcb\x17\x3e\x34\x98" + "\x04\xa3\xc4\x20\x38\x90\x92\xe3\xc8\x07\x2c\x36\x74\x66\x26\x0e" + "\x29\x02\x64\x29\x2d\x21\xe6\x16\x9c\x6b\xce\xa3\x89\xd9\x4f\xd3" + "\xc4\xbd\xc5\x87\x79\x9c\x65\xf6\x39\x45\x60\xe8\xce\x9e\xab\x6d" + "\x13\x15\x22\xe1\x5e\x4b\x38\x42\xc4\x1e\xd5\x76\xe0\xc5\xeb\x85" + "\x07\x2d\x0f\xb8\xb6\xa6\xd6\x6d\x71\x0d\xa2\x43\x4c\x25\xea\xfa" + "\xa1\xae\x4c\xe4\x7d\xbd\x76\xa9\xfb\x06\xc2\x83\x42\xeb\xad\xe7" + "\xe9\x5f\x68\x6f\xba\xfb\x2f\x07\xce\xb8\x13\xc1\x9b\xeb\xb0\x76" + "\x45\x57\x28\x7b\xea\xbe\x0f\xf4\x30\x7b\xa0\xed\xe4\x22\x93\x21" + "\xfc\xbc\xe0\xb9\x75\xc1\x4f\xfc\xef\xb6\xfa\xa1\xfc\x64\xa1\x4a" + "\x82\xc7\x33\xad\x75\xed\x82\xbd\x3d\xdb\xf7\xa8\xbe\x5e\xbb\x36" + "\x62\x04\x9a\x2e\xc5\xd9\x9e\x9c\x3a\x0b\x98\x0b\x57\xac\xf1\x24" + "\x62\x58\x83\x15\x5b\xa6\xf2\xda\x34\x70\x03\xce\x0f\x93\x1b\x12" + "\xc7\xce\x54\x87\x33\x15\xd6\x53\x25\x1f\x2a\x90\x87\x12\xe3\x78" + "\xef\x55\x77\x4d\x4a\xd8\x7e\xef\xd2\xfd\xd1\xaf\x3a\xaf\x55\xdb" + "\x6a\x2d\x3d\x42\xac\x51\x79\xee\x91\xab\xe1\x05\x2d\x3c\x80\xa2" + "\x43\xad\x22\x2e\xd5\x33\x13\xa4\x9e\x00\xe0\x04\x10\x84\xc8\xf2" + "\x19\x30\x92\x1f\xaa\xc3\x28\xc9\x76\x30\x3f\xe9\x10\x61\x5e\x79" + "\xd5\xf7\xdf\xd0\x54\xdb\xae\xb6\xae\xfa\xe8\xa3\x57\xe0\x6c\x2d" + "\xf7\xbd\x49\xd6\x6e\x76\x79\xcc\x54\x0c\x5f\xff\x00\xbb\x06\x98" + "\xa6\x9e\x89\x61\xb4\x6f\xc3\xe3\x6a\xc2\x4f\x59\x03\xc9\x80\x2c" + "\x59\x24\x44\x70\x38\xd5\x96\x6a\x9e\x8b\x81\x64\xe5\xbc\xa0\x3c" + "\x33\xaf\x17\x9d\xff\x00\x71\x1a\xd1\x3a\x80\x66\xb3\xd9\x31\x77" + "\x0d\x12\xbd\xae\x29\xb5\x6a\xd6\xcf\x8d\x68\x87\x75\xcd\xe8\x65" + "\x5a\xbe\x3c\x04\x7b\x34\xdb\x54\x19\xa4\x63\x9c\x2a\x5d\x23\xbe" + "\xf4\xb1\x1c\x4d\x90\xec\x92\x2f\x49\x71\xf7\x14\xf2\x97\x9f\x15" + "\x57\xed\x13\x21\x2a\xf5\x33\xd1\x2a\x52\x52\xac\xb7\x62\xd1\xcb" + "\x46\x73\x8c\x67\x28\x56\x77\x86\xbf\x6f\x2a\x4e\x73\xfe\x95\x65" + "\x0b\x5a\x3e\x38\xfc\xfc\xaa\x56\x3f\x86\x73\xe3\xb9\x4a\x52\x84" + "\xa5\x08\x4e\x12\x94\x27\x09\x4a\x53\x8c\x61\x29\x4a\x71\xf0\x4a" + "\x53\x8c\x7e\x31\x8c\x63\x18\xc6\x31\x8f\xc6\x31\xf8\xc7\x9f\x7c" + "\xd5\xbb\xae\x5e\xe2\x1f\xab\x6e\x24\x34\x00\x8a\x25\x83\x70\x40" + "\x1c\xcc\xda\x45\x7f\x66\x4e\x30\x2e\x94\x7e\x74\x49\xf0\xe4\x4e" + "\x06\x5c\xa8\x2f\x89\x21\x2e\x98\x0e\xd9\x21\xc2\x0b\x21\x0f\xc4" + "\x16\x6e\x48\xd9\xe4\xe3\x4a\x19\x1e\x64\x67\x54\xff\x00\x3a\x6d" + "\x4f\x62\xb5\x00\x4a\xaa\x51\xfd\x2d\xe8\x0e\x6c\xaf\xc6\x7d\x6d" + "\xc8\x88\xc7\x67\xea\x8a\x58\x02\x73\xe3\x65\x4d\xc9\x24\xc0\x3d" + "\x57\xa3\x2e\x53\x16\x99\x4f\xe5\xe7\x19\x97\x3e\x3b\xcf\xc9\x4b" + "\x99\x7f\x33\x25\xa5\xdf\xba\x77\x2b\xd3\x3e\xc2\x7b\x8b\x94\x07" + "\xe9\x52\x5b\x43\x87\x34\x14\x86\x37\xcf\x41\x6b\x8e\x6a\xa5\x22" + "\xab\xdb\x96\xa2\xcf\x46\xd8\x9b\x45\x93\xef\xd6\xdf\x3e\x99\x9c" + "\x7e\x29\x10\x6b\x6c\xa2\xb8\x43\x05\x09\x44\x70\x8c\xb8\xaa\x54" + "\x7c\x30\x36\x5e\x1c\x5e\x5b\x9f\x6c\x0d\x81\xee\xa0\x93\x8d\x67" + "\x55\xf3\x87\xaf\xaa\x6b\x58\xf9\xbe\xb2\x36\x07\x42\x6e\xbd\x96" + "\xe3\x9f\x1f\x8f\xc9\xf4\x9d\xae\x6a\x7d\x4c\x96\xbe\x5f\xc7\xcd" + "\xf3\xb2\xf7\xcd\xf0\xcf\xc3\xe4\xf8\xfe\x37\x4f\x1c\x4d\xf6\x40" + "\xf1\x6b\x7c\x4e\xe0\xa6\x71\xad\x56\xa7\x1c\x5c\x15\x6b\xfc\xf3" + "\x01\x5d\xac\xf1\x75\x9a\x72\x6b\xaa\x28\xc5\x88\x6d\xfb\x33\x85" + "\xe0\x4e\x61\xab\xeb\x31\x2c\x71\x08\x73\x11\x3b\xfc\xb5\xc0\x96" + "\xcc\x87\x24\x44\xb5\x9b\x9e\xb3\x71\xba\xe9\xed\xb1\x4e\xd7\x76" + "\x6c\xd2\xb6\x05\xb7\x5a\xde\xeb\x34\x5b\x96\x16\xfb\x59\xa9\x5c" + "\x4f\x55\xca\x8a\xac\x59\xb0\xe4\x54\x39\x25\xbc\x81\x37\x2a\x09" + "\x5f\x9e\x3b\x6b\x7d\x1f\x69\xf3\x34\x85\x39\x84\xa7\x28\x0b\xd3" + "\xfd\xfb\x4b\x7a\xea\xe7\xd2\x3c\xd3\xda\x15\x68\xbc\x73\xd3\x22" + "\x6f\xd7\x72\x5b\x2b\x66\xee\xa8\x0d\x54\xe8\x5b\xf9\x92\x96\x92" + "\x93\xea\x97\x4a\xc7\x43\x10\x46\x35\xc5\xc0\x60\x8a\xe4\xc1\xb5" + "\x36\xc6\xae\xed\xf7\x70\xa5\x86\x99\x3d\x91\xf8\xfd\x4e\x53\xeb" + "\xbb\xbd\x6d\xec\x8f\xd7\x89\x3d\x31\x7f\xd7\x78\xba\x50\xbb\x74" + "\x9d\xf6\xac\x4e\xb9\x03\x9c\x79\xd5\xe1\xbd\x17\x68\xd9\x13\x0b" + "\x45\x75\x88\x00\x1d\x1f\xae\x73\x6a\x1d\x5c\x6e\x44\x9f\xa6\xfa" + "\x4e\xd8\x25\x8b\xc0\xbc\xb2\x99\xe3\x17\x24\xb3\x23\xe2\x48\x8b" + "\xfa\x22\xe7\x7e\x8f\xe6\x3f\x5f\x55\x0d\x75\xd3\x51\x0b\xd7\xed" + "\xd3\x6f\x97\x3b\x85\x42\x80\x7e\x5f\xdc\x1b\xd6\xba\xee\xc4\x80" + "\xce\x06\xa9\x15\x8c\x97\x5f\x40\x69\xb2\x4d\xc5\xb2\x5c\x1e\x01" + "\x87\x7e\xe0\x36\x6d\x78\x80\x4e\x3c\x02\xec\x90\x1d\x11\x81\x74" + "\xa5\x8b\xa4\xa0\x56\x06\xd5\x79\x72\x85\x57\x3b\xb2\x2e\xae\x90" + "\x18\x8d\x91\xb2\x0e\x44\x19\xaa\xb4\xcc\x08\xed\x46\xfa\xd7\x2b" + "\x78\x58\x72\x5d\xbb\x5e\x49\xe7\xee\xf3\x8a\x9d\x22\xa4\x19\xc8" + "\xe7\x08\xc3\x90\x9b\x35\x9a\xa4\x25\x8c\x4b\x9b\xa7\xf8\xbf\x81" + "\xf5\xdf\x22\x66\xf1\x7e\x9f\x66\x3d\xbb\xfa\x73\x73\x4d\xfd\x67" + "\x7b\xf4\xce\xc3\x62\x2e\x6f\xbb\x0c\xa2\xdc\x69\xfc\x8a\x17\x0e" + "\x3a\x9e\x83\x46\xd7\xe3\x5e\x65\x86\xc0\x51\x00\xbb\x91\xe3\xe1" + "\xc1\x16\xc4\xe9\x65\x5c\x14\x3e\x44\x6a\x6b\xd1\x1e\xb0\x36\xdd" + "\x0b\x7d\x8a\xeb\xaf\x58\x5b\x64\x3f\x38\xed\x52\x76\xe8\x46\xf7" + "\x86\x84\xb3\x93\xb1\x0b\xe5\xfd\xfd\x0d\xe9\x6d\xe4\xf1\x1b\x1d" + "\x56\xb4\x34\xe4\x6a\xf5\xa4\x9c\x2c\xc9\x64\x94\xc1\xf5\x79\x6d" + "\x12\x96\xf3\x47\xc5\x48\xa8\xdb\xd8\x95\x64\x29\xcf\xf6\x88\xf1" + "\x95\x7a\x98\xe8\xbc\x27\x19\xce\x73\x61\xd1\xb8\xc6\x31\x8c\xe7" + "\x39\xce\x77\x9e\xbc\xc6\x31\x8c\x63\xf3\x9c\xe7\x39\xc6\x31\x8f" + "\xf7\xce\x7e\x1e\x3b\x7f\x0f\x0f\x0f\x13\x57\xb9\x0a\xe1\x0b\x64" + "\x5f\x58\x40\xc6\xc7\x7a\x4b\xf2\x3d\xbc\x71\xf4\xa7\xd2\xca\x14" + "\xe2\x98\x1a\x30\x1e\xe0\x26\x5a\x6a\xf0\x9c\x67\x38\x66\x00\xb8" + "\x72\xe6\xbe\xac\xfe\x12\xd3\x0b\x56\x73\x8c\x63\xc7\x2b\xe1\xe2" + "\xe8\xdd\x7b\xff\x00\xd8\xe5\x23\x6c\xce\xa8\x69\xcf\x5e\x3a\xef" + "\x77\xea\xe5\xab\x0e\x82\xdb\xd9\xed\x7a\x9e\xb8\x6d\x51\x32\xdb" + "\x79\xc3\x36\x9a\x2d\xa3\x50\x39\x65\x0a\x63\x0e\xe5\xd4\x39\x12" + "\xbf\x8b\x98\xa4\xa1\x2d\xad\xb3\xcf\x65\x6a\x43\x78\xb3\x3b\x07" + "\xd8\xd5\xea\xae\x76\xad\x6f\xf5\xff\x00\xca\x93\xab\x96\xb0\x64" + "\xeb\xd6\x4a\xd5\x87\xba\xec\x24\x60\x97\x06\x76\x03\xe3\x4c\x07" + "\x29\x11\x8e\x34\x25\x02\x64\x29\xf0\x25\x48\x85\x3a\x33\x8b\x7a" + "\x3c\x86\x1e\x75\xa5\x61\xc6\x97\x9f\x8d\x25\xf5\xc9\xcd\xde\xc9" + "\x7d\x77\xf2\xc8\x7e\x70\xaf\x73\x5f\x2d\xec\xa2\x51\x2d\x96\xfb" + "\x89\xad\x80\x57\xb2\x36\x1d\x7d\x83\x45\xac\xf3\xdb\xcc\x6c\x31" + "\x4f\xcf\x30\x58\xd0\x12\x28\x90\x50\x42\x86\xfb\x48\x16\x3c\xc5" + "\x9c\xf8\xe7\xcc\x29\x88\xb3\x4a\x4b\x4e\x6c\xbc\xdb\xc7\xbb\xe9" + "\xb6\xa0\x8b\x11\xa1\x7d\x73\xd7\xe9\xbf\x7e\xc2\x6c\x10\x8d\xee" + "\x9d\xef\x63\x3a\xe0\xf5\xbe\x8c\x3e\xa1\xc7\xc5\xd1\x00\x44\x1e" + "\xf3\x51\xf2\xe2\xb0\xe3\xb5\x13\x7f\x32\xf1\x8c\xa6\x22\xfe\x1f" + "\x49\x4d\xbb\xcf\x3a\x5d\xed\x4c\xd2\xfc\x85\xed\x23\xd6\xc7\x50" + "\xb6\x5b\x3a\x16\x83\xb8\x6f\xfd\x32\x3f\xaa\x36\x34\xbb\xf5\x96" + "\xa9\xab\xcf\x9f\x8f\xac\xc3\xca\xd5\x8b\xd8\x48\x9e\x79\xaa\x30" + "\x87\xca\x58\x4d\x59\x96\xb9\x4f\xc5\x1b\x1c\xd2\xda\x5b\xe6\x57" + "\x29\xa1\x28\x7a\x2b\x5b\xff\x00\x12\x2f\x5e\x3f\xf3\xbb\x8e\x7f" + "\xec\xc6\x98\xff\x00\xed\x3c\xa6\xdd\xa9\xdc\x7e\xa0\xf7\xd6\x99" + "\x31\xa2\xf7\xaf\x6b\xe9\x82\x74\x4b\x3d\x8f\x5e\x58\x0b\x33\xab" + "\xef\xc3\xaf\x84\x64\xb9\xae\xb6\x25\x5f\x62\x8f\x1c\xe3\xf4\x51" + "\xb7\x96\xe3\x0e\x30\x42\xa9\x18\x39\xbf\x9e\x2a\x1f\x74\x19\x02" + "\x2d\x43\x93\x06\x63\xb1\xa7\x47\x6a\xfa\x9b\x6c\xeb\xbd\xe9\xae" + "\x6a\x7b\x6f\x53\x5a\x60\x5d\xb5\xcd\xe8\x67\xeb\x35\x3b\x48\xc6" + "\xa6\xb3\x04\xc8\xdf\xb8\x7e\x26\x64\xb0\xc9\x18\xb0\xa7\x33\xf2" + "\x4a\x8b\x22\x3b\x8d\x4b\x89\x1d\xf6\x9d\x65\xc4\x38\xd2\x54\x9c" + "\xe3\xcd\x89\xe1\xe1\xe6\x3e\x70\x81\x45\x1d\x18\xf9\x31\x83\xc8" + "\xbe\x14\x82\x4b\x87\x7a\x74\x28\xd2\xdd\x12\x55\x30\xe6\x0e\x49" + "\x31\x8e\x48\x69\xc5\xc0\x20\x91\xe4\x48\x41\x4c\xd8\xb9\x6a\x4e" + "\x21\xce\x99\x1b\x0e\xfd\x09\x4f\xa1\x79\x0f\x0f\x0f\x0f\x0f\x0f" + "\x0f\x3f\x3c\xb8\x71\x27\xc7\x72\x24\xe8\xb1\xa6\xc5\x7b\x18\xc3" + "\xb1\xa5\xb0\xd4\x98\xee\xe3\x19\xc6\x71\x87\x19\x79\x2b\x6d\x78" + "\xc6\x71\x8c\xe3\x0a\x4e\x71\x8c\xe3\x19\xfe\x38\xf2\x3b\xfb\x8b" + "\x48\xfe\x4e\xaa\xff\x00\x4f\x08\xff\x00\xc7\xe1\xfb\x8b\x48\xfe" + "\x4e\xaa\xff\x00\x4f\x08\xff\x00\xc7\xe4\x95\x86\x18\x8a\xcb\x31" + "\xa3\x32\xd4\x78\xf1\xdb\x43\x2c\x47\x61\xb4\x32\xcb\x2c\xb4\x9c" + "\x21\xb6\x99\x69\xbc\x25\xb6\xdb\x6d\x18\xc2\x10\xda\x12\x94\xa1" + "\x38\xc2\x53\x8c\x63\x18\xc7\x9d\xbe\x7f\xff\xd9" + ; diff --git a/suhosin_rfc1867.h b/suhosin_rfc1867.h new file mode 100644 index 0000000..1ddaab3 --- /dev/null +++ b/suhosin_rfc1867.h @@ -0,0 +1,88 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: suhosin_rfc1867.h,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ */ + +#ifndef SUHOSIN_RFC1867_H +#define SUHOSIN_RFC1867_H + +#include "rfc1867.h" +#include "SAPI.h" + +#define MULTIPART_CONTENT_TYPE "multipart/form-data" +#ifdef MULTIPART_EVENT_START +#define HAVE_RFC1867_CALLBACK 1 +#else +#define HAVE_RFC1867_CALLBACK 0 + +#define MULTIPART_EVENT_START 0 +#define MULTIPART_EVENT_FORMDATA 1 +#define MULTIPART_EVENT_FILE_START 2 +#define MULTIPART_EVENT_FILE_DATA 3 +#define MULTIPART_EVENT_FILE_END 4 +#define MULTIPART_EVENT_END 5 + +typedef struct _multipart_event_start { + size_t content_length; +} multipart_event_start; + +typedef struct _multipart_event_formdata { + size_t post_bytes_processed; + char *name; + char **value; + size_t length; + size_t *newlength; +} multipart_event_formdata; + +typedef struct _multipart_event_file_start { + size_t post_bytes_processed; + char *name; + char **filename; +} multipart_event_file_start; + +typedef struct _multipart_event_file_data { + size_t post_bytes_processed; + off_t offset; + char *data; + size_t length; + size_t *newlength; +} multipart_event_file_data; + +typedef struct _multipart_event_file_end { + size_t post_bytes_processed; + char *temp_filename; + int cancel_upload; +} multipart_event_file_end; + +typedef struct _multipart_event_end { + size_t post_bytes_processed; +} multipart_event_end; + +#endif + +SAPI_POST_HANDLER_FUNC(suhosin_rfc1867_post_handler); + +void destroy_uploaded_files_hash(TSRMLS_D); +#if !HAVE_RFC1867_CALLBACK +extern PHP_SUHOSIN_API int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC); +#else +extern PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC); +#endif + +#endif /* SUHOSIN_RFC1867_H */ diff --git a/tests/empty.inc b/tests/empty.inc new file mode 100644 index 0000000..35cbf45 --- /dev/null +++ b/tests/empty.inc @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/tests/executor/disable_emod_off.phpt b/tests/executor/disable_emod_off.phpt new file mode 100644 index 0000000..3c9cb01 --- /dev/null +++ b/tests/executor/disable_emod_off.phpt @@ -0,0 +1,18 @@ +--TEST-- +Testing: suhosin.executor.disable_emodifier=0 +--SKIPIF-- + +--INI-- +suhosin.log.sapi=64 +suhosin.executor.disable_emodifier=0 +--FILE-- + +--EXPECTF-- +string(5) "HALLO" +string(5) "HALLO" + diff --git a/tests/executor/disable_emod_on.phpt b/tests/executor/disable_emod_on.phpt new file mode 100644 index 0000000..6daf82f --- /dev/null +++ b/tests/executor/disable_emod_on.phpt @@ -0,0 +1,19 @@ +--TEST-- +Testing: suhosin.executor.disable_emodifier=1 +--SKIPIF-- + +--INI-- +suhosin.log.sapi=64 +suhosin.executor.disable_emodifier=1 +--FILE-- + +--EXPECTF-- +string(5) "HALLO" +ALERT - use of preg_replace() with /e modifier is forbidden by configuration (attacker 'REMOTE_ADDR not set', file '%s', line 5) + +Fatal error: SUHOSIN - Use of preg_replace() with /e modifier is forbidden by configuration in %s(5) : regexp code on line 5 diff --git a/tests/executor/disable_eval_off.phpt b/tests/executor/disable_eval_off.phpt new file mode 100644 index 0000000..1ee87f5 --- /dev/null +++ b/tests/executor/disable_eval_off.phpt @@ -0,0 +1,15 @@ +--TEST-- +Testing: suhosin.executor.disable_eval=0 +--SKIPIF-- + +--INI-- +suhosin.log.sapi=64 +suhosin.executor.disable_eval=0 +--FILE-- + +--EXPECTF-- +int(1) diff --git a/tests/executor/disable_eval_on.phpt b/tests/executor/disable_eval_on.phpt new file mode 100644 index 0000000..49f4936 --- /dev/null +++ b/tests/executor/disable_eval_on.phpt @@ -0,0 +1,17 @@ +--TEST-- +Testing: suhosin.executor.disable_eval=1 +--SKIPIF-- + +--INI-- +suhosin.log.sapi=64 +suhosin.executor.disable_eval=1 +--FILE-- + +--EXPECTF-- +ALERT - use of eval is forbidden by configuration (attacker 'REMOTE_ADDR not set', file '%s', line 3) + +Fatal error: SUHOSIN - Use of eval is forbidden by configuration in %s(3) : eval()'d code on line 3 diff --git a/tests/executor/memory_limit.phpt b/tests/executor/memory_limit.phpt new file mode 100644 index 0000000..404ab19 --- /dev/null +++ b/tests/executor/memory_limit.phpt @@ -0,0 +1,29 @@ +--TEST-- +memory_limit test: set suhosin hard_limit to normal limit +--SKIPIF-- + +--INI-- +memory_limit=16M +suhosin.memory_limit=0 +suhosin.log.syslog=0 +suhosin.log.script=0 +suhosin.log.sapi=2 +--FILE-- + +--EXPECTF-- +13M +14M +15M +16M +ALERT - script tried to increase memory_limit to 17825792 bytes which is above the allowed value (attacker 'REMOTE_ADDR not set', file '%s', line 6) +16M +ALERT - script tried to increase memory_limit to 18874368 bytes which is above the allowed value (attacker 'REMOTE_ADDR not set', file '%s', line 7) +16M + diff --git a/tests/executor/memory_limit_other_hardlimit.phpt b/tests/executor/memory_limit_other_hardlimit.phpt new file mode 100644 index 0000000..cac11dc --- /dev/null +++ b/tests/executor/memory_limit_other_hardlimit.phpt @@ -0,0 +1,28 @@ +--TEST-- +memory_limit test: set suhosin hard_limit to normal limit + 1M +--SKIPIF-- + +--INI-- +memory_limit=16M +suhosin.memory_limit=17M +suhosin.log.syslog=0 +suhosin.log.script=0 +suhosin.log.sapi=2 +--FILE-- + +--EXPECTF-- +13M +14M +15M +16M +17M +ALERT - script tried to increase memory_limit to %d bytes which is above the allowed value (attacker 'REMOTE_ADDR not set', file '%s', line 7) +17M + diff --git a/tests/executor/negative_memory_limit.phpt b/tests/executor/negative_memory_limit.phpt new file mode 100644 index 0000000..8582cc9 --- /dev/null +++ b/tests/executor/negative_memory_limit.phpt @@ -0,0 +1,18 @@ +--TEST-- +memory_limit test: trying to set memory_limit to a negative value +--SKIPIF-- + +--INI-- +memory_limit=16M +suhosin.memory_limit=17M +suhosin.log.syslog=0 +suhosin.log.script=0 +suhosin.log.sapi=2 +--FILE-- + +--EXPECTF-- +ALERT - script tried to increase memory_limit to %d bytes which is above the allowed value (attacker 'REMOTE_ADDR not set', file '%s', line 2) +16M + diff --git a/tests/executor/preg_replace.phpt b/tests/executor/preg_replace.phpt new file mode 100644 index 0000000..9060a29 --- /dev/null +++ b/tests/executor/preg_replace.phpt @@ -0,0 +1,30 @@ +--TEST-- +Testing protection against "\0" in preg_replace() first parameter +--SKIPIF-- + +--INI-- +suhosin.log.sapi=0 +--FILE-- + +--EXPECT-- +string(49) "One little boy with 2 dogs, 3 cats and four birds" +bool(false) +string(39) "The three cats play with the four birds" +bool(false) diff --git a/tests/executor/preg_replace_error.phpt b/tests/executor/preg_replace_error.phpt new file mode 100644 index 0000000..39e0aee --- /dev/null +++ b/tests/executor/preg_replace_error.phpt @@ -0,0 +1,32 @@ +--TEST-- +Testing protection against "\0" in preg_replace() first parameter (INCL. SUHOSIN ERROR MESSAGES) +--SKIPIF-- + +--INI-- +suhosin.log.sapi=64 +--FILE-- + +--EXPECTF-- +string(49) "One little boy with 2 dogs, 3 cats and four birds" +ALERT - string termination attack on first preg_replace parameter detected (attacker 'REMOTE_ADDR not set', file '%s', line 14) +bool(false) +string(39) "The three cats play with the four birds" +ALERT - string termination attack on first preg_replace parameter detected (attacker 'REMOTE_ADDR not set', file '%s', line 16) +bool(false) diff --git a/tests/executor/recursion_maxdepth.phpt b/tests/executor/recursion_maxdepth.phpt new file mode 100644 index 0000000..31fe9c2 --- /dev/null +++ b/tests/executor/recursion_maxdepth.phpt @@ -0,0 +1,31 @@ +--TEST-- +Testing: suhosin.executor.max_depth +--SKIPIF-- + +--INI-- +suhosin.log.sapi=64 +suhosin.executor.max_depth=13 +--FILE-- + +--EXPECTF-- +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +ALERT - maximum execution depth reached - script terminated (attacker 'REMOTE_ADDR not set', file '%s', line 5) diff --git a/tests/filter/get_globals.phpt b/tests/filter/get_globals.phpt new file mode 100644 index 0000000..f16991b --- /dev/null +++ b/tests/filter/get_globals.phpt @@ -0,0 +1,24 @@ +--TEST-- +Testing: GLOBALS in GET +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=255 +suhosin.log.script.name=/tmp/xx +--GET-- +a=1&b=2&GLOBALS=123&c=3 +--FILE-- + +--EXPECT-- +string(1) "1" +string(1) "2" +string(1) "3" +int(5) diff --git a/tests/funcs/crypt_blowfish.phpt b/tests/funcs/crypt_blowfish.phpt new file mode 100644 index 0000000..f48e411 --- /dev/null +++ b/tests/funcs/crypt_blowfish.phpt @@ -0,0 +1,13 @@ +--TEST-- +CRYPT_BLOWFISH support +--SKIPIF-- + +--FILE-- + +--EXPECT-- +int(1) +$2a$07$rasmuslerd............nIdrcHdxcUxWomQX9j6kvERCFjTg7Ra + diff --git a/tests/funcs/crypt_ext_des.phpt b/tests/funcs/crypt_ext_des.phpt new file mode 100644 index 0000000..4e2ba73 --- /dev/null +++ b/tests/funcs/crypt_ext_des.phpt @@ -0,0 +1,12 @@ +--TEST-- +CRYPT_EXT_DES support +--SKIPIF-- + +--FILE-- + +--EXPECT-- +_J9..rasmBYk8r9AiWNc + + diff --git a/tests/funcs/crypt_md5.phpt b/tests/funcs/crypt_md5.phpt new file mode 100644 index 0000000..fd39d20 --- /dev/null +++ b/tests/funcs/crypt_md5.phpt @@ -0,0 +1,11 @@ +--TEST-- +CRYPT_MD5 support +--SKIPIF-- + +--FILE-- + +--EXPECT-- +$1$rasmusle$rISCgZzpwk3UhDidwXvin0 + diff --git a/tests/funcs/crypt_std_des.phpt b/tests/funcs/crypt_std_des.phpt new file mode 100644 index 0000000..926ec44 --- /dev/null +++ b/tests/funcs/crypt_std_des.phpt @@ -0,0 +1,11 @@ +--TEST-- +CRYPT_STD_DES support +--SKIPIF-- + +--FILE-- + +--EXPECT-- +rl.3StKT.4T8M + diff --git a/tests/funcs/sha256.phpt b/tests/funcs/sha256.phpt new file mode 100644 index 0000000..cb407b1 --- /dev/null +++ b/tests/funcs/sha256.phpt @@ -0,0 +1,40 @@ +--TEST-- +SHA256 support +--SKIPIF-- + +--FILE-- + +--EXPECT-- +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb +68325720aabd7c82f30f554b313d0570c95accbb7dc4b5aae11204c08ffe732b +7c4fbf484498d21b487b9d61de8914b2eadaf2698712936d47c3ada2558f6788 +4096804221093ddccfbf46831490ea63e9e99414858f8d75ff7f642c7ca61803 +7abc22c0ae5af26ce93dbb94433a0e0b2e119d014f8e7f65bd56c61ccccd9504 +7516fb8bb11350df2bf386bc3c33bd0f52cb4c67c6e4745e0488e62c2aea2605 +0eb0281b27a4604709b0513b43ad29fdcff9a7a958554abc689d7fe35af703e4 +dee684641421d1ba5a65c71f986a117cbb3d619a052a0b3409306c629575c00f +47f527210d6e8f940b5082fec01b7305908fa2b49ea3ae597c19a3986097153c +c60d239cc6da3ad31f4de0c2d58a73ccf3f9279e504fa60ad55a31dcf686f3ca +e0164d90dbfcf173bb88044fac596ccd03b8d247c79907aaa5701767fad7b576 +dc990ef3109a7bcf626199db9ab7801213ceb0ad2ee398963b5061e39c05c7b5 +c1c9a4daadcc8678835872c7f1f8824376ac7b412e1fc2285069b41afd51397e +6840619417b4d8ecaa7902f8eaf2e82be2638dec97cb7e8fcc377007cc176718 +0f5308ff22b828e18bd65afbc427e3c1a678962832519df5f2f803f68f55e10b diff --git a/tests/include/include_constant.phpt b/tests/include/include_constant.phpt new file mode 100644 index 0000000..180aa69 --- /dev/null +++ b/tests/include/include_constant.phpt @@ -0,0 +1,17 @@ +--TEST-- +Include "Constant URL"; +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=0 +suhosin.log.phpscript=0 +suhosin.executor.include.whitelist= +suhosin.executor.include.blacklist= +--FILE-- + +--EXPECTF-- +ALERT - Include filename ('http://127.0.0.1/') is an URL that is not allowed (attacker 'REMOTE_ADDR not set', file '%s', line 2) diff --git a/tests/include/include_etc_passwd.phpt b/tests/include/include_etc_passwd.phpt new file mode 100644 index 0000000..fb3c4e2 --- /dev/null +++ b/tests/include/include_etc_passwd.phpt @@ -0,0 +1,23 @@ +--TEST-- +Include "../../../../../../../../../../../etc/passwd"; +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=0 +suhosin.log.phpscript=0 +suhosin.executor.include.whitelist= +suhosin.executor.include.blacklist= +suhosin.executor.include.max_traversal=3 +--FILE-- + +--EXPECTF-- +value-from-empty.inc +ALERT - Include filename ('%s../../../../../../../../../../../etc/passwd') contains too many '../' (attacker 'REMOTE_ADDR not set', file '%s', line 6) diff --git a/tests/include/include_once_constant.phpt b/tests/include/include_once_constant.phpt new file mode 100644 index 0000000..3faac33 --- /dev/null +++ b/tests/include/include_once_constant.phpt @@ -0,0 +1,17 @@ +--TEST-- +Include_once "Constant URL"; +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=0 +suhosin.log.phpscript=0 +suhosin.executor.include.whitelist= +suhosin.executor.include.blacklist= +--FILE-- + +--EXPECTF-- +ALERT - Include filename ('http://127.0.0.1/') is an URL that is not allowed (attacker 'REMOTE_ADDR not set', file '%s', line 2) diff --git a/tests/include/include_once_tmpvar.phpt b/tests/include/include_once_tmpvar.phpt new file mode 100644 index 0000000..1f94c5a --- /dev/null +++ b/tests/include/include_once_tmpvar.phpt @@ -0,0 +1,19 @@ +--TEST-- +Include_once "Temp Variable URL"; +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=0 +suhosin.log.phpscript=0 +suhosin.executor.include.whitelist= +suhosin.executor.include.blacklist= +--FILE-- + +--EXPECTF-- +ALERT - Include filename ('http://127.0.0.1/?') is an URL that is not allowed (attacker 'REMOTE_ADDR not set', file '%s', line 4) diff --git a/tests/include/include_once_var.phpt b/tests/include/include_once_var.phpt new file mode 100644 index 0000000..bf38377 --- /dev/null +++ b/tests/include/include_once_var.phpt @@ -0,0 +1,18 @@ +--TEST-- +Include_once "Variable URL"; +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=0 +suhosin.log.phpscript=0 +suhosin.executor.include.whitelist= +suhosin.executor.include.blacklist= +--FILE-- + +--EXPECTF-- +ALERT - Include filename ('http://127.0.0.1/') is an URL that is not allowed (attacker 'REMOTE_ADDR not set', file '%s', line 3) diff --git a/tests/include/include_tmpvar.phpt b/tests/include/include_tmpvar.phpt new file mode 100644 index 0000000..8ad26d7 --- /dev/null +++ b/tests/include/include_tmpvar.phpt @@ -0,0 +1,19 @@ +--TEST-- +Include "Temp Variable URL"; +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=0 +suhosin.log.phpscript=0 +suhosin.executor.include.whitelist= +suhosin.executor.include.blacklist= +--FILE-- + +--EXPECTF-- +ALERT - Include filename ('http://127.0.0.1/?') is an URL that is not allowed (attacker 'REMOTE_ADDR not set', file '%s', line 4) diff --git a/tests/include/include_var.phpt b/tests/include/include_var.phpt new file mode 100644 index 0000000..7431240 --- /dev/null +++ b/tests/include/include_var.phpt @@ -0,0 +1,18 @@ +--TEST-- +Include "Variable URL"; +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=0 +suhosin.log.phpscript=0 +suhosin.executor.include.whitelist= +suhosin.executor.include.blacklist= +--FILE-- + +--EXPECTF-- +ALERT - Include filename ('http://127.0.0.1/') is an URL that is not allowed (attacker 'REMOTE_ADDR not set', file '%s', line 3) diff --git a/tests/include/require_constant.phpt b/tests/include/require_constant.phpt new file mode 100644 index 0000000..6ee79fb --- /dev/null +++ b/tests/include/require_constant.phpt @@ -0,0 +1,17 @@ +--TEST-- +Require "Constant URL"; +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=0 +suhosin.log.phpscript=0 +suhosin.executor.include.whitelist= +suhosin.executor.include.blacklist= +--FILE-- + +--EXPECTF-- +ALERT - Include filename ('http://127.0.0.1/') is an URL that is not allowed (attacker 'REMOTE_ADDR not set', file '%s', line 2) diff --git a/tests/include/require_once_constant.phpt b/tests/include/require_once_constant.phpt new file mode 100644 index 0000000..43c69c8 --- /dev/null +++ b/tests/include/require_once_constant.phpt @@ -0,0 +1,17 @@ +--TEST-- +Require_once "Constant URL"; +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=0 +suhosin.log.phpscript=0 +suhosin.executor.include.whitelist= +suhosin.executor.include.blacklist= +--FILE-- + +--EXPECTF-- +ALERT - Include filename ('http://127.0.0.1/') is an URL that is not allowed (attacker 'REMOTE_ADDR not set', file '%s', line 2) diff --git a/tests/include/require_once_tmpvar.phpt b/tests/include/require_once_tmpvar.phpt new file mode 100644 index 0000000..2be24b2 --- /dev/null +++ b/tests/include/require_once_tmpvar.phpt @@ -0,0 +1,19 @@ +--TEST-- +Require_once "Temp Variable URL"; +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=0 +suhosin.log.phpscript=0 +suhosin.executor.include.whitelist= +suhosin.executor.include.blacklist= +--FILE-- + +--EXPECTF-- +ALERT - Include filename ('http://127.0.0.1/?') is an URL that is not allowed (attacker 'REMOTE_ADDR not set', file '%s', line 4) diff --git a/tests/include/require_once_var.phpt b/tests/include/require_once_var.phpt new file mode 100644 index 0000000..b3857f5 --- /dev/null +++ b/tests/include/require_once_var.phpt @@ -0,0 +1,18 @@ +--TEST-- +Require_once "Variable URL"; +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=0 +suhosin.log.phpscript=0 +suhosin.executor.include.whitelist= +suhosin.executor.include.blacklist= +--FILE-- + +--EXPECTF-- +ALERT - Include filename ('http://127.0.0.1/') is an URL that is not allowed (attacker 'REMOTE_ADDR not set', file '%s', line 3) diff --git a/tests/include/require_tmpvar.phpt b/tests/include/require_tmpvar.phpt new file mode 100644 index 0000000..d411067 --- /dev/null +++ b/tests/include/require_tmpvar.phpt @@ -0,0 +1,19 @@ +--TEST-- +Require "Temp Variable URL"; +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=0 +suhosin.log.phpscript=0 +suhosin.executor.include.whitelist= +suhosin.executor.include.blacklist= +--FILE-- + +--EXPECTF-- +ALERT - Include filename ('http://127.0.0.1/?') is an URL that is not allowed (attacker 'REMOTE_ADDR not set', file '%s', line 4) diff --git a/tests/include/require_var.phpt b/tests/include/require_var.phpt new file mode 100644 index 0000000..20468d4 --- /dev/null +++ b/tests/include/require_var.phpt @@ -0,0 +1,18 @@ +--TEST-- +Require "Variable URL"; +--SKIPIF-- + +--INI-- +suhosin.log.syslog=0 +suhosin.log.sapi=255 +suhosin.log.script=0 +suhosin.log.phpscript=0 +suhosin.executor.include.whitelist= +suhosin.executor.include.blacklist= +--FILE-- + +--EXPECTF-- +ALERT - Include filename ('http://127.0.0.1/') is an URL that is not allowed (attacker 'REMOTE_ADDR not set', file '%s', line 3) diff --git a/tests/skipif.inc b/tests/skipif.inc new file mode 100644 index 0000000..fd0598c --- /dev/null +++ b/tests/skipif.inc @@ -0,0 +1,4 @@ + diff --git a/tests/skipifcli.inc b/tests/skipifcli.inc new file mode 100644 index 0000000..63b41ca --- /dev/null +++ b/tests/skipifcli.inc @@ -0,0 +1,8 @@ + diff --git a/tests/skipifnotcli.inc b/tests/skipifnotcli.inc new file mode 100644 index 0000000..823cb91 --- /dev/null +++ b/tests/skipifnotcli.inc @@ -0,0 +1,8 @@ + diff --git a/treat_data.c b/treat_data.c new file mode 100644 index 0000000..d4af286 --- /dev/null +++ b/treat_data.c @@ -0,0 +1,216 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: treat_data.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "php_suhosin.h" +#include "SAPI.h" +#include "php_variables.h" +#include "ext/standard/url.h" + +SAPI_TREAT_DATA_FUNC(suhosin_treat_data) +{ + char *res = NULL, *var, *val, *separator = NULL; + const char *c_var; + zval *array_ptr; + int free_buffer = 0; + char *strtok_buf = NULL; + + /* Mark that we were not yet called */ + SUHOSIN_G(already_scanned) = 0; + + switch (arg) { + case PARSE_POST: + case PARSE_GET: + case PARSE_COOKIE: + ALLOC_ZVAL(array_ptr); + array_init(array_ptr); + INIT_PZVAL(array_ptr); + switch (arg) { + case PARSE_POST: + if (PG(http_globals)[TRACK_VARS_POST]) { + zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_POST]); + } + PG(http_globals)[TRACK_VARS_POST] = array_ptr; + + if (SUHOSIN_G(max_request_variables) && (SUHOSIN_G(max_post_vars) == 0 || + SUHOSIN_G(max_request_variables) <= SUHOSIN_G(max_post_vars))) { + SUHOSIN_G(max_post_vars) = SUHOSIN_G(max_request_variables); + } + break; + case PARSE_GET: + if (PG(http_globals)[TRACK_VARS_GET]) { + zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_GET]); + } + PG(http_globals)[TRACK_VARS_GET] = array_ptr; + if (SUHOSIN_G(max_request_variables) && (SUHOSIN_G(max_get_vars) == 0 || + SUHOSIN_G(max_request_variables) <= SUHOSIN_G(max_get_vars))) { + SUHOSIN_G(max_get_vars) = SUHOSIN_G(max_request_variables); + } + break; + case PARSE_COOKIE: + if (PG(http_globals)[TRACK_VARS_COOKIE]) { + zval_ptr_dtor(&PG(http_globals)[TRACK_VARS_COOKIE]); + } + PG(http_globals)[TRACK_VARS_COOKIE] = array_ptr; + if (SUHOSIN_G(max_request_variables) && (SUHOSIN_G(max_cookie_vars) == 0 || + SUHOSIN_G(max_request_variables) <= SUHOSIN_G(max_cookie_vars))) { + SUHOSIN_G(max_cookie_vars) = SUHOSIN_G(max_request_variables); + } + break; + } + break; + default: + array_ptr = destArray; + break; + } + + if (arg == PARSE_POST) { + sapi_handle_post(array_ptr TSRMLS_CC); + return; + } + + if (arg == PARSE_GET) { /* GET data */ + c_var = SG(request_info).query_string; + if (c_var && *c_var) { + res = (char *) estrdup(c_var); + free_buffer = 1; + } else { + free_buffer = 0; + } + } else if (arg == PARSE_COOKIE) { /* Cookie data */ + c_var = SG(request_info).cookie_data; + if (c_var && *c_var) { + if (SUHOSIN_G(cookie_encrypt)) { + res = (char *) estrdup(suhosin_cookie_decryptor(TSRMLS_C)); + } else { + res = (char *) estrdup(c_var); + } + free_buffer = 1; + } else { + free_buffer = 0; + } + } else if (arg == PARSE_STRING) { /* String data */ + res = str; + free_buffer = 1; + } + + if (!res) { + return; + } + + switch (arg) { + case PARSE_GET: + case PARSE_STRING: + separator = (char *) estrdup(PG(arg_separator).input); + break; + case PARSE_COOKIE: + separator = ";\0"; + break; + } + + var = php_strtok_r(res, separator, &strtok_buf); + + while (var) { + /* Overjump plain whitespace */ + while (*var && *var == ' ') var++; + + val = strchr(var, '='); + if (val) { /* have a value */ + int val_len; + unsigned int new_val_len; + + *val++ = '\0'; + php_url_decode(var, strlen(var)); + val_len = php_url_decode(val, strlen(val)); + val = estrndup(val, val_len); + if (suhosin_input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { +#ifdef ZEND_ENGINE_2 + if (sapi_module.input_filter(arg, var, &val, new_val_len, &new_val_len TSRMLS_CC)) { +#endif + php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); +#ifdef ZEND_ENGINE_2 + } +#endif + } else { + SUHOSIN_G(abort_request) = 1; + } + efree(val); + } else { + int val_len; + unsigned int new_val_len; + + php_url_decode(var, strlen(var)); + val_len = 0; + val = estrndup("", val_len); + if (suhosin_input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { +#ifdef ZEND_ENGINE_2 + if (sapi_module.input_filter(arg, var, &val, new_val_len, &new_val_len TSRMLS_CC)) { +#endif + php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); +#ifdef ZEND_ENGINE_2 + } +#endif + } else { + SUHOSIN_G(abort_request) = 1; + } + efree(val); + } + var = php_strtok_r(NULL, separator, &strtok_buf); + } + + if (arg != PARSE_COOKIE) { + efree(separator); + } + + if (free_buffer) { + efree(res); + } +} + + +void suhosin_hook_treat_data() +{ + sapi_register_treat_data(suhosin_treat_data); +#ifdef ZEND_ENGINE_2 + if (old_input_filter == NULL) { + old_input_filter = sapi_module.input_filter; + } + sapi_module.input_filter = suhosin_input_filter_wrapper; +#endif +} + + +/* + * 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 --git a/ufilter.c b/ufilter.c new file mode 100644 index 0000000..c2c64c2 --- /dev/null +++ b/ufilter.c @@ -0,0 +1,367 @@ +/* + +----------------------------------------------------------------------+ + | Suhosin Version 1 | + +----------------------------------------------------------------------+ + | Copyright (c) 2006-2007 The Hardened-PHP Project | + | Copyright (c) 2007 SektionEins GmbH | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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: ufilter.c,v 1.1.1.1 2007-11-28 01:15:35 sesser Exp $ +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "php_suhosin.h" +#include "php_variables.h" +#include "suhosin_rfc1867.h" + +#if !HAVE_RFC1867_CALLBACK +PHP_SUHOSIN_API int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC) = NULL; +#endif + +static int is_protected_varname(char *var, int var_len) +{ + 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; + } + + return 0; +protected_varname2: + return 1; +} + +/* {{{ SAPI_UPLOAD_VARNAME_FILTER_FUNC + */ +static int check_fileupload_varname(char *varname) +{ + char *index, *prev_index = NULL, *var; + unsigned int var_len, total_len, depth = 0; + TSRMLS_FETCH(); + + 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 (SUHOSIN_G(max_varname_length) && SUHOSIN_G(max_varname_length) < var_len) { + suhosin_log(S_FILES, "configured request variable name length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + goto return_failure; + } + } + if (SUHOSIN_G(max_totalname_length) && SUHOSIN_G(max_totalname_length) < total_len) { + suhosin_log(S_FILES, "configured request variable total name length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + goto return_failure; + } + } + if (SUHOSIN_G(max_post_name_length) && SUHOSIN_G(max_post_name_length) < var_len) { + suhosin_log(S_FILES, "configured POST variable name length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + goto return_failure; + } + } + if (SUHOSIN_G(max_post_totalname_length) && SUHOSIN_G(max_post_totalname_length) < var_len) { + suhosin_log(S_FILES, "configured POST variable total name length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + 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 (SUHOSIN_G(max_array_index_length) && SUHOSIN_G(max_array_index_length) < index_length) { + suhosin_log(S_FILES, "configured request variable array index length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + goto return_failure; + } + } + if (SUHOSIN_G(max_post_array_index_length) && SUHOSIN_G(max_post_array_index_length) < index_length) { + suhosin_log(S_FILES, "configured POST variable array index length limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + goto return_failure; + } + } + prev_index = index; + } + + } + + /* Drop this variable if it exceeds the array depth limit */ + if (SUHOSIN_G(max_array_depth) && SUHOSIN_G(max_array_depth) < depth) { + suhosin_log(S_FILES, "configured request variable array depth limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + goto return_failure; + } + } + if (SUHOSIN_G(max_post_array_depth) && SUHOSIN_G(max_post_array_depth) < depth) { + suhosin_log(S_FILES, "configured POST variable array depth limit exceeded - dropped variable '%s'", var); + if (!SUHOSIN_G(simulation)) { + 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 */ + + if (is_protected_varname(var, var_len)) { + suhosin_log(S_FILES, "tried to register forbidden variable '%s' through FILE variables", var); + if (!SUHOSIN_G(simulation)) { + goto return_failure; + } + } + + efree(var); + return SUCCESS; + +return_failure: + efree(var); + return FAILURE; +} +/* }}} */ + +int suhosin_rfc1867_filter(unsigned int event, void *event_data, void **extra TSRMLS_DC) +{ + int retval = SUCCESS; + + SDEBUG("rfc1867_filter %u", event); + + switch (event) { + case MULTIPART_EVENT_START: + case MULTIPART_EVENT_FORMDATA: + /* nothing todo */ + break; + + case MULTIPART_EVENT_FILE_START: + { + multipart_event_file_start *mefs = (multipart_event_file_start *) event_data; + + /* Drop if no more variables flag is set */ + if (SUHOSIN_G(no_more_uploads)) { + goto continue_with_failure; + } + + /* Drop this fileupload if the limit is reached */ + if (SUHOSIN_G(upload_limit) && SUHOSIN_G(upload_limit) <= SUHOSIN_G(num_uploads)) { + suhosin_log(S_FILES, "configured fileupload limit exceeded - file dropped"); + if (!SUHOSIN_G(simulation)) { + SUHOSIN_G(no_more_uploads) = 1; + goto continue_with_failure; + } + } + + + if (check_fileupload_varname(mefs->name) == FAILURE) { + goto continue_with_failure; + } + } + + break; + + case MULTIPART_EVENT_FILE_DATA: + + if (SUHOSIN_G(upload_disallow_elf)) { + multipart_event_file_data *mefd = (multipart_event_file_data *) event_data; + + if (mefd->offset == 0 && mefd->length > 10) { + if (mefd->data[0] == 0x7F && mefd->data[1] == 'E' && mefd->data[2] == 'L' && mefd->data[3] == 'F') { + suhosin_log(S_FILES, "uploaded file is an ELF executable - file dropped"); + if (!SUHOSIN_G(simulation)) { + goto continue_with_failure; + } + } + } + } + + if (SUHOSIN_G(upload_disallow_binary)) { + + multipart_event_file_data *mefd = (multipart_event_file_data *) event_data; + size_t i; + + for (i=0; ilength; i++) { + if (mefd->data[i] < 32 && !isspace(mefd->data[i])) { + suhosin_log(S_FILES, "uploaded file contains binary data - file dropped"); + if (!SUHOSIN_G(simulation)) { + goto continue_with_failure; + } + } + } + } + + if (SUHOSIN_G(upload_remove_binary)) { + + multipart_event_file_data *mefd = (multipart_event_file_data *) event_data; + size_t i, j; + + for (i=0, j=0; ilength; i++) { + if (mefd->data[i] >= 32 || isspace(mefd->data[i])) { + mefd->data[j++] = mefd->data[i]; + } + } + SDEBUG("removing binary %u %u",i,j); + /* IMPORTANT FOR DAISY CHAINING */ + mefd->length = j; + if (mefd->newlength) { + *mefd->newlength = j; + } + } + + break; + + case MULTIPART_EVENT_FILE_END: + + if (SUHOSIN_G(upload_verification_script)) { + multipart_event_file_end *mefe = (multipart_event_file_end *) event_data; + char cmd[8192]; + FILE *in; + int first=1; + char *sname = SUHOSIN_G(upload_verification_script); + + /* ignore files that will get deleted anyway */ + if (mefe->cancel_upload) { + break; + } + + /* ignore empty scriptnames */ + while (isspace(*sname)) ++sname; + if (*sname == 0) { + SUHOSIN_G(num_uploads)++; + break; + } + + ap_php_snprintf(cmd, sizeof(cmd), "%s %s", sname, mefe->temp_filename); + + if ((in=VCWD_POPEN(cmd, "r"))==NULL) { + suhosin_log(S_FILES, "unable to execute fileupload verification script %s - file dropped", sname); + if (!SUHOSIN_G(simulation)) { + goto continue_with_failure; + } else { + goto continue_with_next; + } + } + + 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) { + suhosin_log(S_FILES, "fileupload verification script disallows file - file dropped"); + if (!SUHOSIN_G(simulation)) { + goto continue_with_failure; + } + } + + SUHOSIN_G(num_uploads)++; + break; + + case MULTIPART_EVENT_END: + /* nothing todo */ + break; + + default: + /* unknown: return failure */ + goto continue_with_failure; + } +continue_with_next: +#if HAVE_RFC1867_CALLBACK + if (php_rfc1867_callback != NULL) { + return php_rfc1867_callback(event, event_data, extra TSRMLS_CC); + } +#endif + return SUCCESS; +continue_with_failure: + SUHOSIN_G(abort_request) = 1; + return FAILURE; +} + + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ -- cgit v1.3