Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:27634 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 41779 invoked by uid 1010); 24 Jan 2007 14:38:39 -0000 Delivered-To: ezmlm-scan-internals@lists.php.net Delivered-To: ezmlm-internals@lists.php.net Received: (qmail 41764 invoked from network); 24 Jan 2007 14:38:39 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 24 Jan 2007 14:38:39 -0000 X-Host-Fingerprint: 217.155.246.60 office.vbulletin.com Received: from [217.155.246.60] ([217.155.246.60:14049] helo=localhost.localdomain) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 68/D3-08544-E6F67B54 for ; Wed, 24 Jan 2007 09:38:38 -0500 Message-ID: <68.D3.08544.E6F67B54@pb1.pair.com> To: internals@lists.php.net Date: Wed, 24 Jan 2007 14:38:35 +0000 User-Agent: Thunderbird 1.5.0.9 (Windows/20061207) MIME-Version: 1.0 References: <45362247.2000306@ntlworld.com> In-Reply-To: <45362247.2000306@ntlworld.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Posted-By: 217.155.246.60 Subject: Re: [Patch] mysql_set_charset for mysql ext From: scottmacvicar@ntlworld.com (Scott MacVicar) This is a gentle nudge, there was no interest since this was posted 2 months ago, we had a client who get exploited recently because of this issue. We use mysqli where appropriate but sometimes its not available because hosts don't know any better. Since there are no plans to deprecate the mysql extension any time soon we at least need the ability to protect ourselves. Patches are again PHP 4_4, 5_2 and HEAD. Scott Scott MacVicar wrote: > Hi, > > Attached is a patch that adds a mysql_set_charset function to the MySQL > extension, its for all branches at the moment and ideally it should be > applied to all. > > Before anyone starts advocating that everyone upgrades to PHP5 and use > MySQLi its not always realistic for some and other people are just > stubborn. > > The reason for the patch is that the mysql_set_character_set function > provided by the MySQL API sets the internal MySQL character set for the > connection which is referenced by functions such as > mysql_real_escape_string. > > Without the ability to change the character set on the connection users > use the SET NAMES 'charset' query which lacks the ability to update the > internal character set. > > In certain cases this can lead to an SQL Injection. I'll simply refer > everyone to a blog entry by Ilia > http://ilia.ws/archives/103-mysql_real_escape_string-versus-Prepared-Statements.html > > > I'd like this consider this a security issue and get it applied to the > PHP 4 branch even though active development is more or less finished. > > Cheers, > Scott > > > ------------------------------------------------------------------------ > > Index: ext/mysql/php_mysql.c > =================================================================== > RCS file: /repository/php-src/ext/mysql/php_mysql.c,v > retrieving revision 1.226 > diff -u -r1.226 php_mysql.c > --- ext/mysql/php_mysql.c 8 Oct 2006 13:34:22 -0000 1.226 > +++ ext/mysql/php_mysql.c 18 Oct 2006 12:09:40 -0000 > @@ -94,6 +94,10 @@ > #define MYSQL_HAS_YEAR > #endif > > +#if (MYSQL_VERSION_ID > 40112 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID > 50005 > +#define MYSQL_HAS_SET_CHARSET > +#endif > + > #define MYSQL_ASSOC 1<<0 > #define MYSQL_NUM 1<<1 > #define MYSQL_BOTH (MYSQL_ASSOC|MYSQL_NUM) > @@ -166,6 +170,9 @@ > PHP_FE(mysql_thread_id, NULL) > PHP_FE(mysql_client_encoding, NULL) > PHP_FE(mysql_ping, NULL) > +#ifdef MYSQL_HAS_SET_CHARSET > + PHP_FE(mysql_set_charset, NULL) > +#endif > #ifdef HAVE_GETINFO_FUNCS > PHP_FE(mysql_get_client_info, NULL) > PHP_FE(mysql_get_host_info, NULL) > @@ -1119,6 +1126,48 @@ > /* }}} */ > #endif > > +#ifdef MYSQL_HAS_SET_CHARSET > +/* {{{ proto bool mysql_set_charset(string csname [, int link_identifier]) > + sets client character set */ > +PHP_FUNCTION(mysql_set_charset) > +{ > + zval **cs_name, **mysql_link; > + int id; > + php_mysql_conn *mysql; > + > + switch(ZEND_NUM_ARGS()) { > + case 1: > + if (zend_get_parameters_ex(1, &cs_name)==FAILURE) { > + RETURN_FALSE; > + } > + id = php_mysql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU); > + CHECK_LINK(id); > + break; > + case 2: > + if (zend_get_parameters_ex(2, &cs_name, &mysql_link)==FAILURE) { > + RETURN_FALSE; > + } > + id = -1; > + break; > + default: > + WRONG_PARAM_COUNT; > + break; > + } > + > + > + ZEND_FETCH_RESOURCE2(mysql, php_mysql_conn *, mysql_link, id, "MySQL-Link", le_link, le_plink); > + > + convert_to_string_ex(cs_name); > + > + if (!mysql_set_character_set(&mysql->conn, Z_STRVAL_PP(cs_name))) { > + RETURN_TRUE; > + } else { > + RETURN_FALSE; > + } > +} > +/* }}} */ > +#endif > + > #ifndef NETWARE /* The below two functions not supported on NetWare */ > #if MYSQL_VERSION_ID < 40000 > /* {{{ proto bool mysql_create_db(string database_name [, int link_identifier]) > Index: ext/mysql/php_mysql.h > =================================================================== > RCS file: /repository/php-src/ext/mysql/php_mysql.h,v > retrieving revision 1.38 > diff -u -r1.38 php_mysql.h > --- ext/mysql/php_mysql.h 1 Jan 2006 13:09:52 -0000 1.38 > +++ ext/mysql/php_mysql.h 18 Oct 2006 12:10:02 -0000 > @@ -91,6 +91,9 @@ > PHP_FUNCTION(mysql_thread_id); > PHP_FUNCTION(mysql_client_encoding); > PHP_FUNCTION(mysql_ping); > +#if (MYSQL_VERSION_ID > 40112 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID > 50005 > +PHP_FUNCTION(mysql_set_charset); > +#endif > > ZEND_BEGIN_MODULE_GLOBALS(mysql) > long default_link; > > > ------------------------------------------------------------------------ > > Index: ext/mysql/php_mysql.c > =================================================================== > RCS file: /repository/php-src/ext/mysql/php_mysql.c,v > retrieving revision 1.174.2.29.2.2 > diff -u -r1.174.2.29.2.2 php_mysql.c > --- ext/mysql/php_mysql.c 1 Jan 2006 13:46:55 -0000 1.174.2.29.2.2 > +++ ext/mysql/php_mysql.c 18 Oct 2006 11:54:02 -0000 > @@ -93,6 +93,10 @@ > #define MYSQL_HAS_YEAR > #endif > > +#if (MYSQL_VERSION_ID > 40112 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID > 50005 > +#define MYSQL_HAS_SET_CHARSET > +#endif > + > #define MYSQL_ASSOC 1<<0 > #define MYSQL_NUM 1<<1 > #define MYSQL_BOTH (MYSQL_ASSOC|MYSQL_NUM) > @@ -162,6 +166,9 @@ > PHP_FE(mysql_thread_id, NULL) > PHP_FE(mysql_client_encoding, NULL) > PHP_FE(mysql_ping, NULL) > +#ifdef MYSQL_HAS_SET_CHARSET > + PHP_FE(mysql_set_charset, NULL) > +#endif > #ifdef HAVE_GETINFO_FUNCS > PHP_FE(mysql_get_client_info, NULL) > PHP_FE(mysql_get_host_info, NULL) > @@ -1123,6 +1130,48 @@ > /* }}} */ > #endif > > +#ifdef MYSQL_HAS_SET_CHARSET > +/* {{{ proto bool mysql_set_charset(string csname [, int link_identifier]) > + sets client character set */ > +PHP_FUNCTION(mysql_set_charset) > +{ > + zval **cs_name, **mysql_link; > + int id; > + php_mysql_conn *mysql; > + > + switch(ZEND_NUM_ARGS()) { > + case 1: > + if (zend_get_parameters_ex(1, &cs_name)==FAILURE) { > + RETURN_FALSE; > + } > + id = php_mysql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU); > + CHECK_LINK(id); > + break; > + case 2: > + if (zend_get_parameters_ex(2, &cs_name, &mysql_link)==FAILURE) { > + RETURN_FALSE; > + } > + id = -1; > + break; > + default: > + WRONG_PARAM_COUNT; > + break; > + } > + > + > + ZEND_FETCH_RESOURCE2(mysql, php_mysql_conn *, mysql_link, id, "MySQL-Link", le_link, le_plink); > + > + convert_to_string_ex(cs_name); > + > + if (!mysql_set_character_set(&mysql->conn, Z_STRVAL_PP(cs_name))) { > + RETURN_TRUE; > + } else { > + RETURN_FALSE; > + } > +} > +/* }}} */ > +#endif > + > #ifndef NETWARE /* The below two functions not supported on NetWare */ > #if MYSQL_VERSION_ID < 40000 > /* {{{ proto bool mysql_create_db(string database_name [, int link_identifier]) > Index: ext/mysql/php_mysql.h > =================================================================== > RCS file: /repository/php-src/ext/mysql/php_mysql.h,v > retrieving revision 1.33.2.2.4.1 > diff -u -r1.33.2.2.4.1 php_mysql.h > --- ext/mysql/php_mysql.h 1 Jan 2006 13:46:55 -0000 1.33.2.2.4.1 > +++ ext/mysql/php_mysql.h 18 Oct 2006 11:41:37 -0000 > @@ -91,6 +91,9 @@ > PHP_FUNCTION(mysql_thread_id); > PHP_FUNCTION(mysql_client_encoding); > PHP_FUNCTION(mysql_ping); > +#if (MYSQL_VERSION_ID > 40112 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID > 50005 > +PHP_FUNCTION(mysql_set_charset); > +#endif > > ZEND_BEGIN_MODULE_GLOBALS(mysql) > long default_link; > > > ------------------------------------------------------------------------ > > Index: ext/mysql/php_mysql.c > =================================================================== > RCS file: /repository/php-src/ext/mysql/php_mysql.c,v > retrieving revision 1.213.2.6.2.5 > diff -u -r1.213.2.6.2.5 php_mysql.c > --- ext/mysql/php_mysql.c 2 Aug 2006 10:04:11 -0000 1.213.2.6.2.5 > +++ ext/mysql/php_mysql.c 18 Oct 2006 12:05:41 -0000 > @@ -101,6 +101,10 @@ > #define MYSQL_HAS_YEAR > #endif > > +#if (MYSQL_VERSION_ID > 40112 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID > 50005 > +#define MYSQL_HAS_SET_CHARSET > +#endif > + > #define MYSQL_ASSOC 1<<0 > #define MYSQL_NUM 1<<1 > #define MYSQL_BOTH (MYSQL_ASSOC|MYSQL_NUM) > @@ -173,6 +177,9 @@ > PHP_FE(mysql_thread_id, NULL) > PHP_FE(mysql_client_encoding, NULL) > PHP_FE(mysql_ping, NULL) > +#ifdef MYSQL_HAS_SET_CHARSET > + PHP_FE(mysql_set_charset, NULL) > +#endif > #ifdef HAVE_GETINFO_FUNCS > PHP_FE(mysql_get_client_info, NULL) > PHP_FE(mysql_get_host_info, NULL) > @@ -1126,6 +1133,48 @@ > /* }}} */ > #endif > > +#ifdef MYSQL_HAS_SET_CHARSET > +/* {{{ proto bool mysql_set_charset(string csname [, int link_identifier]) > + sets client character set */ > +PHP_FUNCTION(mysql_set_charset) > +{ > + zval **cs_name, **mysql_link; > + int id; > + php_mysql_conn *mysql; > + > + switch(ZEND_NUM_ARGS()) { > + case 1: > + if (zend_get_parameters_ex(1, &cs_name)==FAILURE) { > + RETURN_FALSE; > + } > + id = php_mysql_get_default_link(INTERNAL_FUNCTION_PARAM_PASSTHRU); > + CHECK_LINK(id); > + break; > + case 2: > + if (zend_get_parameters_ex(2, &cs_name, &mysql_link)==FAILURE) { > + RETURN_FALSE; > + } > + id = -1; > + break; > + default: > + WRONG_PARAM_COUNT; > + break; > + } > + > + > + ZEND_FETCH_RESOURCE2(mysql, php_mysql_conn *, mysql_link, id, "MySQL-Link", le_link, le_plink); > + > + convert_to_string_ex(cs_name); > + > + if (!mysql_set_character_set(&mysql->conn, Z_STRVAL_PP(cs_name))) { > + RETURN_TRUE; > + } else { > + RETURN_FALSE; > + } > +} > +/* }}} */ > +#endif > + > #ifndef NETWARE /* The below two functions not supported on NetWare */ > #if MYSQL_VERSION_ID < 40000 > /* {{{ proto bool mysql_create_db(string database_name [, int link_identifier]) > Index: ext/mysql/php_mysql.h > =================================================================== > RCS file: /repository/php-src/ext/mysql/php_mysql.h,v > retrieving revision 1.37.2.1 > diff -u -r1.37.2.1 php_mysql.h > --- ext/mysql/php_mysql.h 1 Jan 2006 12:50:09 -0000 1.37.2.1 > +++ ext/mysql/php_mysql.h 18 Oct 2006 12:02:50 -0000 > @@ -91,6 +91,9 @@ > PHP_FUNCTION(mysql_thread_id); > PHP_FUNCTION(mysql_client_encoding); > PHP_FUNCTION(mysql_ping); > +#if (MYSQL_VERSION_ID > 40112 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID > 50005 > +PHP_FUNCTION(mysql_set_charset); > +#endif > > ZEND_BEGIN_MODULE_GLOBALS(mysql) > long default_link;