From: Andrey Hristov Date: Thu, 5 Nov 2015 14:26:33 +0000 (+0100) Subject: MNDR: X-Git-Tag: php-7.1.0alpha1~773 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b8b1d45c3c9b5ceba2e3a12108c84e122e2e20b1;p=php MNDR: - move connection establishment code to own command - COM_HANDSHAKE --- diff --git a/ext/mysqlnd/mysqlnd.c b/ext/mysqlnd/mysqlnd.c index a8394ab2d2..80ca681ea0 100644 --- a/ext/mysqlnd/mysqlnd.c +++ b/ext/mysqlnd/mysqlnd.c @@ -305,9 +305,9 @@ MYSQLND_METHOD(mysqlnd_conn_data, free_contents)(MYSQLND_CONN_DATA * conn) mnd_pefree(conn->host_info, pers); conn->host_info = NULL; } - if (conn->auth_plugin_data) { - mnd_pefree(conn->auth_plugin_data, pers); - conn->auth_plugin_data = NULL; + if (conn->authentication_plugin_data.s) { + mnd_pefree(conn->authentication_plugin_data.s, pers); + conn->authentication_plugin_data.s = NULL; } if (conn->last_message.s) { mnd_pefree(conn->last_message.s, pers); @@ -408,24 +408,21 @@ MYSQLND_METHOD(mysqlnd_conn_data, end_psession)(MYSQLND_CONN_DATA * conn) static enum_func_status mysqlnd_switch_to_ssl_if_needed( MYSQLND_CONN_DATA * conn, - const MYSQLND_PACKET_GREET * const greet_packet, + unsigned int charset_no, + size_t server_capabilities, const MYSQLND_SESSION_OPTIONS * const session_options, zend_ulong mysql_flags) { enum_func_status ret = FAIL; const MYSQLND_CHARSET * charset; - unsigned int charset_no; DBG_ENTER("mysqlnd_switch_to_ssl_if_needed"); if (session_options->charset_name && (charset = mysqlnd_find_charset_name(session_options->charset_name))) { charset_no = charset->nr; - } else { - charset_no = greet_packet->charset_no; } { size_t client_capabilities = mysql_flags; - size_t server_capabilities = greet_packet->server_capabilities; struct st_mysqlnd_protocol_command * command = conn->command_factory(COM_ENABLE_SSL, conn, client_capabilities, server_capabilities, charset_no); if (command) { ret = command->run(command); @@ -464,8 +461,7 @@ mysqlnd_run_authentication( const size_t passwd_len, const char * const db, const size_t db_len, - const zend_uchar * const auth_plugin_data, - const size_t auth_plugin_data_len, + const MYSQLND_STRING auth_plugin_data, const char * const auth_protocol, unsigned int charset_no, const MYSQLND_SESSION_OPTIONS * const session_options, @@ -485,12 +481,12 @@ mysqlnd_run_authentication( DBG_ENTER("mysqlnd_run_authentication"); - plugin_data_len = auth_plugin_data_len; + plugin_data_len = auth_plugin_data.l; plugin_data = mnd_emalloc(plugin_data_len + 1); if (!plugin_data) { goto end; } - memcpy(plugin_data, auth_plugin_data, plugin_data_len); + memcpy(plugin_data, auth_plugin_data.s, plugin_data_len); plugin_data[plugin_data_len] = '\0'; requested_protocol = mnd_pestrdup(auth_protocol? auth_protocol : MYSQLND_DEFAULT_AUTH_PROTOCOL, FALSE); @@ -517,17 +513,17 @@ mysqlnd_run_authentication( switch_to_auth_protocol = NULL; switch_to_auth_protocol_len = 0; - if (conn->auth_plugin_data) { - mnd_pefree(conn->auth_plugin_data, conn->persistent); - conn->auth_plugin_data = NULL; + if (conn->authentication_plugin_data.s) { + mnd_pefree(conn->authentication_plugin_data.s, conn->persistent); + conn->authentication_plugin_data.s = NULL; } - conn->auth_plugin_data_len = plugin_data_len; - conn->auth_plugin_data = mnd_pemalloc(conn->auth_plugin_data_len, conn->persistent); - if (!conn->auth_plugin_data) { + conn->authentication_plugin_data.l = plugin_data_len; + conn->authentication_plugin_data.s = mnd_pemalloc(conn->authentication_plugin_data.l, conn->persistent); + if (!conn->authentication_plugin_data.s) { SET_OOM_ERROR(conn->error_info); goto end; } - memcpy(conn->auth_plugin_data, plugin_data, plugin_data_len); + memcpy(conn->authentication_plugin_data.s, plugin_data, plugin_data_len); DBG_INF_FMT("salt(%d)=[%.*s]", plugin_data_len, plugin_data_len, plugin_data); /* The data should be allocated with malloc() */ @@ -592,7 +588,7 @@ end: /* {{{ mysqlnd_connect_run_authentication */ -static enum_func_status +enum_func_status mysqlnd_connect_run_authentication( MYSQLND_CONN_DATA * conn, const char * const user, @@ -600,7 +596,10 @@ mysqlnd_connect_run_authentication( const char * const db, size_t db_len, size_t passwd_len, - const MYSQLND_PACKET_GREET * const greet_packet, + MYSQLND_STRING authentication_plugin_data, + const char * const authentication_protocol, + const unsigned int charset_no, + size_t server_capabilities, const MYSQLND_SESSION_OPTIONS * const session_options, zend_ulong mysql_flags ) @@ -608,11 +607,11 @@ mysqlnd_connect_run_authentication( enum_func_status ret = FAIL; DBG_ENTER("mysqlnd_connect_run_authentication"); - ret = mysqlnd_switch_to_ssl_if_needed(conn, greet_packet, session_options, mysql_flags); + ret = mysqlnd_switch_to_ssl_if_needed(conn, charset_no, server_capabilities, session_options, mysql_flags); if (PASS == ret) { ret = mysqlnd_run_authentication(conn, user, passwd, passwd_len, db, db_len, - greet_packet->auth_plugin_data, greet_packet->auth_plugin_data_len, greet_packet->auth_protocol, - greet_packet->charset_no, session_options, mysql_flags, FALSE /*silent*/, FALSE/*is_change*/); + authentication_plugin_data, authentication_protocol, + charset_no, session_options, mysql_flags, FALSE /*silent*/, FALSE/*is_change*/); } DBG_RETURN(ret); } @@ -696,77 +695,25 @@ MYSQLND_METHOD(mysqlnd_conn_data, get_updated_connect_flags)(MYSQLND_CONN_DATA * /* {{{ mysqlnd_conn_data::connect_handshake */ static enum_func_status MYSQLND_METHOD(mysqlnd_conn_data, connect_handshake)(MYSQLND_CONN_DATA * conn, - const char * const host, const char * const user, - const char * const passwd, const unsigned int passwd_len, - const char * const db, const unsigned int db_len, + const MYSQLND_CSTRING * const username, + const MYSQLND_CSTRING * const password, + const MYSQLND_CSTRING * const database, const unsigned int mysql_flags) { - MYSQLND_PACKET_GREET * greet_packet; - MYSQLND_NET * net = conn->net; - + enum_func_status ret = FAIL; + size_t client_flags = mysql_flags; DBG_ENTER("mysqlnd_conn_data::connect_handshake"); - greet_packet = conn->payload_decoder_factory->m.get_greet_packet(conn->payload_decoder_factory, FALSE); - if (!greet_packet) { - SET_OOM_ERROR(conn->error_info); - DBG_RETURN(FAIL); /* OOM */ - } - - if (FAIL == net->data->m.connect_ex(conn->net, conn->scheme, conn->persistent, - conn->stats, conn->error_info)) - { - goto err; - } - - DBG_INF_FMT("stream=%p", net->data->m.get_stream(net)); - - if (FAIL == PACKET_READ(greet_packet)) { - DBG_ERR("Error while reading greeting packet"); - php_error_docref(NULL, E_WARNING, "Error while reading greeting packet. PID=%d", getpid()); - goto err; - } else if (greet_packet->error_no) { - DBG_ERR_FMT("errorno=%u error=%s", greet_packet->error_no, greet_packet->error); - SET_CLIENT_ERROR(conn->error_info, greet_packet->error_no, greet_packet->sqlstate, greet_packet->error); - goto err; - } else if (greet_packet->pre41) { - DBG_ERR_FMT("Connecting to 3.22, 3.23 & 4.0 is not supported. Server is %-.32s", greet_packet->server_version); - php_error_docref(NULL, E_WARNING, "Connecting to 3.22, 3.23 & 4.0 " - " is not supported. Server is %-.32s", greet_packet->server_version); - SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, - "Connecting to 3.22, 3.23 & 4.0 servers is not supported"); - goto err; - } - - conn->thread_id = greet_packet->thread_id; - conn->protocol_version = greet_packet->protocol_version; - conn->server_version = mnd_pestrdup(greet_packet->server_version, conn->persistent); - - conn->greet_charset = mysqlnd_find_charset_nr(greet_packet->charset_no); - if (!conn->greet_charset) { - php_error_docref(NULL, E_WARNING, - "Server sent charset (%d) unknown to the client. Please, report to the developers", greet_packet->charset_no); - SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, - "Server sent charset unknown to the client. Please, report to the developers"); - goto err; - } - - conn->server_capabilities = greet_packet->server_capabilities; - - if (FAIL == mysqlnd_connect_run_authentication(conn, user, passwd, db, db_len, (size_t) passwd_len, - greet_packet, conn->options, mysql_flags)) - { - goto err; + if (FAIL == conn->net->data->m.connect_ex(conn->net, conn->scheme, conn->persistent, conn->stats, conn->error_info)) { + DBG_RETURN(FAIL); + } else { + struct st_mysqlnd_protocol_command * command = conn->command_factory(COM_HANDSHAKE, conn, username, password, database, client_flags); + if (command) { + ret = command->run(command); + command->free_command(command); + } } - - UPSERT_STATUS_RESET(conn->upsert_status); - UPSERT_STATUS_SET_SERVER_STATUS(conn->upsert_status, greet_packet->server_status); - - PACKET_FREE(greet_packet); - DBG_RETURN(PASS); -err: - conn->server_capabilities = 0; - PACKET_FREE(greet_packet); - DBG_RETURN(FAIL); + DBG_RETURN(ret); } /* }}} */ @@ -774,16 +721,16 @@ err: /* {{{ mysqlnd_conn_data::connect */ static enum_func_status MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, - const char *host, const char *user, - const char *passwd, unsigned int passwd_len, - const char *db, unsigned int db_len, - unsigned int port, - const char *socket_or_pipe, - unsigned int mysql_flags - ) + MYSQLND_CSTRING hostname, + MYSQLND_CSTRING username, + MYSQLND_CSTRING password, + MYSQLND_CSTRING database, + unsigned int port, + MYSQLND_CSTRING socket_or_pipe, + unsigned int mysql_flags + ) { const size_t this_func = STRUCT_OFFSET(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_conn_data), connect); - size_t host_len; zend_bool unix_socket = FALSE; zend_bool named_pipe = FALSE; zend_bool reconnect = FALSE; @@ -803,7 +750,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); DBG_INF_FMT("host=%s user=%s db=%s port=%u flags=%u persistent=%u state=%u", - host?host:"", user?user:"", db?db:"", port, mysql_flags, + hostname.s?hostname.s:"", username.s?username.s:"", database.s?database.s:"", port, mysql_flags, conn? conn->persistent:0, conn? GET_CONNECTION_STATE(&conn->state):-1); if (GET_CONNECTION_STATE(&conn->state) > CONN_ALLOCED && GET_CONNECTION_STATE(&conn->state) ) { @@ -838,52 +785,55 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, conn->m->set_client_option(conn, MYSQLND_OPT_MAX_ALLOWED_PACKET, (char *)&max_allowed_size); } - if (!host || !host[0]) { - host = "localhost"; + if (!hostname.s || !hostname.s[0]) { + hostname.s = "localhost"; + hostname.l = strlen(hostname.s); } - if (!user) { + if (!username.s) { DBG_INF_FMT("no user given, using empty string"); - user = ""; + username.s = ""; + username.l = 0; } - if (!passwd) { + if (!password.s) { DBG_INF_FMT("no password given, using empty string"); - passwd = ""; - passwd_len = 0; + password.s = ""; + password.l = 0; } - if (!db) { + if (!database.s) { DBG_INF_FMT("no db given, using empty string"); - db = ""; - db_len = 0; + database.s = ""; + database.l = 0; } else { mysql_flags |= CLIENT_CONNECT_WITH_DB; } - host_len = strlen(host); { char * transport = NULL; int transport_len; #ifndef PHP_WIN32 - if (host_len == sizeof("localhost") - 1 && !strncasecmp(host, "localhost", host_len)) { - DBG_INF_FMT("socket=%s", socket_or_pipe? socket_or_pipe:"n/a"); - if (!socket_or_pipe) { - socket_or_pipe = "/tmp/mysql.sock"; + if (hostname.l == sizeof("localhost") - 1 && !strncasecmp(hostname.s, "localhost", hostname.l)) { + DBG_INF_FMT("socket=%s", socket_or_pipe.s? socket_or_pipe.s:"n/a"); + if (!socket_or_pipe.s) { + socket_or_pipe.s = "/tmp/mysql.sock"; + socket_or_pipe.l = strlen(socket_or_pipe.s); } - transport_len = mnd_sprintf(&transport, 0, "unix://%s", socket_or_pipe); + transport_len = mnd_sprintf(&transport, 0, "unix://%s", socket_or_pipe.s); unix_socket = TRUE; #else - if (host_len == sizeof(".") - 1 && host[0] == '.') { + if (hostname.l == sizeof(".") - 1 && hostname.s[0] == '.') { /* named pipe in socket */ - if (!socket_or_pipe) { - socket_or_pipe = "\\\\.\\pipe\\MySQL"; + if (!socket_or_pipe.s) { + socket_or_pipe.s = "\\\\.\\pipe\\MySQL"; + socket_or_pipe.l = strlen(socket_or_pipe.s); } - transport_len = mnd_sprintf(&transport, 0, "pipe://%s", socket_or_pipe); + transport_len = mnd_sprintf(&transport, 0, "pipe://%s", socket_or_pipe.s); named_pipe = TRUE; #endif } else { if (!port) { port = 3306; } - transport_len = mnd_sprintf(&transport, 0, "tcp://%s:%u", host, port); + transport_len = mnd_sprintf(&transport, 0, "tcp://%s:%u", hostname.s, port); } if (!transport) { SET_OOM_ERROR(conn->error_info); @@ -901,8 +851,11 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, mysql_flags = conn->m->get_updated_connect_flags(conn, mysql_flags); - if (FAIL == conn->m->connect_handshake(conn, host, user, passwd, passwd_len, db, db_len, mysql_flags)) { - goto err; + { + + if (FAIL == conn->m->connect_handshake(conn, &username, &password, &database, mysql_flags)) { + goto err; + } } { @@ -918,13 +871,13 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, */ net->data->compressed = mysql_flags & CLIENT_COMPRESS? TRUE:FALSE; - conn->user_len = strlen(user); - conn->user = mnd_pestrndup(user, conn->user_len, conn->persistent); - conn->passwd = mnd_pestrndup(passwd, passwd_len, conn->persistent); - conn->passwd_len = passwd_len; + conn->user_len = username.l; + conn->user = mnd_pestrndup(username.s, conn->user_len, conn->persistent); + conn->passwd = mnd_pestrndup(password.s, password.l, conn->persistent); + conn->passwd_len = password.l; conn->port = port; - conn->connect_or_select_db.s = mnd_pestrndup(db, db_len, conn->persistent); - conn->connect_or_select_db.l = db_len; + conn->connect_or_select_db.s = mnd_pestrndup(database.s, database.l, conn->persistent); + conn->connect_or_select_db.l = database.l; if (!conn->user || !conn->passwd || !conn->connect_or_select_db.s) { SET_OOM_ERROR(conn->error_info); @@ -932,12 +885,12 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, } if (!unix_socket && !named_pipe) { - conn->host = mnd_pestrndup(host, host_len, conn->persistent); + conn->host = mnd_pestrndup(hostname.s, hostname.l, conn->persistent); if (!conn->host) { SET_OOM_ERROR(conn->error_info); goto err; /* OOM */ } - conn->host_len = host_len; + conn->host_len = hostname.l; { char *p; mnd_sprintf(&p, 0, "%s via TCP/IP", conn->host); @@ -953,7 +906,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, } } } else { - conn->unix_socket = mnd_pestrdup(socket_or_pipe, conn->persistent); + conn->unix_socket = mnd_pestrdup(socket_or_pipe.s, conn->persistent); if (unix_socket) { conn->host_info = mnd_pestrdup("Localhost via UNIX socket", conn->persistent); } else if (named_pipe) { @@ -1024,12 +977,13 @@ err: /* {{{ mysqlnd_conn::connect */ static enum_func_status MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn_handle, - const char * host, const char * user, - const char * passwd, unsigned int passwd_len, - const char * db, unsigned int db_len, - unsigned int port, - const char * socket_or_pipe, - unsigned int mysql_flags + const MYSQLND_CSTRING hostname, + const MYSQLND_CSTRING username, + const MYSQLND_CSTRING password, + const MYSQLND_CSTRING database, + unsigned int port, + const MYSQLND_CSTRING socket_or_pipe, + unsigned int mysql_flags ) { const size_t this_func = STRUCT_OFFSET(MYSQLND_CLASS_METHODS_TYPE(mysqlnd_conn_data), connect); @@ -1040,7 +994,7 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn_handle, if (PASS == conn->m->local_tx_start(conn, this_func)) { mysqlnd_options4(conn_handle, MYSQL_OPT_CONNECT_ATTR_ADD, "_client_name", "mysqlnd"); - ret = conn->m->connect(conn, host, user, passwd, passwd_len, db, db_len, port, socket_or_pipe, mysql_flags); + ret = conn->m->connect(conn, hostname, username, password, database, port, socket_or_pipe, mysql_flags); conn->m->local_tx_end(conn, this_func, FAIL); } @@ -1051,20 +1005,26 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn_handle, /* {{{ mysqlnd_connect */ PHPAPI MYSQLND * mysqlnd_connection_connect(MYSQLND * conn_handle, - const char * host, const char * user, - const char * passwd, unsigned int passwd_len, - const char * db, unsigned int db_len, + const char * const host, + const char * const user, + const char * const passwd, unsigned int passwd_len, + const char * const db, unsigned int db_len, unsigned int port, - const char * socket_or_pipe, + const char * const sock_or_pipe, unsigned int mysql_flags, unsigned int client_api_flags ) { enum_func_status ret = FAIL; zend_bool self_alloced = FALSE; + MYSQLND_CSTRING hostname = { host, host? strlen(host) : 0 }; + MYSQLND_CSTRING username = { user, user? strlen(user) : 0 }; + MYSQLND_CSTRING password = { passwd, passwd_len }; + MYSQLND_CSTRING database = { db, db_len }; + MYSQLND_CSTRING socket_or_pipe = { sock_or_pipe, sock_or_pipe? strlen(sock_or_pipe) : 0 }; DBG_ENTER("mysqlnd_connect"); - DBG_INF_FMT("host=%s user=%s db=%s port=%u flags=%u", host?host:"", user?user:"", db?db:"", port, mysql_flags); + DBG_INF_FMT("host=%s user=%s db=%s port=%u flags=%u", host? host:"", user? user:"", db? db:"", port, mysql_flags); if (!conn_handle) { self_alloced = TRUE; @@ -1074,7 +1034,7 @@ PHPAPI MYSQLND * mysqlnd_connection_connect(MYSQLND * conn_handle, } } - ret = conn_handle->m->connect(conn_handle, host, user, passwd, passwd_len, db, db_len, port, socket_or_pipe, mysql_flags); + ret = conn_handle->m->connect(conn_handle, hostname, username, password, database, port, socket_or_pipe, mysql_flags); if (ret == FAIL) { if (self_alloced) { @@ -2087,7 +2047,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, change_user)(MYSQLND_CONN_DATA * const conn, /* XXX: passwords that have \0 inside work during auth, but in this case won't work with change user */ ret = mysqlnd_run_authentication(conn, user, passwd, passwd_len, db, strlen(db), - conn->auth_plugin_data, conn->auth_plugin_data_len, conn->options->auth_protocol, + conn->authentication_plugin_data, conn->options->auth_protocol, 0 /*charset not used*/, conn->options, conn->server_capabilities, silent, TRUE/*is_change*/); /* diff --git a/ext/mysqlnd/mysqlnd.h b/ext/mysqlnd/mysqlnd.h index d49f765108..f683562811 100644 --- a/ext/mysqlnd/mysqlnd.h +++ b/ext/mysqlnd/mysqlnd.h @@ -89,11 +89,12 @@ PHPAPI const MYSQLND_CHARSET * mysqlnd_find_charset_name(const char * const char PHPAPI MYSQLND * mysqlnd_connection_init(unsigned int client_flags, zend_bool persistent, struct st_mysqlnd_object_factory_methods * object_factory); PHPAPI MYSQLND * mysqlnd_connection_connect(MYSQLND * conn, - const char * host, const char * user, - const char * passwd, unsigned int passwd_len, - const char * db, unsigned int db_len, + const char * const host, + const char * const user, + const char * const passwd, unsigned int passwd_len, + const char * const db, unsigned int db_len, unsigned int port, - const char * socket_or_pipe, + const char * const socket_or_pipe, unsigned int mysql_flags, unsigned int client_api_flags ); diff --git a/ext/mysqlnd/mysqlnd_enum_n_def.h b/ext/mysqlnd/mysqlnd_enum_n_def.h index ad64fc1a41..f48ae1d968 100644 --- a/ext/mysqlnd/mysqlnd_enum_n_def.h +++ b/ext/mysqlnd/mysqlnd_enum_n_def.h @@ -640,8 +640,9 @@ enum php_mysqlnd_server_command COM_STMT_EXECUTE_BATCH = 32, COM_END, /* Here follow own, non-protocol, commands */ - COM_REAP_RESULT=240, /* own command */ - COM_ENABLE_SSL, + COM_REAP_RESULT=240, /* own command */ + COM_ENABLE_SSL, /* own command */ + COM_HANDSHAKE, /* own command */ }; diff --git a/ext/mysqlnd/mysqlnd_priv.h b/ext/mysqlnd/mysqlnd_priv.h index e737d9cac5..a0a061f4ee 100644 --- a/ext/mysqlnd/mysqlnd_priv.h +++ b/ext/mysqlnd/mysqlnd_priv.h @@ -232,6 +232,23 @@ send_command_handle_response( MYSQLND_STRING * last_message, zend_bool last_message_persistent ); + +enum_func_status +mysqlnd_connect_run_authentication( + MYSQLND_CONN_DATA * conn, + const char * const user, + const char * const passwd, + const char * const db, + size_t db_len, + size_t passwd_len, + MYSQLND_STRING authentication_plugin_data, + const char * const authentication_protocol, + const unsigned int charset_no, + size_t server_capabilities, + const MYSQLND_SESSION_OPTIONS * const session_options, + zend_ulong mysql_flags + ); + #endif /* MYSQLND_PRIV_H */ diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index 27d2d0e5e7..61a6fdfae1 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -460,7 +460,7 @@ MYSQLND_CLASS_METHODS_TYPE(mysqlnd_object_factory) }; -typedef enum_func_status (*func_mysqlnd_conn_data__connect)(MYSQLND_CONN_DATA * conn, const char * host, const char * user, const char * passwd, unsigned int passwd_len, const char * db, unsigned int db_len, unsigned int port, const char * socket_or_pipe, unsigned int mysql_flags); +typedef enum_func_status (*func_mysqlnd_conn_data__connect)(MYSQLND_CONN_DATA * conn, MYSQLND_CSTRING hostname, MYSQLND_CSTRING username, MYSQLND_CSTRING password, MYSQLND_CSTRING database, unsigned int port, MYSQLND_CSTRING socket_or_pipe, unsigned int mysql_flags); typedef zend_ulong (*func_mysqlnd_conn_data__escape_string)(MYSQLND_CONN_DATA * const conn, char *newstr, const char *escapestr, size_t escapestr_len); typedef enum_func_status (*func_mysqlnd_conn_data__set_charset)(MYSQLND_CONN_DATA * const conn, const char * const charset); typedef enum_func_status (*func_mysqlnd_conn_data__query)(MYSQLND_CONN_DATA * conn, const char * query, unsigned int query_len); @@ -539,7 +539,7 @@ typedef enum_func_status (*func_mysqlnd_conn_data__local_tx_start)(MYSQLND_CONN_ typedef enum_func_status (*func_mysqlnd_conn_data__local_tx_end)(MYSQLND_CONN_DATA * conn, size_t this_func, enum_func_status status); typedef enum_func_status (*func_mysqlnd_conn_data__execute_init_commands)(MYSQLND_CONN_DATA * conn); typedef unsigned int (*func_mysqlnd_conn_data__get_updated_connect_flags)(MYSQLND_CONN_DATA * conn, unsigned int mysql_flags); -typedef enum_func_status (*func_mysqlnd_conn_data__connect_handshake)(MYSQLND_CONN_DATA * conn, const char * const host, const char * const user, const char * const passwd, const unsigned int passwd_len, const char * const db, const unsigned int db_len, const unsigned int mysql_flags); +typedef enum_func_status (*func_mysqlnd_conn_data__connect_handshake)(MYSQLND_CONN_DATA * conn, const MYSQLND_CSTRING * const username, const MYSQLND_CSTRING * const password, const MYSQLND_CSTRING * const database, const unsigned int mysql_flags); typedef struct st_mysqlnd_authentication_plugin * (*func_mysqlnd_conn_data__fetch_auth_plugin_by_name)(const char * const requested_protocol); typedef enum_func_status (*func_mysqlnd_conn_data__set_client_option_2d)(MYSQLND_CONN_DATA * const conn, enum_mysqlnd_client_option option, const char * const key, const char * const value); @@ -640,7 +640,7 @@ MYSQLND_CLASS_METHODS_TYPE(mysqlnd_conn_data) }; -typedef enum_func_status (*func_mysqlnd_data__connect)(MYSQLND * conn, const char * host, const char * user, const char * passwd, unsigned int passwd_len, const char * db, unsigned int db_len, unsigned int port, const char * socket_or_pipe, unsigned int mysql_flags); +typedef enum_func_status (*func_mysqlnd_data__connect)(MYSQLND * conn, const MYSQLND_CSTRING hostname, const MYSQLND_CSTRING username, const MYSQLND_CSTRING password, const MYSQLND_CSTRING database, unsigned int port, const MYSQLND_CSTRING socket_or_pipe, unsigned int mysql_flags); typedef MYSQLND * (*func_mysqlnd_conn__clone_object)(MYSQLND * const conn); typedef void (*func_mysqlnd_conn__dtor)(MYSQLND * conn); typedef enum_func_status (*func_mysqlnd_conn__close)(MYSQLND * conn, enum_connection_close_type close_type); @@ -982,8 +982,7 @@ struct st_mysqlnd_connection_data uint64_t thread_id; char *server_version; char *host_info; - zend_uchar *auth_plugin_data; - size_t auth_plugin_data_len; + MYSQLND_STRING authentication_plugin_data; const MYSQLND_CHARSET *charset; const MYSQLND_CHARSET *greet_charset; MYSQLND_STRING connect_or_select_db; diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c index 5f7838d983..c6b53e4323 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.c +++ b/ext/mysqlnd/mysqlnd_wireprotocol.c @@ -347,8 +347,8 @@ php_mysqlnd_greet_read(void * _packet) } BAIL_IF_NO_MORE_DATA; - packet->auth_plugin_data = packet->intern_auth_plugin_data; - packet->auth_plugin_data_len = sizeof(packet->intern_auth_plugin_data); + packet->authentication_plugin_data.s = packet->intern_auth_plugin_data; + packet->authentication_plugin_data.l = sizeof(packet->intern_auth_plugin_data); if (packet->header.size < sizeof(buf)) { /* @@ -386,7 +386,7 @@ php_mysqlnd_greet_read(void * _packet) p+=4; BAIL_IF_NO_MORE_DATA; - memcpy(packet->auth_plugin_data, p, SCRAMBLE_LENGTH_323); + memcpy(packet->authentication_plugin_data.s, p, SCRAMBLE_LENGTH_323); p+= SCRAMBLE_LENGTH_323; BAIL_IF_NO_MORE_DATA; @@ -413,7 +413,7 @@ php_mysqlnd_greet_read(void * _packet) if ((size_t) (p - buf) < packet->header.size) { /* auth_plugin_data is split into two parts */ - memcpy(packet->auth_plugin_data + SCRAMBLE_LENGTH_323, p, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323); + memcpy(packet->authentication_plugin_data.s + SCRAMBLE_LENGTH_323, p, SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323); p+= SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323; p++; /* 0x0 at the end of the scramble and thus last byte in the packet in 5.1 and previous */ } else { @@ -428,19 +428,19 @@ php_mysqlnd_greet_read(void * _packet) /* Additional 16 bits for server capabilities */ packet->server_capabilities |= uint2korr(pad_start) << 16; /* And a length of the server scramble in one byte */ - packet->auth_plugin_data_len = uint1korr(pad_start + 2); - if (packet->auth_plugin_data_len > SCRAMBLE_LENGTH) { + packet->authentication_plugin_data.l = uint1korr(pad_start + 2); + if (packet->authentication_plugin_data.l > SCRAMBLE_LENGTH) { /* more data*/ - zend_uchar * new_auth_plugin_data = emalloc(packet->auth_plugin_data_len); + char * new_auth_plugin_data = emalloc(packet->authentication_plugin_data.l); if (!new_auth_plugin_data) { goto premature_end; } /* copy what we already have */ - memcpy(new_auth_plugin_data, packet->auth_plugin_data, SCRAMBLE_LENGTH); + memcpy(new_auth_plugin_data, packet->authentication_plugin_data.s, SCRAMBLE_LENGTH); /* add additional scramble data 5.5+ sent us */ - memcpy(new_auth_plugin_data + SCRAMBLE_LENGTH, p, packet->auth_plugin_data_len - SCRAMBLE_LENGTH); - p+= (packet->auth_plugin_data_len - SCRAMBLE_LENGTH); - packet->auth_plugin_data = new_auth_plugin_data; + memcpy(new_auth_plugin_data + SCRAMBLE_LENGTH, p, packet->authentication_plugin_data.l - SCRAMBLE_LENGTH); + p+= (packet->authentication_plugin_data.l - SCRAMBLE_LENGTH); + packet->authentication_plugin_data.s = new_auth_plugin_data; } } @@ -456,7 +456,7 @@ php_mysqlnd_greet_read(void * _packet) DBG_INF_FMT("server_capabilities=%u charset_no=%u server_status=%i auth_protocol=%s scramble_length=%u", packet->server_capabilities, packet->charset_no, packet->server_status, - packet->auth_protocol? packet->auth_protocol:"n/a", packet->auth_plugin_data_len); + packet->auth_protocol? packet->auth_protocol:"n/a", packet->authentication_plugin_data.l); DBG_RETURN(PASS); premature_end: @@ -477,9 +477,9 @@ void php_mysqlnd_greet_free_mem(void * _packet, zend_bool stack_allocation) efree(p->server_version); p->server_version = NULL; } - if (p->auth_plugin_data && p->auth_plugin_data != p->intern_auth_plugin_data) { - efree(p->auth_plugin_data); - p->auth_plugin_data = NULL; + if (p->authentication_plugin_data.s && p->authentication_plugin_data.s != p->intern_auth_plugin_data) { + efree(p->authentication_plugin_data.s); + p->authentication_plugin_data.s = NULL; } if (p->auth_protocol) { efree(p->auth_protocol); @@ -2782,7 +2782,7 @@ send_command( cmd_packet->command = command; if (arg && arg_len) { - cmd_packet->argument.s = arg; + cmd_packet->argument.s = (char *) arg; cmd_packet->argument.l = arg_len; } @@ -4171,6 +4171,125 @@ mysqlnd_com_enable_ssl_create_command(va_list args) } /* }}} */ +/************************** COM_READ_HANDSHAKE ******************************************/ +struct st_mysqlnd_protocol_com_handshake_command +{ + struct st_mysqlnd_protocol_command parent; + struct st_mysqlnd_com_handshake_context + { + MYSQLND_CONN_DATA * conn; + MYSQLND_CSTRING user; + MYSQLND_CSTRING passwd; + MYSQLND_CSTRING database; + size_t client_flags; + } context; +}; + + +/* {{{ mysqlnd_com_handshake_run */ +static enum_func_status +mysqlnd_com_handshake_run(void *cmd) +{ + struct st_mysqlnd_protocol_com_handshake_command * command = (struct st_mysqlnd_protocol_com_handshake_command *) cmd; + const char * user = command->context.user.s; + + const char * passwd = command->context.passwd.s; + size_t passwd_len = command->context.passwd.l; + + const char * db = command->context.database.s; + size_t db_len = command->context.database.l; + + size_t mysql_flags = command->context.client_flags; + + MYSQLND_CONN_DATA * conn = command->context.conn; + MYSQLND_PACKET_GREET * greet_packet; + + DBG_ENTER("mysqlnd_conn_data::connect_handshake"); + DBG_INF_FMT("stream=%p", conn->net->data->m.get_stream(conn->net)); + DBG_INF_FMT("[user=%s] [db=%s:%d] [flags=%llu]", user, db, db_len, mysql_flags); + + greet_packet = conn->payload_decoder_factory->m.get_greet_packet(conn->payload_decoder_factory, FALSE); + if (!greet_packet) { + SET_OOM_ERROR(conn->error_info); + DBG_RETURN(FAIL); /* OOM */ + } + + if (FAIL == PACKET_READ(greet_packet)) { + DBG_ERR("Error while reading greeting packet"); + php_error_docref(NULL, E_WARNING, "Error while reading greeting packet. PID=%d", getpid()); + goto err; + } else if (greet_packet->error_no) { + DBG_ERR_FMT("errorno=%u error=%s", greet_packet->error_no, greet_packet->error); + SET_CLIENT_ERROR(conn->error_info, greet_packet->error_no, greet_packet->sqlstate, greet_packet->error); + goto err; + } else if (greet_packet->pre41) { + DBG_ERR_FMT("Connecting to 3.22, 3.23 & 4.0 is not supported. Server is %-.32s", greet_packet->server_version); + php_error_docref(NULL, E_WARNING, "Connecting to 3.22, 3.23 & 4.0 " + " is not supported. Server is %-.32s", greet_packet->server_version); + SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, + "Connecting to 3.22, 3.23 & 4.0 servers is not supported"); + goto err; + } + + conn->thread_id = greet_packet->thread_id; + conn->protocol_version = greet_packet->protocol_version; + conn->server_version = mnd_pestrdup(greet_packet->server_version, conn->persistent); + + conn->greet_charset = mysqlnd_find_charset_nr(greet_packet->charset_no); + if (!conn->greet_charset) { + php_error_docref(NULL, E_WARNING, + "Server sent charset (%d) unknown to the client. Please, report to the developers", greet_packet->charset_no); + SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, + "Server sent charset unknown to the client. Please, report to the developers"); + goto err; + } + + conn->server_capabilities = greet_packet->server_capabilities; + + if (FAIL == mysqlnd_connect_run_authentication(conn, user, passwd, db, db_len, (size_t) passwd_len, + greet_packet->authentication_plugin_data, greet_packet->auth_protocol, + greet_packet->charset_no, greet_packet->server_capabilities, + conn->options, mysql_flags)) + { + goto err; + } + + UPSERT_STATUS_RESET(conn->upsert_status); + UPSERT_STATUS_SET_SERVER_STATUS(conn->upsert_status, greet_packet->server_status); + + PACKET_FREE(greet_packet); + DBG_RETURN(PASS); +err: + conn->server_capabilities = 0; + PACKET_FREE(greet_packet); + DBG_RETURN(FAIL); +} +/* }}} */ + + +/* {{{ mysqlnd_com_handshake_create_command */ +static struct st_mysqlnd_protocol_command * +mysqlnd_com_handshake_create_command(va_list args) +{ + struct st_mysqlnd_protocol_com_handshake_command * command; + DBG_ENTER("mysqlnd_com_handshake_create_command"); + command = mnd_ecalloc(1, sizeof(struct st_mysqlnd_protocol_com_handshake_command)); + if (command) { + command->context.conn = va_arg(args, MYSQLND_CONN_DATA *); + command->context.user = *va_arg(args, const MYSQLND_CSTRING *); + command->context.passwd = *va_arg(args, const MYSQLND_CSTRING *); + command->context.database = *va_arg(args, const MYSQLND_CSTRING *); + command->context.client_flags = va_arg(args, size_t); + + command->parent.free_command = mysqlnd_com_no_params_free_command; + command->parent.run = mysqlnd_com_handshake_run; + } + + DBG_RETURN((struct st_mysqlnd_protocol_command *) command); +} +/* }}} */ + + /* {{{ mysqlnd_get_command */ static struct st_mysqlnd_protocol_command * @@ -4239,6 +4358,9 @@ mysqlnd_get_command(enum php_mysqlnd_server_command command, ...) case COM_ENABLE_SSL: ret = mysqlnd_com_enable_ssl_create_command(args); break; + case COM_HANDSHAKE: + ret = mysqlnd_com_handshake_create_command(args); + break; default: break; } diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.h b/ext/mysqlnd/mysqlnd_wireprotocol.h index cace621d3f..58ef62c645 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.h +++ b/ext/mysqlnd/mysqlnd_wireprotocol.h @@ -78,9 +78,8 @@ typedef struct st_mysqlnd_packet_greet { uint8_t protocol_version; char *server_version; uint32_t thread_id; - zend_uchar intern_auth_plugin_data[SCRAMBLE_LENGTH]; - zend_uchar * auth_plugin_data; - size_t auth_plugin_data_len; + char intern_auth_plugin_data[SCRAMBLE_LENGTH]; + MYSQLND_STRING authentication_plugin_data; /* 1 byte pad */ uint32_t server_capabilities; uint8_t charset_no;