]> granicus.if.org Git - php/commitdiff
Fix for bug#49234 method not found ssl_set
authorAndrey Hristov <andrey@php.net>
Thu, 15 Apr 2010 11:01:30 +0000 (11:01 +0000)
committerAndrey Hristov <andrey@php.net>
Thu, 15 Apr 2010 11:01:30 +0000 (11:01 +0000)
Patch was tested and compiles on Windows. (Thanks Kalle)

15 files changed:
ext/mysqli/mysqli_api.c
ext/mysqli/mysqli_fe.c
ext/mysqli/tests/mysqli_class_mysqli_interface.phpt
ext/mysqli/tests/mysqli_class_mysqli_reflection.phpt
ext/mysqlnd/config9.m4
ext/mysqlnd/mysqlnd.c
ext/mysqlnd/mysqlnd.h
ext/mysqlnd/mysqlnd_enum_n_def.h
ext/mysqlnd/mysqlnd_libmysql_compat.h
ext/mysqlnd/mysqlnd_net.c
ext/mysqlnd/mysqlnd_structs.h
ext/mysqlnd/mysqlnd_wireprotocol.c
ext/mysqlnd/mysqlnd_wireprotocol.h
ext/mysqlnd/php_mysqlnd.c
ext/openssl/openssl.c

index 6162cce92b5c5db93d4411f7afb3f1dda726d2e8..651bdeacabd717394b9cfd7e6bb50f4ffb08e936 100644 (file)
@@ -2121,7 +2121,6 @@ PHP_FUNCTION(mysqli_sqlstate)
 
 /* {{{ proto bool mysqli_ssl_set(object link ,string key ,string cert ,string ca ,string capath ,string cipher]) U
 */
-#if !defined(MYSQLI_USE_MYSQLND)
 PHP_FUNCTION(mysqli_ssl_set)
 {
        MY_MYSQL        *mysql;
@@ -2144,7 +2143,6 @@ PHP_FUNCTION(mysqli_ssl_set)
 
        RETURN_TRUE;
 }
-#endif
 /* }}} */
   
 /* {{{ proto mixed mysqli_stat(object link) 
index 59cb65563c754f51e511660f4d9d2ef001337da2..0f9c9b6943322287e63ceb6df61541bcf1918c2a 100644 (file)
@@ -156,9 +156,7 @@ const zend_function_entry mysqli_functions[] = {
        PHP_FE(mysqli_stmt_reset,                                                       NULL)
        PHP_FE(mysqli_stmt_param_count,                                         NULL)
        PHP_FE(mysqli_sqlstate,                                                         NULL)
-#if !defined(MYSQLI_USE_MYSQLND)
        PHP_FE(mysqli_ssl_set,                                                          NULL)
-#endif
        PHP_FE(mysqli_stat,                                                                     NULL)
        PHP_FE(mysqli_stmt_affected_rows,                                       NULL)
        PHP_FE(mysqli_stmt_close,                                                       NULL)
@@ -246,9 +244,7 @@ const zend_function_entry mysqli_link_methods[] = {
        PHP_FALIAS(set_charset,mysqli_set_charset,NULL)
 #endif
        PHP_FALIAS(set_opt, mysqli_options,NULL)
-#if !defined(MYSQLI_USE_MYSQLND)
        PHP_FALIAS(ssl_set,mysqli_ssl_set,NULL)
-#endif
        PHP_FALIAS(stat,mysqli_stat,NULL)
        PHP_FALIAS(stmt_init,mysqli_stmt_init, NULL)
        PHP_FALIAS(store_result,mysqli_store_result,NULL)
index b86f69c445b76bc0317fda078cb94a47ef575aff..50c66d4f4d659e8b448d2b9571f7265e4a03247a 100644 (file)
@@ -50,6 +50,7 @@ require_once('skipifconnectfailure.inc');
                'select_db'                     => true,
                'set_charset'                   => true,
                'set_opt'                       => true,
+               'ssl_set'                       => true,
                'stat'                          => true,
                'stmt_init'                     => true,
                'store_result'                  => true,
index 802e524337b98bc10f36f12b35aa2af15217205a..ebe7a0285d63311db248932e0f8ac1ad1a4d1e14 100644 (file)
@@ -615,6 +615,22 @@ Modifiers: 256
 Number of Parameters: 0
 Number of Required Parameters: 0
 
+Inspecting method 'ssl_set'
+isFinal: no
+isAbstract: no
+isPublic: yes
+isPrivate: no
+isProtected: no
+isStatic: no
+isConstructor: no
+isDestructor: no
+isInternal: yes
+isUserDefined: no
+returnsReference: no
+Modifiers: 256
+Number of Parameters: 0
+Number of Required Parameters: 0
+
 Inspecting method 'stat'
 isFinal: no
 isAbstract: no
index 72e27961952182fe8a8b41aaeddd91b61d5905f5..2fcf336fc49b3d2d866bc52fa2d9c573b09739f1 100644 (file)
@@ -36,6 +36,7 @@ if test "$PHP_MYSQLND_ENABLED" = "yes"; then
       MYSQLND_LIBS="$MYSQLND_LIBS -lz"
     fi
   fi
+  AC_DEFINE([MYSQLND_SSL_SUPPORTED], 1, [Enable SSL support])
 fi
 
 if test "$PHP_MYSQLND_ENABLED" = "yes" || test "$PHP_MYSQLI" != "no"; then
index 078d2e6afaf3fa8a6ba2836c90b20ae983fc5cf3..bb26c4cd5c18ef4003fe2f72b886f04f4b69c65e 100644 (file)
@@ -109,27 +109,8 @@ MYSQLND_METHOD(mysqlnd_conn, free_options)(MYSQLND *conn TSRMLS_DC)
                mnd_pefree(conn->options.cfg_section, pers);
                conn->options.cfg_section = NULL;
        }
-       if (conn->options.ssl_key) {
-               mnd_pefree(conn->options.ssl_key, pers);
-               conn->options.ssl_key = NULL;
-       }
-       if (conn->options.ssl_cert) {
-               mnd_pefree(conn->options.ssl_cert, pers);
-               conn->options.ssl_cert = NULL;
-       }
-       if (conn->options.ssl_ca) {
-               mnd_pefree(conn->options.ssl_ca, pers);
-               conn->options.ssl_ca = NULL;
-       }
-       if (conn->options.ssl_capath) {
-               mnd_pefree(conn->options.ssl_capath, pers);
-               conn->options.ssl_capath = NULL;
-       }
-       if (conn->options.ssl_cipher) {
-               mnd_pefree(conn->options.ssl_cipher, pers);
-               conn->options.ssl_cipher = NULL;
-       }
 }
+/* }}} */
 
 
 /* {{{ mysqlnd_conn::free_contents */
@@ -356,9 +337,8 @@ MYSQLND_METHOD(mysqlnd_conn, simple_command)(MYSQLND *conn, enum php_mysqlnd_ser
                        DBG_ERR("Server is gone");
                        DBG_RETURN(FAIL);
                default:
-                       SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
-                                                        mysqlnd_out_of_sync);
-                       DBG_ERR("Command out of sync");
+                       SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
+                       DBG_ERR_FMT("Command out of sync. State=%d", CONN_GET_STATE(conn));
                        DBG_RETURN(FAIL);
        }
 
@@ -597,7 +577,20 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND *conn,
                mysql_flags &= ~CLIENT_COMPRESS;
        }
 #endif
-
+#ifndef MYSQLND_SSL_SUPPORTED
+       if (mysql_flags & CLIENT_SSL) {
+               mysql_flags &= ~CLIENT_SSL;
+       }
+#else
+       if (conn->net->options.ssl_key || conn->net->options.ssl_cert ||
+               conn->net->options.ssl_ca || conn->net->options.ssl_capath || conn->net->options.ssl_cipher)
+       {
+               mysql_flags |= CLIENT_SSL;
+       }
+       if ((greet_packet->server_capabilities & CLIENT_SSL) && (mysql_flags & CLIENT_SSL)) {
+               auth_packet->send_half_packet = TRUE;
+       }
+#endif
        auth_packet->user               = user;
        auth_packet->password   = passwd;
 
@@ -619,12 +612,33 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND *conn,
 
        conn->scramble = auth_packet->server_scramble_buf = mnd_pemalloc(SCRAMBLE_LENGTH, conn->persistent);
        memcpy(auth_packet->server_scramble_buf, greet_packet->scramble_buf, SCRAMBLE_LENGTH);
+       
        if (!PACKET_WRITE(auth_packet, conn)) {
                CONN_SET_STATE(conn, CONN_QUIT_SENT);
                SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
                goto err;
        }
 
+#ifdef MYSQLND_SSL_SUPPORTED
+       if (auth_packet->send_half_packet) {
+               zend_bool verify = mysql_flags & CLIENT_SSL_VERIFY_SERVER_CERT? TRUE:FALSE;
+               DBG_INF("Switching to SSL");
+
+               conn->net->m.set_client_option(conn->net, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (const char *) &verify TSRMLS_CC);
+
+               if (FAIL == conn->net->m.enable_ssl(conn->net TSRMLS_CC)) {
+                       goto err;
+               }
+               
+               auth_packet->send_half_packet = FALSE;
+               if (!PACKET_WRITE(auth_packet, conn)) {
+                       CONN_SET_STATE(conn, CONN_QUIT_SENT);
+                       SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
+                       goto err;
+               }
+       }
+#endif
+
        if (FAIL == PACKET_READ(ok_packet, conn) || ok_packet->field_count >= 0xFE) {
                if (ok_packet->field_count == 0xFE) {
                        /* old authentication with new server  !*/
@@ -1178,6 +1192,18 @@ PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, size
 }
 /* }}} */
 
+/* {{{ mysqlnd_conn::ssl_set */
+void
+MYSQLND_METHOD(mysqlnd_conn, ssl_set)(MYSQLND * const conn, const char * key, const char * const cert, const char * const ca, const char * const capath, const char * const cipher TSRMLS_DC)
+{
+       conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_KEY, key TSRMLS_CC);
+       conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CERT, cert TSRMLS_CC);
+       conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CA, ca TSRMLS_CC);
+       conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CAPATH, capath TSRMLS_CC);
+       conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CIPHER, cipher TSRMLS_CC);
+}
+/* }}} */
+
 
 /* {{{ mysqlnd_conn::escape_string */
 static ulong
@@ -1875,6 +1901,12 @@ MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn,
                case MYSQL_OPT_READ_TIMEOUT:
                case MYSQL_OPT_WRITE_TIMEOUT:
 #endif
+               case MYSQLND_OPT_SSL_KEY:
+               case MYSQLND_OPT_SSL_CERT:
+               case MYSQLND_OPT_SSL_CA:
+               case MYSQLND_OPT_SSL_CAPATH:
+               case MYSQLND_OPT_SSL_CIPHER:
+               case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
                case MYSQL_OPT_CONNECT_TIMEOUT:
                case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
                case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
@@ -1913,7 +1945,6 @@ MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn,
 #ifdef WHEN_SUPPORTED_BY_MYSQLI
                case MYSQL_SET_CLIENT_IP:
                case MYSQL_REPORT_DATA_TRUNCATION:
-               case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
 #endif
                        /* currently not supported. Todo!! */
                        break;
@@ -2100,7 +2131,9 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_conn)
        MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response),
        MYSQLND_METHOD(mysqlnd_conn, restart_psession),
        MYSQLND_METHOD(mysqlnd_conn, end_psession),
-       MYSQLND_METHOD(mysqlnd_conn, send_close)
+       MYSQLND_METHOD(mysqlnd_conn, send_close),
+
+       MYSQLND_METHOD(mysqlnd_conn, ssl_set)
 MYSQLND_CLASS_METHODS_END;
 
 
index 1539c7b5255cacd76488d97889a8c9b84ae13a51..4f15aa4fef26a38f8c90db116358f6fcad1987ea 100644 (file)
@@ -172,6 +172,8 @@ PHPAPI unsigned long * _mysqlnd_fetch_lengths(MYSQLND_RES * const result  TSRMLS
 PHPAPI const char *    mysqlnd_get_client_info();
 PHPAPI unsigned int    mysqlnd_get_client_version();
 
+#define mysqlnd_ssl_set(conn, key, cert, ca, capath, cipher) (conn)->m->ssl_set((conn), (key), (cert), (ca), (capath), (cipher) TSRMLS_CC)
+
 /* PS */
 #define mysqlnd_stmt_insert_id(stmt)           (stmt)->m->get_last_insert_id((stmt) TSRMLS_CC)
 #define mysqlnd_stmt_affected_rows(stmt)       (stmt)->m->get_affected_rows((stmt) TSRMLS_CC)
index 4550bfd621c8854677f328fd901497c04a67d2d1..d6aadd54784073eef093af1bd19aff235a3bf351 100644 (file)
@@ -90,6 +90,8 @@
 #define CLIENT_MULTI_RESULTS           (1UL << 17) /* Enable/disable multi-results */
 #define CLIENT_PS_MULTI_RESULTS                (1UL << 18) /* Multi-results in PS-protocol */
 
+#define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30)
+
 typedef enum mysqlnd_extension
 {
        MYSQLND_MYSQL = 0,
@@ -156,6 +158,12 @@ typedef enum mysqlnd_option
 #endif
        MYSQLND_OPT_NET_CMD_BUFFER_SIZE = 202,
        MYSQLND_OPT_NET_READ_BUFFER_SIZE = 203,
+       MYSQLND_OPT_SSL_KEY = 204,
+       MYSQLND_OPT_SSL_CERT = 205,
+       MYSQLND_OPT_SSL_CA = 206,
+       MYSQLND_OPT_SSL_CAPATH = 207,
+       MYSQLND_OPT_SSL_CIPHER = 208,
+       MYSQLND_OPT_SSL_PASSPHRASE = 209
 } enum_mysqlnd_option;
 
 
index 78f48c97b99f18010ea01e9af9224b0d716cf03c..4044ae6a253d300d0890831f9727ef8e378b8f04 100644 (file)
@@ -79,6 +79,7 @@
 #define mysql_set_server_option(r,o)   mysqlnd_set_server_option((r), (o))
 #define mysql_set_character_set(r,a)   mysqlnd_set_character_set((r), (a))
 #define mysql_sqlstate(r)                              mysqlnd_sqlstate((r))
+#define mysql_ssl_set(c,key,cert,ca,capath,cipher)     mysqlnd_ssl_set((c), (key), (cert), (ca), (capath), (cipher))
 #define mysql_stmt_affected_rows(s)            mysqlnd_stmt_affected_rows((s))
 #define mysql_stmt_field_count(s)              mysqlnd_stmt_field_count((s))
 #define mysql_stmt_param_count(s)              mysqlnd_stmt_param_count((s))
index d88e20418cfc79bb66fabc51ed2efc629f6290df..4705c8b4ef7d867d9645da1f67198f52cc1d4619 100644 (file)
@@ -172,8 +172,8 @@ MYSQLND_METHOD(mysqlnd_net, connect)(MYSQLND_NET * net, const char * const schem
                /* should always happen because read_timeout cannot be set via API */
                net->options.timeout_read = (unsigned int) MYSQLND_G(net_read_timeout);
        }
-       if (net->options.timeout_read)
-       {
+       if (net->options.timeout_read) {
+               DBG_INF_FMT("setting %u as PHP_STREAM_OPTION_READ_TIMEOUT", net->options.timeout_read);
                tv.tv_sec = net->options.timeout_read;
                tv.tv_usec = 0;
                php_stream_set_option(net->stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
@@ -587,6 +587,63 @@ MYSQLND_METHOD(mysqlnd_net, set_client_option)(MYSQLND_NET * const net, enum mys
                        DBG_INF("MYSQL_OPT_CONNECT_TIMEOUT");
                        net->options.timeout_connect = *(unsigned int*) value;
                        break;
+               case MYSQLND_OPT_SSL_KEY:
+                       {
+                               zend_bool pers = net->persistent;
+                               if (net->options.ssl_key) {
+                                       mnd_pefree(net->options.ssl_key, pers);
+                               }
+                               net->options.ssl_key = value? mnd_pestrdup(value, pers) : NULL;
+                               break;
+                       }
+               case MYSQLND_OPT_SSL_CERT:
+                       {
+                               zend_bool pers = net->persistent;
+                               if (net->options.ssl_cert) {
+                                       mnd_pefree(net->options.ssl_cert, pers);
+                               }
+                               net->options.ssl_cert = value? mnd_pestrdup(value, pers) : NULL;
+                               break;
+                       }
+               case MYSQLND_OPT_SSL_CA:
+                       {
+                               zend_bool pers = net->persistent;
+                               if (net->options.ssl_ca) {
+                                       mnd_pefree(net->options.ssl_ca, pers);
+                               }
+                               net->options.ssl_ca = value? mnd_pestrdup(value, pers) : NULL;
+                               break;
+                       }
+               case MYSQLND_OPT_SSL_CAPATH:
+                       {
+                               zend_bool pers = net->persistent;
+                               if (net->options.ssl_capath) {
+                                       mnd_pefree(net->options.ssl_capath, pers);
+                               }
+                               net->options.ssl_capath = value? mnd_pestrdup(value, pers) : NULL;
+                               break;
+                       }
+               case MYSQLND_OPT_SSL_CIPHER:
+                       {
+                               zend_bool pers = net->persistent;
+                               if (net->options.ssl_cipher) {
+                                       mnd_pefree(net->options.ssl_cipher, pers);
+                               }
+                               net->options.ssl_cipher = value? mnd_pestrdup(value, pers) : NULL;
+                               break;
+                       }
+               case MYSQLND_OPT_SSL_PASSPHRASE:
+                       {
+                               zend_bool pers = net->persistent;
+                               if (net->options.ssl_passphrase) {
+                                       mnd_pefree(net->options.ssl_passphrase, pers);
+                               }
+                               net->options.ssl_passphrase = value? mnd_pestrdup(value, pers) : NULL;
+                               break;
+                       }
+               case MYSQL_OPT_SSL_VERIFY_SERVER_CERT:
+                       net->options.ssl_verify_peer = value? ((*(zend_bool *)value)? TRUE:FALSE): FALSE;
+                       break;
 #ifdef WHEN_SUPPORTED_BY_MYSQLI
                case MYSQL_OPT_READ_TIMEOUT:
                        DBG_INF("MYSQL_OPT_READ_TIMEOUT");
@@ -657,12 +714,113 @@ MYSQLND_METHOD(mysqlnd_net, consume_uneaten_data)(MYSQLND_NET * const net, enum
 }
 /* }}} */
 
+/*
+  in libmyusql, if cert and !key then key=cert
+*/
+/* {{{ mysqlnd_net::enable_ssl */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_net, enable_ssl)(MYSQLND_NET * const net TSRMLS_DC)
+{
+#ifdef MYSQLND_SSL_SUPPORTED
+       php_stream_context *context = php_stream_context_alloc();
+       DBG_ENTER("mysqlnd_net::enable_ssl");
+       if (!context) {
+               DBG_RETURN(FAIL);       
+       }
+
+       if (net->options.ssl_key) {
+               zval key_zval;
+               ZVAL_STRING(&key_zval, net->options.ssl_key, 0);
+               DBG_INF("key");
+               php_stream_context_set_option(context, "ssl", "local_pk", &key_zval);   
+       }
+       if (net->options.ssl_verify_peer) {
+               zval verify_peer_zval;
+               ZVAL_TRUE(&verify_peer_zval);
+               DBG_INF("verify peer");
+               php_stream_context_set_option(context, "ssl", "verify_peer", &verify_peer_zval);
+       }
+       if (net->options.ssl_cert) {
+               zval cert_zval;
+               ZVAL_STRING(&cert_zval, net->options.ssl_cert, 0);
+               DBG_INF_FMT("local_cert=%s", net->options.ssl_cert);
+               php_stream_context_set_option(context, "ssl", "local_cert", &cert_zval);
+               if (!net->options.ssl_key) {
+                       php_stream_context_set_option(context, "ssl", "local_pk", &cert_zval);  
+               }
+       }
+       if (net->options.ssl_ca) {
+               zval cafile_zval;
+               ZVAL_STRING(&cafile_zval, net->options.ssl_ca, 0);
+               DBG_INF_FMT("cafile=%s", net->options.ssl_ca);
+               php_stream_context_set_option(context, "ssl", "cafile", &cafile_zval);
+       }
+       if (net->options.ssl_capath) {
+               zval capath_zval;
+               ZVAL_STRING(&capath_zval, net->options.ssl_capath, 0);
+               DBG_INF_FMT("capath=%s", net->options.ssl_capath);
+               php_stream_context_set_option(context, "ssl", "cafile", &capath_zval);
+       }
+       if (net->options.ssl_passphrase) {
+               zval passphrase_zval;
+               ZVAL_STRING(&passphrase_zval, net->options.ssl_passphrase, 0);
+               php_stream_context_set_option(context, "ssl", "passphrase", &passphrase_zval);
+       }
+       if (net->options.ssl_cipher) {
+               zval cipher_zval;
+               ZVAL_STRING(&cipher_zval, net->options.ssl_cipher, 0);
+               DBG_INF_FMT("ciphers=%s", net->options.ssl_cipher);
+               php_stream_context_set_option(context, "ssl", "ciphers", &cipher_zval);
+       }
+       php_stream_context_set(net->stream, context);
+       if (php_stream_xport_crypto_setup(net->stream, STREAM_CRYPTO_METHOD_TLS_CLIENT, NULL TSRMLS_CC) < 0 ||
+           php_stream_xport_crypto_enable(net->stream, 1 TSRMLS_CC) < 0)
+       {
+               DBG_ERR("Cannot connect to MySQL by using SSL");
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot connect to MySQL by using SSL");
+               DBG_RETURN(FAIL);
+       }
+       /*
+         get rid of the context. we are persistent and if this is a real pconn used by mysql/mysqli,
+         then the context would not survive cleaning of EG(regular_list), where it is registered, as a
+         resource. What happens is that after this destruction any use of the network will mean usage
+         of the context, which means usage of already freed memory, bad. Actually we don't need this
+         context anymore after we have enabled SSL on the connection. Thus it is very simple, we remove it.
+       */
+       php_stream_context_set(net->stream, NULL);
+
+       if (net->options.timeout_read) {
+               struct timeval tv;
+               DBG_INF_FMT("setting %u as PHP_STREAM_OPTION_READ_TIMEOUT", net->options.timeout_read);
+               tv.tv_sec = net->options.timeout_read;
+               tv.tv_usec = 0;
+               php_stream_set_option(net->stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &tv);
+       }
+
+       DBG_RETURN(PASS);
+#else
+       DBG_ENTER("mysqlnd_net::enable_ssl");
+       DBG_RETURN(PASS);
+#endif
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_net::disable_ssl */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_net, disable_ssl)(MYSQLND_NET * const net TSRMLS_DC)
+{
+       DBG_ENTER("mysqlnd_net::disable_ssl");
+       DBG_RETURN(PASS);
+}
+/* }}} */
 
 
 /* {{{ mysqlnd_net::set_client_option */
 static void
 MYSQLND_METHOD(mysqlnd_net, free_contents)(MYSQLND_NET * net TSRMLS_DC)
 {
+       zend_bool pers = net->persistent;
        DBG_ENTER("mysqlnd_net::free_contents");
 
 #ifdef MYSQLND_COMPRESSION_ENABLED
@@ -670,6 +828,27 @@ MYSQLND_METHOD(mysqlnd_net, free_contents)(MYSQLND_NET * net TSRMLS_DC)
                net->uncompressed_data->free_buffer(&net->uncompressed_data TSRMLS_CC);
        }
 #endif
+       if (net->options.ssl_key) {
+               mnd_pefree(net->options.ssl_key, pers);
+               net->options.ssl_key = NULL;
+       }
+       if (net->options.ssl_cert) {
+               mnd_pefree(net->options.ssl_cert, pers);
+               net->options.ssl_cert = NULL;
+       }
+       if (net->options.ssl_ca) {
+               mnd_pefree(net->options.ssl_ca, pers);
+               net->options.ssl_ca = NULL;
+       }
+       if (net->options.ssl_capath) {
+               mnd_pefree(net->options.ssl_capath, pers);
+               net->options.ssl_capath = NULL;
+       }
+       if (net->options.ssl_cipher) {
+               mnd_pefree(net->options.ssl_cipher, pers);
+               net->options.ssl_cipher = NULL;
+       }
+
        DBG_VOID_RETURN;
 }
 /* }}} */
@@ -696,6 +875,8 @@ mysqlnd_net_init(zend_bool persistent TSRMLS_DC)
        net->m.encode = MYSQLND_METHOD(mysqlnd_net, encode);
        net->m.consume_uneaten_data = MYSQLND_METHOD(mysqlnd_net, consume_uneaten_data);
        net->m.free_contents = MYSQLND_METHOD(mysqlnd_net, free_contents);
+       net->m.enable_ssl = MYSQLND_METHOD(mysqlnd_net, enable_ssl);
+       net->m.disable_ssl = MYSQLND_METHOD(mysqlnd_net, disable_ssl);
 
        {
                unsigned int buf_size = MYSQLND_G(net_cmd_buffer_size); /* this is long, cast to unsigned int*/
index 52f27ab2920ac2f711f48de2095daa5b48d340be..6e196e0f16aaf302909fa9ce2318d14928e288ce 100644 (file)
@@ -155,13 +155,17 @@ typedef struct st_mysqlnd_options
        char            *cfg_file;
        char            *cfg_section;
 
-       /* SSL information */
-       char            *ssl_key;
-       char            *ssl_cert;
-       char            *ssl_ca;
-       char            *ssl_capath;
-       char            *ssl_cipher;
-       zend_bool       use_ssl;
+       /*
+         We need to keep these because otherwise st_mysqlnd_conn will be changed.
+         The ABI will be broken and the methods structure will be somewhere else
+         in the memory which can crash external code. Feel free to reuse these.
+       */
+       char            * unused1;
+       char            * unused2;
+       char            * unused3;
+       char            * unused4;
+       char            * unused5;
+       zend_bool       unused6;
 
        char            *charset_name;
        /* maximum allowed packet size for communication */
@@ -181,6 +185,15 @@ typedef struct st_mysqlnd_net_options
        unsigned int timeout_write;
 
        unsigned int net_read_buffer_size;
+
+       /* SSL information */
+       char            *ssl_key;
+       char            *ssl_cert;
+       char            *ssl_ca;
+       char            *ssl_capath;
+       char            *ssl_cipher;
+       char            *ssl_passphrase;
+       zend_bool       ssl_verify_peer;
 } MYSQLND_NET_OPTIONS;
 
 
@@ -250,6 +263,8 @@ typedef enum_func_status    (*func_mysqlnd_net__decode)(zend_uchar * uncompressed_d
 typedef enum_func_status       (*func_mysqlnd_net__encode)(zend_uchar * compress_buffer, size_t compress_buffer_len, const zend_uchar * const uncompressed_data, size_t uncompressed_data_len TSRMLS_DC);
 typedef size_t                         (*func_mysqlnd_net__consume_uneaten_data)(MYSQLND_NET * const net, enum php_mysqlnd_server_command cmd TSRMLS_DC);
 typedef void                           (*func_mysqlnd_net__free_contents)(MYSQLND_NET * net TSRMLS_DC);
+typedef enum_func_status       (*func_mysqlnd_net__enable_ssl)(MYSQLND_NET * const net TSRMLS_DC);
+typedef enum_func_status       (*func_mysqlnd_net__disable_ssl)(MYSQLND_NET * const net TSRMLS_DC);
 
 
 struct st_mysqlnd_net_methods
@@ -264,6 +279,8 @@ struct st_mysqlnd_net_methods
        func_mysqlnd_net__encode encode;
        func_mysqlnd_net__consume_uneaten_data consume_uneaten_data;
        func_mysqlnd_net__free_contents free_contents;
+       func_mysqlnd_net__enable_ssl enable_ssl;
+       func_mysqlnd_net__disable_ssl disable_ssl;
 };
 
 
@@ -375,6 +392,8 @@ typedef enum_func_status    (*func_mysqlnd_conn__restart_psession)(MYSQLND *conn TS
 typedef enum_func_status       (*func_mysqlnd_conn__end_psession)(MYSQLND *conn TSRMLS_DC);
 typedef enum_func_status       (*func_mysqlnd_conn__send_close)(MYSQLND * conn TSRMLS_DC);
 
+typedef void                           (*func_mysqlnd_conn__ssl_set)(MYSQLND * const conn, const char * key, const char * const cert, const char * const ca, const char * const capath, const char * const cipher TSRMLS_DC);
+
 
 struct st_mysqlnd_conn_methods
 {
@@ -443,6 +462,8 @@ struct st_mysqlnd_conn_methods
        func_mysqlnd_conn__restart_psession restart_psession;
        func_mysqlnd_conn__end_psession end_psession;
        func_mysqlnd_conn__send_close send_close;
+
+       func_mysqlnd_conn__ssl_set ssl_set;
 };
 
 
index 61036bc306ae5300d6e073a696211770d01d8be3..6145e32b3d481361b2edee03fdf7e80156027925 100644 (file)
@@ -458,31 +458,33 @@ size_t php_mysqlnd_auth_write(void *_packet, MYSQLND *conn TSRMLS_DC)
        memset(p, 0, 23); /* filler */
        p+= 23;
 
-       len= strlen(packet->user);
-       memcpy(p, packet->user, len);
-       p+= len;
-       *p++ = '\0';
-
-       /* copy scrambled pass*/
-       if (packet->password && packet->password[0]) {
-               /* In 4.1 we use CLIENT_SECURE_CONNECTION and thus the len of the buf should be passed */
-               int1store(p, 20);
-               p++;
-               php_mysqlnd_scramble((zend_uchar*)p, packet->server_scramble_buf, (zend_uchar*)packet->password);
-               p+= 20;
-       } else {
-               /* Zero length */
-               int1store(p, 0);
-               p++;
-       }
+       if (!packet->send_half_packet) {
+               len = strlen(packet->user);
+               memcpy(p, packet->user, len);
+               p+= len;
+               *p++ = '\0';
+
+               /* copy scrambled pass*/
+               if (packet->password && packet->password[0]) {
+                       /* In 4.1 we use CLIENT_SECURE_CONNECTION and thus the len of the buf should be passed */
+                       int1store(p, 20);
+                       p++;
+                       php_mysqlnd_scramble((zend_uchar*)p, packet->server_scramble_buf, (zend_uchar*)packet->password);
+                       p+= 20;
+               } else {
+                       /* Zero length */
+                       int1store(p, 0);
+                       p++;
+               }
 
-       if (packet->db) {
-               memcpy(p, packet->db, packet->db_len);
-               p+= packet->db_len;
-               *p++= '\0';
+               if (packet->db) {
+                       memcpy(p, packet->db, packet->db_len);
+                       p+= packet->db_len;
+                       *p++= '\0';
+               }
+               /* Handle CLIENT_CONNECT_WITH_DB */
+               /* no \0 for no DB */
        }
-       /* Handle CLIENT_CONNECT_WITH_DB */
-       /* no \0 for no DB */
 
        DBG_RETURN(conn->net->m.send(conn, buffer, p - buffer - MYSQLND_HEADER_SIZE TSRMLS_CC));
 }
index 82f0465df34e80a292be68a88b1d628daf639467..fe4736c0ca5cfa9442ed3c65514dc384d3c2fd51 100644 (file)
@@ -101,6 +101,7 @@ typedef struct st_mysqlnd_packet_auth {
        /* +1 for \0 because of scramble() */
        unsigned char   *server_scramble_buf;
        size_t                  db_len;
+       zend_bool               send_half_packet;
 } MYSQLND_PACKET_AUTH;
 
 /* OK packet */
index 1ad5b4e25322a2f2285971f8e49b5149c7052c54..431ee4d3ef74b9ffd1433786b683d9be5a552a35 100644 (file)
@@ -107,6 +107,12 @@ PHP_MINFO_FUNCTION(mysqlnd)
                                                                "supported");
 #else
                                                                "not supported");
+#endif
+       php_info_print_table_row(2, "SSL",
+#ifdef MYSQLND_SSL_SUPPORTED
+                                                               "supported");
+#else
+                                                               "not supported");
 #endif
        snprintf(buf, sizeof(buf), "%ld", MYSQLND_G(net_cmd_buffer_size));
        php_info_print_table_row(2, "Command buffer size", buf);
index b11709aa480d09390a40a9b331252181d8fcb748..392295eb708f9c647f646a8458ec1fe5a37467a2 100644 (file)
@@ -4433,7 +4433,9 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{
        if (!cipherlist) {
                cipherlist = "DEFAULT";
        }
-       SSL_CTX_set_cipher_list(ctx, cipherlist);
+       if (SSL_CTX_set_cipher_list(ctx, cipherlist) != 1) {
+               return NULL;
+       }
 
        GET_VER_OPT_STRING("local_cert", certfile);
        if (certfile) {
@@ -4441,6 +4443,7 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{
                EVP_PKEY *key = NULL;
                SSL *tmpssl;
                char resolved_path_buff[MAXPATHLEN];
+               const char * private_key;
 
                if (VCWD_REALPATH(certfile, resolved_path_buff)) {
                        /* a certificate to use for authentication */
@@ -4449,8 +4452,10 @@ SSL *php_SSL_new_from_context(SSL_CTX *ctx, php_stream *stream TSRMLS_DC) /* {{{
                                return NULL;
                        }
 
-                       if (SSL_CTX_use_PrivateKey_file(ctx, resolved_path_buff, SSL_FILETYPE_PEM) != 1) {
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set private key file `%s'", resolved_path_buff);
+                       GET_VER_OPT_STRING("local_pk", private_key);
+
+                       if (private_key && SSL_CTX_use_PrivateKey_file(ctx, private_key, SSL_FILETYPE_PEM) != 1) {
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to set private key file `%s'", private_key);
                                return NULL;
                        }