Program: CWE-119
Project: CVE-2012-0807
Buggy source:
/*
  +----------------------------------------------------------------------+
  | Suhosin Version 1                                                    |
  +----------------------------------------------------------------------+
  | Copyright (c) 2006-2007 The Hardened-PHP Project                     |
  | Copyright (c) 2007-2012 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 <sesser@sektioneins.de>                         |
  +----------------------------------------------------------------------+
*/
/*
  $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"

#if PHP_VERSION_ID >= 50300
static int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC) = NULL;
#else
static int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC) = NULL;
#endif

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
 */
#if PHP_VERSION_ID >= 50300
int suhosin_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
#else
int suhosin_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC)
#endif
{
	int retval = SAPI_HEADER_ADD, i;
	char *tmp;

#if PHP_VERSION_ID >= 50300
	if (op != SAPI_HEADER_ADD && op != SAPI_HEADER_REPLACE) {
                goto suhosin_skip_header_handling;
	}
#endif
	
	if (sapi_header && sapi_header->header) {
	
		tmp = sapi_header->header;

		for (i=0; i<sapi_header->header_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;
				}
			}
			if (SUHOSIN_G(allow_multiheader)) {
				continue;
			} 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;
	}

suhosin_skip_header_handling:
	/* If existing call the sapi header handler */
	if (orig_header_handler) {
#if PHP_VERSION_ID >= 50300
		retval = orig_header_handler(sapi_header, op, sapi_headers TSRMLS_CC);
#else
		retval = orig_header_handler(sapi_header, sapi_headers TSRMLS_CC);
#endif
	}

	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
 */




Fixed version (ground truth):
/*
  +----------------------------------------------------------------------+
  | Suhosin Version 1                                                    |
  +----------------------------------------------------------------------+
  | Copyright (c) 2006-2007 The Hardened-PHP Project                     |
  | Copyright (c) 2007-2012 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 <sesser@sektioneins.de>                         |
  +----------------------------------------------------------------------+
*/
/*
  $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"

#if PHP_VERSION_ID >= 50300
static int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC) = NULL;
#else
static int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC) = NULL;
#endif

char *suhosin_encrypt_single_cookie(char *name, int name_len, char *value, int value_len, char *key TSRMLS_DC)
{
	char *buf, *buf2, *d, *d_url;
	int l;

	buf = estrndup(name, name_len);
	
	
	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:
			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;
		}
	}
	
	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);
	efree(buf);
	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)
{
    int o_name_len = name_len;
	char *buf, *buf2, *d, *d_url;
	int l;

	buf = estrndup(name, name_len);
		
	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:
			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;
		}
	}
	
	
	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:
	efree(buf);
	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
 */
#if PHP_VERSION_ID >= 50300
int suhosin_header_handler(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers TSRMLS_DC)
#else
int suhosin_header_handler(sapi_header_struct *sapi_header, sapi_headers_struct *sapi_headers TSRMLS_DC)
#endif
{
	int retval = SAPI_HEADER_ADD, i;
	char *tmp;

#if PHP_VERSION_ID >= 50300
	if (op != SAPI_HEADER_ADD && op != SAPI_HEADER_REPLACE) {
                goto suhosin_skip_header_handling;
	}
#endif
	
	if (sapi_header && sapi_header->header) {
	
		tmp = sapi_header->header;

		for (i=0; i<sapi_header->header_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;
				}
			}
			if (SUHOSIN_G(allow_multiheader)) {
				continue;
			} 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;
	}

suhosin_skip_header_handling:
	/* If existing call the sapi header handler */
	if (orig_header_handler) {
#if PHP_VERSION_ID >= 50300
		retval = orig_header_handler(sapi_header, op, sapi_headers TSRMLS_CC);
#else
		retval = orig_header_handler(sapi_header, sapi_headers TSRMLS_CC);
#endif
	}

	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
 */