]> granicus.if.org Git - php/commitdiff
Handle MySQL 5.5 authentication features.
authorAndrey Hristov <andrey@php.net>
Mon, 24 Jan 2011 12:34:47 +0000 (12:34 +0000)
committerAndrey Hristov <andrey@php.net>
Mon, 24 Jan 2011 12:34:47 +0000 (12:34 +0000)
Authentication protocol can be changed, a new raw
packet is introduced, which includes only the "encrypted"
data for the auth plugin, sent after change protocol (0xFE)
is sent to the client.

ext/mysqlnd/mysqlnd.c
ext/mysqlnd/mysqlnd_auth.c
ext/mysqlnd/mysqlnd_enum_n_def.h
ext/mysqlnd/mysqlnd_net.c
ext/mysqlnd/mysqlnd_priv.h
ext/mysqlnd/mysqlnd_structs.h
ext/mysqlnd/mysqlnd_wireprotocol.c
ext/mysqlnd/mysqlnd_wireprotocol.h

index 8eda41374ee646b439a7ace99426d2fa83659ccc..1c730c616563b6b5252fb5554e685fccd0d3207f 100644 (file)
@@ -329,7 +329,7 @@ MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response)(MYSQLND * conn, enu
 /* {{{ mysqlnd_conn::simple_command */
 static enum_func_status
 MYSQLND_METHOD(mysqlnd_conn, simple_command)(MYSQLND * conn, enum php_mysqlnd_server_command command,
-                          const char * const arg, size_t arg_len, enum mysqlnd_packet_type ok_packet, zend_bool silent,
+                          const zend_uchar * const arg, size_t arg_len, enum mysqlnd_packet_type ok_packet, zend_bool silent,
                           zend_bool ignore_upsert_status TSRMLS_DC)
 {
        enum_func_status ret = PASS;
@@ -395,7 +395,7 @@ static enum_func_status
 MYSQLND_METHOD(mysqlnd_conn, set_server_option)(MYSQLND * const conn, enum_mysqlnd_server_option option TSRMLS_DC)
 {
        enum_func_status ret;
-       char buffer[2];
+       zend_uchar buffer[2];
        DBG_ENTER("mysqlnd_conn::set_server_option");
 
        int2store(buffer, (unsigned int) option);
@@ -508,43 +508,112 @@ mysqlnd_connect_run_authentication(
 
        ret = mysqlnd_switch_to_ssl_if_needed(conn, greet_packet, options, mysql_flags TSRMLS_CC);
        if (PASS == ret) {
+               zend_bool first_call = TRUE;
+
                char * switch_to_auth_protocol = NULL;
+               size_t switch_to_auth_protocol_len = 0;
                char * requested_protocol = NULL;
+               zend_uchar * plugin_data;
+               size_t plugin_data_len;
+
+               plugin_data_len = greet_packet->auth_plugin_data_len;
+               plugin_data = mnd_emalloc(plugin_data_len);
+               if (!plugin_data) {
+                       ret = FAIL;
+                       goto end;
+               }
+               memcpy(plugin_data, greet_packet->auth_plugin_data, plugin_data_len);
+
+               requested_protocol = mnd_pestrdup(greet_packet->auth_protocol? greet_packet->auth_protocol: "mysql_native_password", FALSE);
+               if (!requested_protocol) {
+                       ret = FAIL;
+                       goto end;
+               }
 
                do {
                        struct st_mysqlnd_authentication_plugin * auth_plugin;
-                       char * plugin_name = NULL;
-                       requested_protocol = switch_to_auth_protocol? switch_to_auth_protocol:
-                                                                                                                 (greet_packet->auth_protocol?
-                                                                                                                               greet_packet->auth_protocol:
-                                                                                                                               "mysql_native_password"
-                                                                                                                 );
-                       spprintf(&plugin_name, 0, "auth_plugin_%s", requested_protocol);
-                       DBG_INF_FMT("looking for %s auth plugin", plugin_name);
-                       auth_plugin = mysqlnd_plugin_find(plugin_name);
-                       efree(plugin_name);
-                       if (!auth_plugin) {
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "The server requested authentication method uknown to the client [%s]", requested_protocol);
-                               SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "The server requested authentication method uknown to the client");
-                               break;
-                       }
+                       {
+                               char * plugin_name = NULL;
 
+                               spprintf(&plugin_name, 0, "auth_plugin_%s", requested_protocol);
+
+                               DBG_INF_FMT("looking for %s auth plugin", plugin_name);
+                               auth_plugin = mysqlnd_plugin_find(plugin_name);
+                               efree(plugin_name);
+
+                               if (!auth_plugin) {
+                                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "The server requested authentication method unknown to the client [%s]", requested_protocol);
+                                       SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "The server requested authentication method umknown to the client");
+                                       break;
+                               }
+                       }
                        DBG_INF("plugin found");
 
-                       ret = mysqlnd_auth_handshake(conn, user, passwd, db, db_len, passwd_len, greet_packet, options, mysql_flags,
-                                                                                auth_plugin, &switch_to_auth_protocol TSRMLS_CC);
-                       DBG_INF_FMT("switch_to_auth_protocol=%s", switch_to_auth_protocol? switch_to_auth_protocol:"n/a");
-               } while (ret == FAIL && switch_to_auth_protocol != NULL);
+                       {
+                               zend_uchar * switch_to_auth_protocol_data = NULL;
+                               size_t switch_to_auth_protocol_data_len = 0;
+                               zend_uchar * scrambled_data = NULL;
+                               size_t scrambled_data_len = 0;
+
+                               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;
+                               }
+                               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) {
+                                       SET_OOM_ERROR(conn->error_info);
+                                       goto end;
+                               }
+                               memcpy(conn->auth_plugin_data, plugin_data, plugin_data_len);
+
+                               DBG_INF_FMT("salt=[%*s]", plugin_data_len - 1, plugin_data);
+                               /* The data should be allocated with malloc() */
+                               scrambled_data =
+                                       auth_plugin->methods.get_auth_data(NULL, &scrambled_data_len, conn, user, passwd, passwd_len,
+                                                                                                          plugin_data, plugin_data_len, options, mysql_flags TSRMLS_CC);
+
+
+                               ret = mysqlnd_auth_handshake(conn, user, passwd, db, db_len, passwd_len, options, mysql_flags, greet_packet->charset_no,
+                                                                                       first_call,
+                                                                                       requested_protocol,
+                                                                                       scrambled_data, scrambled_data_len,
+                                                                                       &switch_to_auth_protocol, &switch_to_auth_protocol_len,
+                                                                                       &switch_to_auth_protocol_data, &switch_to_auth_protocol_data_len
+                                                                                       TSRMLS_CC);
+                               first_call = FALSE;
+                               free(scrambled_data);
+
+                               DBG_INF_FMT("switch_to_auth_protocol=%s", switch_to_auth_protocol? switch_to_auth_protocol:"n/a");
+                               if (requested_protocol) {
+                                       mnd_efree(requested_protocol);
+                               }
+                               requested_protocol = switch_to_auth_protocol;
 
+                               if (plugin_data) {
+                                       mnd_efree(plugin_data);
+                               }
+                               plugin_data_len = switch_to_auth_protocol_data_len;
+                               plugin_data = switch_to_auth_protocol_data;
+                       }
+                       DBG_INF_FMT("conn->error_info.error_no = %d", conn->error_info.error_no);
+               } while (ret == FAIL && conn->error_info.error_no == 0 && switch_to_auth_protocol != NULL);
+               if (plugin_data) {
+                       mnd_efree(plugin_data);
+               }
+               
                if (ret == PASS) {
                        conn->m->set_client_option(conn, MYSQLND_OPT_AUTH_PROTOCOL, requested_protocol TSRMLS_CC);
                }
 
-               if (switch_to_auth_protocol) {
-                       mnd_efree(switch_to_auth_protocol);
-                       switch_to_auth_protocol = NULL;
+               if (requested_protocol) {
+                       mnd_efree(requested_protocol);
                }
        }
+end:
        DBG_RETURN(ret);
 }
 /* }}} */
@@ -937,7 +1006,7 @@ MYSQLND_METHOD(mysqlnd_conn, query)(MYSQLND * conn, const char * query, unsigned
        DBG_ENTER("mysqlnd_conn::query");
        DBG_INF_FMT("conn=%llu query=%s", conn->thread_id, query);
 
-       if (PASS != conn->m->simple_command(conn, COM_QUERY, query, query_len,
+       if (PASS != conn->m->simple_command(conn, COM_QUERY, (zend_uchar *) query, query_len,
                                                                           PROT_LAST /* we will handle the OK packet*/,
                                                                           FALSE, FALSE TSRMLS_CC)) {
                DBG_RETURN(FAIL);
@@ -965,7 +1034,7 @@ MYSQLND_METHOD(mysqlnd_conn, send_query)(MYSQLND * conn, const char * query, uns
        DBG_ENTER("mysqlnd_conn::send_query");
        DBG_INF_FMT("conn=%llu query=%s", conn->thread_id, query);
 
-       ret = conn->m->simple_command(conn, COM_QUERY, query, query_len,
+       ret = conn->m->simple_command(conn, COM_QUERY, (zend_uchar *) query, query_len,
                                                                 PROT_LAST /* we will handle the OK packet*/,
                                                                 FALSE, FALSE TSRMLS_CC);
        CONN_SET_STATE(conn, CONN_QUERY_SENT);
@@ -1184,7 +1253,7 @@ MYSQLND_RES *
 MYSQLND_METHOD(mysqlnd_conn, list_fields)(MYSQLND * conn, const char *table, const char *achtung_wild TSRMLS_DC)
 {
        /* db + \0 + wild + \0 (for wild) */
-       char buff[MYSQLND_MAX_ALLOWED_DB_LEN * 2 + 1 + 1], *p;
+       zend_uchar buff[MYSQLND_MAX_ALLOWED_DB_LEN * 2 + 1 + 1], *p;
        size_t table_len, wild_len;
        MYSQLND_RES *result = NULL;
        DBG_ENTER("mysqlnd_conn::list_fields");
@@ -1360,7 +1429,7 @@ MYSQLND_METHOD(mysqlnd_conn, select_db)(MYSQLND * const conn, const char * const
        DBG_ENTER("mysqlnd_conn::select_db");
        DBG_INF_FMT("conn=%llu db=%s", conn->thread_id, db);
 
-       ret = conn->m->simple_command(conn, COM_INIT_DB, db, db_len, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC);
+       ret = conn->m->simple_command(conn, COM_INIT_DB, (zend_uchar*) db, db_len, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC);
        /*
          The server sends 0 but libmysql doesn't read it and has established
          a protocol of giving back -1. Thus we have to follow it :(
@@ -1444,7 +1513,7 @@ static enum_func_status
 MYSQLND_METHOD(mysqlnd_conn, kill)(MYSQLND * conn, unsigned int pid TSRMLS_DC)
 {
        enum_func_status ret;
-       char buff[4];
+       zend_uchar buff[4];
 
        DBG_ENTER("mysqlnd_conn::kill");
        DBG_INF_FMT("conn=%llu pid=%lu", conn->thread_id, pid);
@@ -1512,7 +1581,7 @@ MYSQLND_METHOD(mysqlnd_conn, refresh)(MYSQLND * const conn, uint8_t options TSRM
 
        int1store(bits, options);
 
-       DBG_RETURN(conn->m->simple_command(conn, COM_REFRESH, (char *)bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC));
+       DBG_RETURN(conn->m->simple_command(conn, COM_REFRESH, bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC));
 }
 /* }}} */
 
@@ -1527,7 +1596,7 @@ MYSQLND_METHOD(mysqlnd_conn, shutdown)(MYSQLND * const conn, uint8_t level TSRML
 
        int1store(bits, level);
 
-       DBG_RETURN(conn->m->simple_command(conn, COM_SHUTDOWN, (char *)bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC));
+       DBG_RETURN(conn->m->simple_command(conn, COM_SHUTDOWN, bits, 1, PROT_OK_PACKET, FALSE, TRUE TSRMLS_CC));
 }
 /* }}} */
 
@@ -1930,6 +1999,7 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
        DBG_INF_FMT("conn=%llu user=%s passwd=%s db=%s silent=%u",
                                conn->thread_id, user?user:"", passwd?"***":"null", db?db:"", (silent == TRUE)?1:0 );
 
+       SET_EMPTY_ERROR(conn->error_info);
        SET_ERROR_AFF_ROWS(conn);
 
        if (!user) {
@@ -1944,47 +2014,116 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
 
 
        {
+               zend_bool first_call = TRUE;
                char * switch_to_auth_protocol = NULL;
-               const char * requested_protocol = NULL;
+               size_t switch_to_auth_protocol_len = 0;
+               char * requested_protocol = NULL;
+               zend_uchar * plugin_data;
+               size_t plugin_data_len;
+
+               plugin_data_len = conn->auth_plugin_data_len;
+               plugin_data = mnd_emalloc(plugin_data_len);
+               if (!plugin_data) {
+                       ret = FAIL;
+                       goto end;
+               }
+               memcpy(plugin_data, conn->auth_plugin_data, plugin_data_len);
+
+               requested_protocol = mnd_pestrdup(conn->options.auth_protocol? conn->options.auth_protocol:"mysql_native_password", FALSE);
+               if (!requested_protocol) {
+                       ret = FAIL;
+                       goto end;
+               }
 
                do {
                        struct st_mysqlnd_authentication_plugin * auth_plugin;
-                       char * plugin_name = NULL;
-                       requested_protocol = switch_to_auth_protocol? switch_to_auth_protocol:
-                                                                                                                 ((conn->server_capabilities & CLIENT_PLUGIN_AUTH)?
-                                                                                                                               conn->options.auth_protocol:
-                                                                                                                               "mysql_native_password"
-                                                                                                                 );
-
-                       spprintf(&plugin_name, 0, "auth_plugin_%s", requested_protocol);
-                       DBG_INF_FMT("looking for %s auth plugin", plugin_name);
-                       auth_plugin = mysqlnd_plugin_find(plugin_name);
-                       efree(plugin_name);
-                       if (!auth_plugin) {
-                               if (!silent) {
-                                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "The server requested authentication method uknown to the client [%s]", requested_protocol);
+                       {
+                               char * plugin_name = NULL;
+
+                               spprintf(&plugin_name, 0, "auth_plugin_%s", requested_protocol);
+
+                               DBG_INF_FMT("looking for %s auth plugin", plugin_name);
+                               auth_plugin = mysqlnd_plugin_find(plugin_name);
+                               efree(plugin_name);
+
+                               if (!auth_plugin) {
+                                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "The server requested authentication method unknown to the client [%s]", requested_protocol);
+                                       SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "The server requested authentication method umknown to the client");
+                                       break;
                                }
-                               SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "The server requested authentication method uknown to the client");
-                               break;
-                       }       
+                       }
                        DBG_INF("plugin found");
-                       ret = mysqlnd_auth_change_user(conn, user, strlen(user), passwd, db, strlen(db), passwd_len, silent,
-                                                                                  auth_plugin, &switch_to_auth_protocol TSRMLS_CC);
 
-                       DBG_INF_FMT("switch_to_auth_protocol=%s", switch_to_auth_protocol? switch_to_auth_protocol:"n/a");
-               } while (ret == FAIL && switch_to_auth_protocol != NULL);
+                       {
+                               zend_uchar * switch_to_auth_protocol_data = NULL;
+                               size_t switch_to_auth_protocol_data_len = 0;
+                               zend_uchar * scrambled_data = NULL;
+                               size_t scrambled_data_len = 0;
+
+                               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;
+                               }
+                               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) {
+                                       SET_OOM_ERROR(conn->error_info);
+                                       ret = FAIL;
+                                       goto end;
+                               }
+                               memcpy(conn->auth_plugin_data, plugin_data, plugin_data_len);
+
+                               DBG_INF_FMT("salt=[%*s]", plugin_data_len - 1, plugin_data);
+
+                               /* The data should be allocated with malloc() */
+                               scrambled_data =
+                                               auth_plugin->methods.get_auth_data(NULL, &scrambled_data_len, conn, user, passwd, passwd_len,
+                                                                                                                  plugin_data, plugin_data_len, 0, conn->server_capabilities TSRMLS_CC);
+
+
+                               ret = mysqlnd_auth_change_user(conn, user, strlen(user), passwd, db, strlen(db), passwd_len, silent,
+                                                                                          first_call,
+                                                                                          requested_protocol,
+                                                                                          scrambled_data, scrambled_data_len,
+                                                                                          &switch_to_auth_protocol, &switch_to_auth_protocol_len,
+                                                                                          &switch_to_auth_protocol_data, &switch_to_auth_protocol_data_len
+                                                                                          TSRMLS_CC);
+
+                               first_call = FALSE;
+                               free(scrambled_data);
+
+                               DBG_INF_FMT("switch_to_auth_protocol=%s", switch_to_auth_protocol? switch_to_auth_protocol:"n/a");
+                               if (requested_protocol) {
+                                       mnd_efree(requested_protocol);
+                               }
+                               requested_protocol = switch_to_auth_protocol;
+
+                               if (plugin_data) {
+                                       mnd_efree(plugin_data);
+                               }
+                               plugin_data_len = switch_to_auth_protocol_data_len;
+                               plugin_data = switch_to_auth_protocol_data;
+                       }
+                       DBG_INF_FMT("conn->error_info.error_no = %d", conn->error_info.error_no);
+               } while (ret == FAIL && conn->error_info.error_no == 0 && switch_to_auth_protocol != NULL);
+               if (plugin_data) {
+                       mnd_efree(plugin_data);
+               }
                if (ret == PASS) {
                        conn->m->set_client_option(conn, MYSQLND_OPT_AUTH_PROTOCOL, requested_protocol TSRMLS_CC);
                }
-               if (switch_to_auth_protocol) {
-                       mnd_efree(switch_to_auth_protocol);
-                       switch_to_auth_protocol = NULL;
+               if (requested_protocol) {
+                       mnd_efree(requested_protocol);
                }
        }
        /*
          Here we should close all statements. Unbuffered queries should not be a
          problem as we won't allow sending COM_CHANGE_USER.
        */
+end:
        DBG_INF(ret == PASS? "PASS":"FAIL");
        DBG_RETURN(ret);
 }
@@ -2107,9 +2246,9 @@ MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn,
                        break;
                case MYSQLND_OPT_AUTH_PROTOCOL:
                {
-                       char * new_auth_protocol = mnd_pestrdup(value, conn->persistent);
+                       char * new_auth_protocol = value? mnd_pestrdup(value, conn->persistent) : NULL;
                        DBG_INF("MYSQLND_OPT_AUTH_PROTOCOL");
-                       if (!new_auth_protocol) {
+                       if (value && !new_auth_protocol) {
                                goto oom;
                        }
                        if (conn->options.auth_protocol) {
@@ -2356,7 +2495,7 @@ PHPAPI void mysqlnd_library_init(TSRMLS_D)
                }
                mysqlnd_example_plugin_register(TSRMLS_C);
                mysqlnd_debug_trace_plugin_register(TSRMLS_C);
-               mysqlnd_native_authentication_plugin_register(TSRMLS_C);
+               mysqlnd_register_builtin_authentication_plugins(TSRMLS_C);
        }
 }
 /* }}} */
index 9183a88b69b93df4c7195577761e1f741e88c2cf..184238f893055f6375899faeb91154ef972bdcd8 100644 (file)
@@ -29,7 +29,7 @@
 #include "mysqlnd_debug.h"
 
 
-/* {{{ mysqlnd_native_auth_handshake */
+/* {{{ mysqlnd_auth_handshake */
 enum_func_status
 mysqlnd_auth_handshake(MYSQLND * conn,
                                                          const char * const user,
@@ -37,93 +37,122 @@ mysqlnd_auth_handshake(MYSQLND * conn,
                                                          const char * const db,
                                                          const size_t db_len,
                                                          const size_t passwd_len,
-                                                         const MYSQLND_PACKET_GREET * const greet_packet,
                                                          const MYSQLND_OPTIONS * const options,
                                                          unsigned long mysql_flags,
-                                                         struct st_mysqlnd_authentication_plugin * auth_plugin,
-                                                         char ** switch_to_auth_protocol
+                                                         unsigned int server_charset_no,
+                                                         zend_bool use_full_blown_auth_packet,
+                                                         const char * const auth_protocol,
+                                                         const zend_uchar * const auth_plugin_data,
+                                                         const size_t auth_plugin_data_len,
+                                                         char ** switch_to_auth_protocol,
+                                                         size_t * switch_to_auth_protocol_len,
+                                                         zend_uchar ** switch_to_auth_protocol_data,
+                                                         size_t * switch_to_auth_protocol_data_len
                                                          TSRMLS_DC)
 {
        enum_func_status ret = FAIL;
        const MYSQLND_CHARSET * charset = NULL;
-       MYSQLND_PACKET_OK * ok_packet = NULL;
+       MYSQLND_PACKET_CHANGE_AUTH_RESPONSE * change_auth_resp_packet = NULL;
+       MYSQLND_PACKET_AUTH_RESPONSE * auth_resp_packet = NULL;
        MYSQLND_PACKET_AUTH * auth_packet = NULL;
 
-       DBG_ENTER("mysqlnd_native_auth_handshake");
+       DBG_ENTER("mysqlnd_auth_handshake");
 
-       ok_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC);
-       auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC);
+       auth_resp_packet = conn->protocol->m.get_auth_response_packet(conn->protocol, FALSE TSRMLS_CC);
 
-       if (!ok_packet || !auth_packet) {
+       if (!auth_resp_packet) {
                SET_OOM_ERROR(conn->error_info);
                goto end;
        }
 
-       auth_packet->client_flags = mysql_flags;
-       auth_packet->max_packet_size = options->max_allowed_packet;
-       if (options->charset_name && (charset = mysqlnd_find_charset_name(options->charset_name))) {
-               auth_packet->charset_no = charset->nr;
+       if (use_full_blown_auth_packet != TRUE) {
+               change_auth_resp_packet = conn->protocol->m.get_change_auth_response_packet(conn->protocol, FALSE TSRMLS_CC);
+               if (!change_auth_resp_packet) {
+                       SET_OOM_ERROR(conn->error_info);
+                       goto end;
+               }
+
+               change_auth_resp_packet->auth_data = auth_plugin_data;
+               change_auth_resp_packet->auth_data_len = auth_plugin_data_len;
+
+               if (!PACKET_WRITE(change_auth_resp_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 end;
+               }
        } else {
+               auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC);
+
+               auth_packet->client_flags = mysql_flags;
+               auth_packet->max_packet_size = options->max_allowed_packet;
+               if (options->charset_name && (charset = mysqlnd_find_charset_name(options->charset_name))) {
+                       auth_packet->charset_no = charset->nr;
+               } else {
 #if MYSQLND_UNICODE
-               auth_packet->charset_no = 200;/* utf8 - swedish collation, check mysqlnd_charset.c */
+                       auth_packet->charset_no = 200;/* utf8 - swedish collation, check mysqlnd_charset.c */
 #else
-               auth_packet->charset_no = greet_packet->charset_no;
+                       auth_packet->charset_no = server_charset_no;
 #endif
-       }
-
-       auth_packet->send_auth_data = TRUE;
-       auth_packet->user               = user;
-       auth_packet->db                 = db;
-       auth_packet->db_len             = db_len;
+               }
 
-       conn->auth_plugin_data_len = greet_packet->auth_plugin_data_len;
-       conn->auth_plugin_data = mnd_pemalloc(conn->auth_plugin_data_len, conn->persistent);
-       if (!conn->auth_plugin_data) {
-               SET_OOM_ERROR(conn->error_info);
-               goto end;
-       }
-       memcpy(conn->auth_plugin_data, greet_packet->auth_plugin_data, greet_packet->auth_plugin_data_len);
+               auth_packet->send_auth_data = TRUE;
+               auth_packet->user               = user;
+               auth_packet->db                 = db;
+               auth_packet->db_len             = db_len;
 
-       auth_packet->auth_data =
-               auth_plugin->methods.get_auth_data(NULL, &auth_packet->auth_data_len, conn, user, passwd, passwd_len,
-                                                                                  conn->auth_plugin_data, conn->auth_plugin_data_len, options, mysql_flags TSRMLS_CC);
-                                                       
+               auth_packet->auth_data = auth_plugin_data;
+               auth_packet->auth_data_len = auth_plugin_data_len;
+               auth_packet->auth_plugin_name = auth_protocol;
 
-       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 end;
+               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 end;
+               }
        }
 
-       if (FAIL == PACKET_READ(ok_packet, conn) || ok_packet->field_count >= 0xFE) {
-               if (ok_packet->field_count == 0xFE) {
+       if (FAIL == PACKET_READ(auth_resp_packet, conn) || auth_resp_packet->response_code >= 0xFE) {
+               if (auth_resp_packet->response_code == 0xFE) {
                        /* old authentication with new server  !*/
-                       DBG_ERR(mysqlnd_old_passwd);
-                       SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd);
-               } else if (ok_packet->field_count == 0xFF) {
-                       if (ok_packet->sqlstate[0]) {
-                               strlcpy(conn->error_info.sqlstate, ok_packet->sqlstate, sizeof(conn->error_info.sqlstate));
-                               DBG_ERR_FMT("ERROR:%u [SQLSTATE:%s] %s", ok_packet->error_no, ok_packet->sqlstate, ok_packet->error);
+                       if (!auth_resp_packet->new_auth_protocol) {
+                               DBG_ERR(mysqlnd_old_passwd);
+                               SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd);
+                       } else {
+                               *switch_to_auth_protocol = mnd_pestrndup(auth_resp_packet->new_auth_protocol, auth_resp_packet->new_auth_protocol_len, FALSE);
+                               *switch_to_auth_protocol_len = auth_resp_packet->new_auth_protocol_len;
+                               if (auth_resp_packet->new_auth_protocol_data) {
+                                       *switch_to_auth_protocol_data_len = auth_resp_packet->new_auth_protocol_data_len;
+                                       *switch_to_auth_protocol_data = mnd_emalloc(*switch_to_auth_protocol_data_len);
+                                       memcpy(*switch_to_auth_protocol_data, auth_resp_packet->new_auth_protocol_data, *switch_to_auth_protocol_data_len);
+                               } else {
+                                       *switch_to_auth_protocol_data = NULL;
+                                       *switch_to_auth_protocol_data_len = 0;
+                               }                               
                        }
-                       conn->error_info.error_no = ok_packet->error_no;
-                       strlcpy(conn->error_info.error, ok_packet->error, sizeof(conn->error_info.error));
+               } else if (auth_resp_packet->response_code == 0xFF) {
+                       if (auth_resp_packet->sqlstate[0]) {
+                               strlcpy(conn->error_info.sqlstate, auth_resp_packet->sqlstate, sizeof(conn->error_info.sqlstate));
+                               DBG_ERR_FMT("ERROR:%u [SQLSTATE:%s] %s", auth_resp_packet->error_no, auth_resp_packet->sqlstate, auth_resp_packet->error);
+                       }
+                       conn->error_info.error_no = auth_resp_packet->error_no;
+                       strlcpy(conn->error_info.error, auth_resp_packet->error, sizeof(conn->error_info.error));
                }
                goto end;
        }
 
-       SET_NEW_MESSAGE(conn->last_message, conn->last_message_len, ok_packet->message, ok_packet->message_len, conn->persistent);
+       SET_NEW_MESSAGE(conn->last_message, conn->last_message_len, auth_resp_packet->message, auth_resp_packet->message_len, conn->persistent);
        conn->charset = mysqlnd_find_charset_nr(auth_packet->charset_no);
        ret = PASS;
 end:
-       mnd_efree(auth_packet->auth_data);
+       PACKET_FREE(change_auth_resp_packet);
        PACKET_FREE(auth_packet);
-       PACKET_FREE(ok_packet);
+       PACKET_FREE(auth_resp_packet);
        DBG_RETURN(ret);
 }
 /* }}} */
 
 
-/* {{{ mysqlnd_native_auth_change_user */
+/* {{{ mysqlnd_auth_change_user */
 enum_func_status
 mysqlnd_auth_change_user(MYSQLND * const conn,
                                                                const char * const user,
@@ -133,8 +162,14 @@ mysqlnd_auth_change_user(MYSQLND * const conn,
                                                                const size_t db_len,
                                                                const size_t passwd_len,
                                                                const zend_bool silent,
-                                                               struct st_mysqlnd_authentication_plugin * auth_plugin,
-                                                               char ** switch_to_auth_protocol
+                                                               zend_bool use_full_blown_auth_packet,
+                                                               const char * const auth_protocol,
+                                                               zend_uchar * auth_plugin_data,
+                                                               size_t auth_plugin_data_len,
+                                                               char ** switch_to_auth_protocol,
+                                                               size_t * switch_to_auth_protocol_len,
+                                                               zend_uchar ** switch_to_auth_protocol_data,
+                                                               size_t * switch_to_auth_protocol_data_len
                                                                TSRMLS_DC)
 {
        /*
@@ -146,40 +181,87 @@ mysqlnd_auth_change_user(MYSQLND * const conn,
        char buffer[MYSQLND_MAX_ALLOWED_USER_LEN + 1 + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 2 /* charset*/ ];
        char *p = buffer;
        const MYSQLND_CHARSET * old_cs = conn->charset;
-       MYSQLND_PACKET_AUTH * auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC);
-       MYSQLND_PACKET_CHG_USER_RESPONSE * chg_user_resp = conn->protocol->m.get_change_user_response_packet(conn->protocol, FALSE TSRMLS_CC);
+       MYSQLND_PACKET_CHANGE_AUTH_RESPONSE * change_auth_resp_packet = NULL;
+       MYSQLND_PACKET_CHG_USER_RESPONSE * chg_user_resp = NULL;
+       MYSQLND_PACKET_AUTH * auth_packet = NULL;
+
+       DBG_ENTER("mysqlnd_auth_change_user");
 
-       DBG_ENTER("mysqlnd_native_auth_change_user");
+       chg_user_resp = conn->protocol->m.get_change_user_response_packet(conn->protocol, FALSE TSRMLS_CC);
 
-       if (!auth_packet || !chg_user_resp) {
+       if (!chg_user_resp) {
                SET_OOM_ERROR(conn->error_info);
                goto end;
        }
 
-       auth_packet->is_change_user_packet = TRUE;
-       auth_packet->user               = user;
-       auth_packet->db                 = db;
-       auth_packet->db_len             = db_len;
-       auth_packet->silent             = silent;
+       if (use_full_blown_auth_packet != TRUE) {
+               change_auth_resp_packet = conn->protocol->m.get_change_auth_response_packet(conn->protocol, FALSE TSRMLS_CC);
+               if (!change_auth_resp_packet) {
+                       SET_OOM_ERROR(conn->error_info);
+                       goto end;
+               }
 
-       auth_packet->auth_data =
-               auth_plugin->methods.get_auth_data(NULL, &auth_packet->auth_data_len, conn, user, passwd, passwd_len,
-                                                                                  conn->auth_plugin_data, conn->auth_plugin_data_len, NULL /* options */, 0 /* mysql_flags */ TSRMLS_CC);
+               change_auth_resp_packet->auth_data = auth_plugin_data;
+               change_auth_resp_packet->auth_data_len = auth_plugin_data_len;
 
-       if (mysqlnd_get_server_version(conn) >= 50123) {
-               auth_packet->charset_no = conn->charset->nr;
-               p+=2;
-       }
+               if (!PACKET_WRITE(change_auth_resp_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 end;
+               }       
+       } else {
+               auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC);
+
+               if (!auth_packet) {
+                       SET_OOM_ERROR(conn->error_info);
+                       goto end;
+               }
+
+               auth_packet->is_change_user_packet = TRUE;
+               auth_packet->user               = user;
+               auth_packet->db                 = db;
+               auth_packet->db_len             = db_len;
+               auth_packet->silent             = silent;
+
+               auth_packet->auth_data = auth_plugin_data;
+               auth_packet->auth_data_len = auth_plugin_data_len;
+               auth_packet->auth_plugin_name = auth_protocol;
+
+
+               if (mysqlnd_get_server_version(conn) >= 50123) {
+                       auth_packet->charset_no = conn->charset->nr;
+                       p+=2;
+               }
        
-       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 end;
+               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 end;
+               }
        }
 
        ret = PACKET_READ(chg_user_resp, conn);
        conn->error_info = chg_user_resp->error_info;
 
+       if (0xFE == chg_user_resp->response_code) {
+               ret = FAIL;
+               if (!chg_user_resp->new_auth_protocol) {
+                       DBG_ERR(mysqlnd_old_passwd);
+                       SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd);
+               } else {
+                       *switch_to_auth_protocol = mnd_pestrndup(chg_user_resp->new_auth_protocol, chg_user_resp->new_auth_protocol_len, FALSE);
+                       *switch_to_auth_protocol_len = chg_user_resp->new_auth_protocol_len;
+                       if (chg_user_resp->new_auth_protocol_data) {
+                               *switch_to_auth_protocol_data_len = chg_user_resp->new_auth_protocol_data_len;
+                               *switch_to_auth_protocol_data = mnd_emalloc(*switch_to_auth_protocol_data_len);
+                               memcpy(*switch_to_auth_protocol_data, chg_user_resp->new_auth_protocol_data, *switch_to_auth_protocol_data_len);
+                       } else {
+                               *switch_to_auth_protocol_data = NULL;
+                               *switch_to_auth_protocol_data_len = 0;
+                       }                               
+               }
+       }
+
        if (conn->error_info.error_no) {
                ret = FAIL;
                /*
@@ -228,7 +310,7 @@ mysqlnd_auth_change_user(MYSQLND * const conn,
                SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd);
        }
 end:
-       mnd_efree(auth_packet->auth_data);
+       PACKET_FREE(change_auth_resp_packet);
        PACKET_FREE(auth_packet);
        PACKET_FREE(chg_user_resp);
        DBG_RETURN(ret);
@@ -236,6 +318,51 @@ end:
 /* }}} */
 
 
+/******************************************* MySQL Native Password ***********************************/
+
+#include "ext/standard/sha1.h"
+
+/* {{{ php_mysqlnd_crypt */
+static void
+php_mysqlnd_crypt(zend_uchar *buffer, const zend_uchar *s1, const zend_uchar *s2, size_t len)
+{
+       const zend_uchar *s1_end = s1 + len;
+       while (s1 < s1_end) {
+               *buffer++= *s1++ ^ *s2++;
+       }
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_scramble */
+void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * const scramble, const zend_uchar * const password, size_t password_len)
+{
+       PHP_SHA1_CTX context;
+       zend_uchar sha1[SHA1_MAX_LENGTH];
+       zend_uchar sha2[SHA1_MAX_LENGTH];
+
+       /* Phase 1: hash password */
+       PHP_SHA1Init(&context);
+       PHP_SHA1Update(&context, password, password_len);
+       PHP_SHA1Final(sha1, &context);
+
+       /* Phase 2: hash sha1 */
+       PHP_SHA1Init(&context);
+       PHP_SHA1Update(&context, (zend_uchar*)sha1, SHA1_MAX_LENGTH);
+       PHP_SHA1Final(sha2, &context);
+
+       /* Phase 3: hash scramble + sha2 */
+       PHP_SHA1Init(&context);
+       PHP_SHA1Update(&context, scramble, SCRAMBLE_LENGTH);
+       PHP_SHA1Update(&context, (zend_uchar*)sha2, SHA1_MAX_LENGTH);
+       PHP_SHA1Final(buffer, &context);
+
+       /* let's crypt buffer now */
+       php_mysqlnd_crypt(buffer, (const zend_uchar *)buffer, (const zend_uchar *)sha1, SHA1_MAX_LENGTH);
+}
+/* }}} */
+
+
 /* {{{ mysqlnd_native_auth_get_auth_data */
 static zend_uchar *
 mysqlnd_native_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self,
@@ -250,7 +377,7 @@ mysqlnd_native_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self
        *auth_data_len = 0;
 
        /* 5.5.x reports 21 as scramble length because it needs to show the length of the data before the plugin name */
-       if (auth_plugin_data_len != SCRAMBLE_LENGTH && (auth_plugin_data_len != 21)) {
+       if (auth_plugin_data_len < SCRAMBLE_LENGTH) {
                /* mysql_native_password only works with SCRAMBLE_LENGTH scramble */
                SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "The server sent wrong length for scramble");
                DBG_ERR_FMT("The server sent wrong length for scramble %u. Expected %u", auth_plugin_data_len, SCRAMBLE_LENGTH);
@@ -259,7 +386,7 @@ mysqlnd_native_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self
 
        /* copy scrambled pass*/
        if (passwd && passwd_len) {
-               ret = mnd_emalloc(SCRAMBLE_LENGTH);
+               ret = malloc(SCRAMBLE_LENGTH);
                *auth_data_len = SCRAMBLE_LENGTH;
                /* In 4.1 we use CLIENT_SECURE_CONNECTION and thus the len of the buf should be passed */
                php_mysqlnd_scramble((zend_uchar*)ret, auth_plugin_data, (zend_uchar*)passwd, passwd_len);
@@ -292,11 +419,59 @@ static struct st_mysqlnd_authentication_plugin mysqlnd_native_auth_plugin =
 };
 
 
-/* {{{ mysqlnd_native_authentication_plugin_register */
+/******************************************* PAM Authentication ***********************************/
+
+/* {{{ mysqlnd_pam_auth_get_auth_data */
+static zend_uchar *
+mysqlnd_pam_auth_get_auth_data(struct st_mysqlnd_authentication_plugin * self,
+                                                          size_t * auth_data_len,
+                                                          MYSQLND * conn, const char * const user, const char * const passwd,
+                                                          const size_t passwd_len, zend_uchar * auth_plugin_data, size_t auth_plugin_data_len,
+                                                          const MYSQLND_OPTIONS * const options, unsigned long mysql_flags
+                                                          TSRMLS_DC)
+{
+       zend_uchar * ret = NULL;
+
+       /* copy pass*/
+       if (passwd && passwd_len) {
+               ret = (zend_uchar*) strndup(passwd, passwd_len);
+       }
+       *auth_data_len = passwd_len;
+
+       return ret;
+}
+/* }}} */
+
+
+static struct st_mysqlnd_authentication_plugin mysqlnd_pam_authentication_plugin =
+{
+       {
+               MYSQLND_PLUGIN_API_VERSION,
+               "auth_plugin_authentication_pam",
+               MYSQLND_VERSION_ID,
+               MYSQLND_VERSION,
+               "Proprietatry",
+               "Andrey Hristov <andrey@mysql.com>,  Ulf Wendel <uwendel@mysql.com>, Georg Richter <georg@mysql.com>",
+               {
+                       NULL, /* no statistics , will be filled later if there are some */
+                       NULL, /* no statistics */
+               },
+               {
+                       NULL /* plugin shutdown */
+               }
+       },
+       {/* methods */
+               mysqlnd_pam_auth_get_auth_data
+       }
+};
+
+
+/* {{{ mysqlnd_register_builtin_authentication_plugins */
 void
-mysqlnd_native_authentication_plugin_register(TSRMLS_D)
+mysqlnd_register_builtin_authentication_plugins(TSRMLS_D)
 {
        mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_native_auth_plugin TSRMLS_CC);
+       mysqlnd_plugin_register_ex((struct st_mysqlnd_plugin_header *) &mysqlnd_pam_authentication_plugin TSRMLS_CC);
 }
 /* }}} */
 
index 79fee3417622c19c9f8ada96fb1ac7f3ebc1260f..e51b87a69df071c868992924eb5af54dc1675854 100644 (file)
 
 #define MYSQLND_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_TRANSACTIONS | \
                                CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION | \
-                               CLIENT_MULTI_RESULTS | CLIENT_PS_MULTI_RESULTS | CLIENT_LOCAL_FILES)
+                               CLIENT_MULTI_RESULTS | CLIENT_PS_MULTI_RESULTS | CLIENT_LOCAL_FILES | CLIENT_PLUGIN_AUTH)
 
 #define MYSQLND_NET_FLAG_USE_COMPRESSION 1
 
@@ -522,6 +522,8 @@ enum mysqlnd_packet_type
 {
        PROT_GREET_PACKET= 0,
        PROT_AUTH_PACKET,
+       PROT_AUTH_RESP_PACKET,
+       PROT_CHANGE_AUTH_RESP_PACKET,
        PROT_OK_PACKET,
        PROT_EOF_PACKET,
        PROT_CMD_PACKET,
index 974f1918e91063da806da8d5c1f86ce08b66a8a1..0acc6ccd6e735142ae8ee45154051faf9d6a8ae5 100644 (file)
@@ -227,7 +227,7 @@ MYSQLND_METHOD(mysqlnd_net, connect)(MYSQLND_NET * net, const char * const schem
   count + MYSQLND_HEADER_SIZE = sizeof(buf) (not the pointer but the actual buffer)
 */
 size_t
-MYSQLND_METHOD(mysqlnd_net, send)(MYSQLND * const conn, char * const buf, size_t count TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_net, send)(MYSQLND * const conn, zend_uchar * const buf, size_t count TSRMLS_DC)
 {
        zend_uchar safe_buf[((MYSQLND_HEADER_SIZE) + (sizeof(zend_uchar)) - 1) / (sizeof(zend_uchar))];
        zend_uchar *safe_storage = safe_buf;
index 31c382f9a18871f799e5c83632400d3c3ab1ecff..4bd063d7bf6ca8ba767a6371772c4c64ba7323e0 100644 (file)
@@ -192,7 +192,7 @@ void ps_fetch_from_1_to_8_bytes(zval *zv, const MYSQLND_FIELD * const field,
 void mysqlnd_plugin_subsystem_init(TSRMLS_D);
 void mysqlnd_plugin_subsystem_end(TSRMLS_D);
 
-void mysqlnd_native_authentication_plugin_register(TSRMLS_D);
+void mysqlnd_register_builtin_authentication_plugins(TSRMLS_D);
 
 void mysqlnd_example_plugin_register(TSRMLS_D);
 
@@ -206,11 +206,17 @@ mysqlnd_auth_handshake(MYSQLND * conn,
                                                const char * const db,
                                                const size_t db_len,
                                                const size_t passwd_len,
-                                               const struct st_mysqlnd_packet_greet * const greet_packet,
                                                const MYSQLND_OPTIONS * const options,
                                                unsigned long mysql_flags,
-                                               struct st_mysqlnd_authentication_plugin * auth_plugin,
-                                               char ** switch_to_auth_protocol
+                                               unsigned int server_charset_no,
+                                               zend_bool use_full_blown_auth_packet,
+                                               const char * const auth_protocol,
+                                               const zend_uchar * const auth_plugin_data,
+                                               const size_t auth_plugin_data_len,
+                                               char ** switch_to_auth_protocol,
+                                               size_t * switch_to_auth_protocol_len,
+                                               zend_uchar ** switch_to_auth_protocol_data,
+                                               size_t * switch_to_auth_protocol_data_len
                                                TSRMLS_DC);
 
 enum_func_status
@@ -222,8 +228,14 @@ mysqlnd_auth_change_user(MYSQLND * const conn,
                                                                const size_t db_len,
                                                                const size_t passwd_len,
                                                                const zend_bool silent,
-                                                               struct st_mysqlnd_authentication_plugin * auth_plugin,
-                                                               char ** switch_to_auth_protocol
+                                                               zend_bool use_full_blown_auth_packet,
+                                                               const char * const auth_protocol,
+                                                               zend_uchar * auth_plugin_data,
+                                                               size_t auth_plugin_data_len,
+                                                               char ** switch_to_auth_protocol,
+                                                               size_t * switch_to_auth_protocol_len,
+                                                               zend_uchar ** switch_to_auth_protocol_data,
+                                                               size_t * switch_to_auth_protocol_data_len
                                                                TSRMLS_DC);
 
 #endif /* MYSQLND_PRIV_H */
index a081468ef6bd16f5eb8414ba78a85822fe6c1390..f043ea9eb8018c100131d074969d50e774222753 100644 (file)
@@ -252,7 +252,7 @@ typedef struct st_mysqlnd_read_buffer {
 
 
 typedef enum_func_status       (*func_mysqlnd_net__connect)(MYSQLND_NET * net, const char * const scheme, size_t scheme_len, zend_bool persistent, char **errstr, int * errcode TSRMLS_DC);
-typedef size_t                         (*func_mysqlnd_net__send)(MYSQLND * const conn, char * const buf, size_t count TSRMLS_DC);
+typedef size_t                         (*func_mysqlnd_net__send)(MYSQLND * const conn, zend_uchar * const buf, size_t count TSRMLS_DC);
 typedef enum_func_status       (*func_mysqlnd_net__receive)(MYSQLND * conn, zend_uchar * buffer, size_t count TSRMLS_DC);
 typedef enum_func_status       (*func_mysqlnd_net__set_client_option)(MYSQLND_NET * const net, enum_mysqlnd_option option, const char * const value TSRMLS_DC);
 typedef enum_func_status       (*func_mysqlnd_net__network_read)(MYSQLND * conn, zend_uchar * buffer, size_t count TSRMLS_DC);
@@ -304,6 +304,8 @@ struct st_mysqlnd_packet_auth_pam;
 
 typedef struct st_mysqlnd_packet_greet *               (*func_mysqlnd_protocol__get_greet_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
 typedef struct st_mysqlnd_packet_auth *                        (*func_mysqlnd_protocol__get_auth_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
+typedef struct st_mysqlnd_packet_auth_response *(*func_mysqlnd_protocol__get_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
+typedef struct st_mysqlnd_packet_change_auth_response *        (*func_mysqlnd_protocol__get_change_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
 typedef struct st_mysqlnd_packet_ok *                  (*func_mysqlnd_protocol__get_ok_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
 typedef struct st_mysqlnd_packet_command *             (*func_mysqlnd_protocol__get_command_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
 typedef struct st_mysqlnd_packet_eof *                 (*func_mysqlnd_protocol__get_eof_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC);
@@ -318,6 +320,8 @@ struct st_mysqlnd_protocol_methods
 {
        func_mysqlnd_protocol__get_greet_packet get_greet_packet;
        func_mysqlnd_protocol__get_auth_packet get_auth_packet;
+       func_mysqlnd_protocol__get_auth_response_packet get_auth_response_packet;
+       func_mysqlnd_protocol__get_change_auth_response_packet get_change_auth_response_packet;
        func_mysqlnd_protocol__get_ok_packet get_ok_packet;
        func_mysqlnd_protocol__get_command_packet get_command_packet;
        func_mysqlnd_protocol__get_eof_packet get_eof_packet;
@@ -396,7 +400,7 @@ typedef enum_func_status    (*func_mysqlnd_conn__free_reference)(MYSQLND * const co
 typedef enum mysqlnd_connection_state (*func_mysqlnd_conn__get_state)(MYSQLND * const conn TSRMLS_DC);
 typedef void                           (*func_mysqlnd_conn__set_state)(MYSQLND * const conn, enum mysqlnd_connection_state new_state TSRMLS_DC);
 
-typedef enum_func_status       (*func_mysqlnd_conn__simple_command)(MYSQLND *conn, enum php_mysqlnd_server_command command, const char * const arg, size_t arg_len, enum mysqlnd_packet_type ok_packet, zend_bool silent, zend_bool ignore_upsert_status TSRMLS_DC);
+typedef enum_func_status       (*func_mysqlnd_conn__simple_command)(MYSQLND *conn, enum php_mysqlnd_server_command command, const zend_uchar * const arg, size_t arg_len, enum mysqlnd_packet_type ok_packet, zend_bool silent, zend_bool ignore_upsert_status TSRMLS_DC);
 typedef enum_func_status       (*func_mysqlnd_conn__simple_command_handle_response)(MYSQLND *conn, enum mysqlnd_packet_type ok_packet, zend_bool silent, enum php_mysqlnd_server_command command, zend_bool ignore_upsert_status TSRMLS_DC);
 
 typedef enum_func_status       (*func_mysqlnd_conn__restart_psession)(MYSQLND *conn TSRMLS_DC);
index e7205066f3cf63c395cfb2a02a30cdd526bbcf1f..c05b1e2462e716538993fac7b5b81f2898116e47 100644 (file)
@@ -25,7 +25,6 @@
 #include "mysqlnd_statistics.h"
 #include "mysqlnd_debug.h"
 #include "mysqlnd_block_alloc.h"
-#include "ext/standard/sha1.h"
 #include "zend_ini.h"
 
 #define MYSQLND_SILENT 1
@@ -459,57 +458,16 @@ void php_mysqlnd_greet_free_mem(void *_packet, zend_bool stack_allocation TSRMLS
 /* }}} */
 
 
-/* {{{ php_mysqlnd_crypt */
-static void
-php_mysqlnd_crypt(zend_uchar *buffer, const zend_uchar *s1, const zend_uchar *s2, size_t len)
-{
-       const zend_uchar *s1_end = s1 + len;
-       while (s1 < s1_end) {
-               *buffer++= *s1++ ^ *s2++;
-       }
-}
-/* }}} */
-
-
-/* {{{ php_mysqlnd_scramble */
-void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * const scramble, const zend_uchar * const password, size_t password_len)
-{
-       PHP_SHA1_CTX context;
-       zend_uchar sha1[SHA1_MAX_LENGTH];
-       zend_uchar sha2[SHA1_MAX_LENGTH];
-
-       /* Phase 1: hash password */
-       PHP_SHA1Init(&context);
-       PHP_SHA1Update(&context, password, password_len);
-       PHP_SHA1Final(sha1, &context);
-
-       /* Phase 2: hash sha1 */
-       PHP_SHA1Init(&context);
-       PHP_SHA1Update(&context, (zend_uchar*)sha1, SHA1_MAX_LENGTH);
-       PHP_SHA1Final(sha2, &context);
-
-       /* Phase 3: hash scramble + sha2 */
-       PHP_SHA1Init(&context);
-       PHP_SHA1Update(&context, scramble, SCRAMBLE_LENGTH);
-       PHP_SHA1Update(&context, (zend_uchar*)sha2, SHA1_MAX_LENGTH);
-       PHP_SHA1Final(buffer, &context);
-
-       /* let's crypt buffer now */
-       php_mysqlnd_crypt(buffer, (const zend_uchar *)buffer, (const zend_uchar *)sha1, SHA1_MAX_LENGTH);
-}
-/* }}} */
-
-
 #define AUTH_WRITE_BUFFER_LEN (MYSQLND_HEADER_SIZE + MYSQLND_MAX_ALLOWED_USER_LEN + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1 + 1024)
 
 /* {{{ php_mysqlnd_auth_write */
 static
 size_t php_mysqlnd_auth_write(void *_packet, MYSQLND * conn TSRMLS_DC)
 {
-       char buffer[AUTH_WRITE_BUFFER_LEN];
-       register char *p= buffer + MYSQLND_HEADER_SIZE; /* start after the header */
+       zend_uchar buffer[AUTH_WRITE_BUFFER_LEN];
+       zend_uchar *p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
        int len;
-       register MYSQLND_PACKET_AUTH *packet= (MYSQLND_PACKET_AUTH *) _packet;
+       MYSQLND_PACKET_AUTH * packet= (MYSQLND_PACKET_AUTH *) _packet;
 
        DBG_ENTER("php_mysqlnd_auth_write");
 
@@ -534,8 +492,8 @@ size_t php_mysqlnd_auth_write(void *_packet, MYSQLND * conn TSRMLS_DC)
                *p++ = '\0';
 
                /* defensive coding */
-               if (!packet->auth_data) {
-                       packet->auth_data = 0;
+               if (packet->auth_data == NULL) {
+                       packet->auth_data_len = 0;
                }
                int1store(p, packet->auth_data_len);
                ++p;
@@ -555,6 +513,8 @@ size_t php_mysqlnd_auth_write(void *_packet, MYSQLND * conn TSRMLS_DC)
                        memcpy(p, packet->db, real_db_len);
                        p+= real_db_len;
                        *p++= '\0';
+               } else if (packet->is_change_user_packet) {
+                       *p++= '\0';             
                }
                /* no \0 for no DB */
 
@@ -563,13 +523,13 @@ size_t php_mysqlnd_auth_write(void *_packet, MYSQLND * conn TSRMLS_DC)
                                int2store(p, packet->charset_no);
                                p+= 2;
                        }
-               } else {
-                       if (packet->auth_plugin_name) {
-                               size_t len = MIN(strlen(packet->auth_plugin_name), sizeof(buffer) - (p - buffer) - 1);
-                               memcpy(p, packet->auth_plugin_name, len);
-                               p+= len;
-                               *p++= '\0';
-                       }
+               }
+               
+               if (packet->auth_plugin_name) {
+                       size_t len = MIN(strlen(packet->auth_plugin_name), sizeof(buffer) - (p - buffer) - 1);
+                       memcpy(p, packet->auth_plugin_name, len);
+                       p+= len;
+                       *p++= '\0';
                }
        }
        if (packet->is_change_user_packet) {
@@ -598,6 +558,166 @@ void php_mysqlnd_auth_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_
 /* }}} */
 
 
+#define AUTH_RESP_BUFFER_SIZE 2048
+
+/* {{{ php_mysqlnd_auth_response_read */
+static enum_func_status
+php_mysqlnd_auth_response_read(void *_packet, MYSQLND *conn TSRMLS_DC)
+{
+       zend_uchar local_buf[AUTH_RESP_BUFFER_SIZE];
+       size_t buf_len = conn->net->cmd_buffer.buffer? conn->net->cmd_buffer.length: AUTH_RESP_BUFFER_SIZE;
+       zend_uchar *buf = conn->net->cmd_buffer.buffer? (zend_uchar *) conn->net->cmd_buffer.buffer : local_buf;
+       zend_uchar *p = buf;
+       zend_uchar *begin = buf;
+       unsigned long i;
+       register MYSQLND_PACKET_AUTH_RESPONSE * packet= (MYSQLND_PACKET_AUTH_RESPONSE *) _packet;
+
+       DBG_ENTER("php_mysqlnd_auth_response_read");
+
+       /* leave space for terminating safety \0 */
+       buf_len--;
+       PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "OK", PROT_OK_PACKET);
+       BAIL_IF_NO_MORE_DATA;
+
+       /*
+         zero-terminate the buffer for safety. We are sure there is place for the \0
+         because buf_len is -1 the size of the buffer pointed
+       */
+       buf[packet->header.size] = '\0';
+       
+       /* Should be always 0x0 or ERROR_MARKER for error */
+       packet->response_code = uint1korr(p);
+       p++;
+       BAIL_IF_NO_MORE_DATA;
+
+       if (ERROR_MARKER == packet->response_code) {
+               php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
+                                                                                packet->error, sizeof(packet->error),
+                                                                                &packet->error_no, packet->sqlstate
+                                                                                TSRMLS_CC);
+               DBG_RETURN(PASS);
+       }
+       if (0xFE == packet->response_code) {
+               /* Authentication Switch Response */
+               if (packet->header.size > (size_t) (p - buf)) {
+                       packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
+                       packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
+                       p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
+
+                       packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
+                       if (packet->new_auth_protocol_data_len) {
+                               packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
+                               memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
+                       }
+                       DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
+                       DBG_INF_FMT("Server salt : [%*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
+               }
+       } else {
+               /* Everything was fine! */
+               packet->affected_rows  = php_mysqlnd_net_field_length_ll(&p);
+               BAIL_IF_NO_MORE_DATA;
+
+               packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
+               BAIL_IF_NO_MORE_DATA;
+
+               packet->server_status = uint2korr(p);
+               p+= 2;
+               BAIL_IF_NO_MORE_DATA;
+
+               packet->warning_count = uint2korr(p);
+               p+= 2;
+               BAIL_IF_NO_MORE_DATA;
+
+               /* There is a message */
+               if (packet->header.size > (size_t) (p - buf) && (i = php_mysqlnd_net_field_length(&p))) {
+                       packet->message_len = MIN(i, buf_len - (p - begin));
+                       packet->message = mnd_pestrndup((char *)p, packet->message_len, FALSE);
+               } else {
+                       packet->message = NULL;
+                       packet->message_len = 0;
+               }
+
+               DBG_INF_FMT("OK packet: aff_rows=%lld last_ins_id=%ld server_status=%u warnings=%u",
+                                       packet->affected_rows, packet->last_insert_id, packet->server_status,
+                                       packet->warning_count);
+       }
+
+       DBG_RETURN(PASS);
+premature_end:
+       DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
+       php_error_docref(NULL TSRMLS_CC, E_WARNING, "AUTH_RESPONSE packet "MYSQLND_SZ_T_SPEC" bytes shorter than expected",
+                                        p - begin - packet->header.size);
+       DBG_RETURN(FAIL);
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_auth_response_free_mem */
+static void
+php_mysqlnd_auth_response_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC)
+{
+       MYSQLND_PACKET_AUTH_RESPONSE * p = (MYSQLND_PACKET_AUTH_RESPONSE *) _packet;
+       if (p->message) {
+               mnd_efree(p->message);
+               p->message = NULL;
+       }
+       if (p->new_auth_protocol) {
+               mnd_efree(p->new_auth_protocol);
+               p->new_auth_protocol = NULL;
+       }
+       p->new_auth_protocol_len = 0;
+
+       if (p->new_auth_protocol_data) {
+               mnd_efree(p->new_auth_protocol_data);
+               p->new_auth_protocol_data = NULL;
+       }
+       p->new_auth_protocol_data_len = 0;
+
+       if (!stack_allocation) {
+               mnd_pefree(p, p->header.persistent);
+       }
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_change_auth_response_write */
+static
+size_t php_mysqlnd_change_auth_response_write(void *_packet, MYSQLND * conn TSRMLS_DC)
+{
+       MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *packet= (MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *) _packet;
+       zend_uchar * buffer = conn->net->cmd_buffer.length >= packet->auth_data_len? conn->net->cmd_buffer.buffer : mnd_emalloc(packet->auth_data_len);
+       zend_uchar *p = buffer + MYSQLND_HEADER_SIZE; /* start after the header */
+
+       DBG_ENTER("php_mysqlnd_change_auth_response_write");
+
+       if (packet->auth_data_len) {
+               memcpy(p, packet->auth_data, packet->auth_data_len);
+               p+= packet->auth_data_len;
+       }
+
+       {
+               size_t ret = conn->net->m.send(conn, buffer, p - buffer - MYSQLND_HEADER_SIZE TSRMLS_CC);
+               if (buffer != conn->net->cmd_buffer.buffer) {
+                       mnd_efree(buffer);
+               }
+               DBG_RETURN(ret);
+       }
+}
+/* }}} */
+
+
+/* {{{ php_mysqlnd_change_auth_response_free_mem */
+static
+void php_mysqlnd_change_auth_response_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC)
+{
+       if (!stack_allocation) {
+               MYSQLND_PACKET_CHANGE_AUTH_RESPONSE * p = (MYSQLND_PACKET_CHANGE_AUTH_RESPONSE *) _packet;
+               mnd_pefree(p, p->header.persistent);
+       }
+}
+/* }}} */
+
+
 #define OK_BUFFER_SIZE 2048
 
 /* {{{ php_mysqlnd_ok_read */
@@ -791,7 +911,7 @@ size_t php_mysqlnd_cmd_write(void *_packet, MYSQLND *conn TSRMLS_DC)
 #endif
 
        if (!packet->argument || !packet->arg_len) {
-               char buffer[MYSQLND_HEADER_SIZE + 1];
+               zend_uchar buffer[MYSQLND_HEADER_SIZE + 1];
 
                int1store(buffer + MYSQLND_HEADER_SIZE, packet->command);
                written = conn->net->m.send(conn, buffer, 1 TSRMLS_CC);
@@ -809,7 +929,7 @@ size_t php_mysqlnd_cmd_write(void *_packet, MYSQLND *conn TSRMLS_DC)
 
                memcpy(p, packet->argument, packet->arg_len);
 
-               ret = conn->net->m.send(conn, (char *)tmp, tmp_len - MYSQLND_HEADER_SIZE TSRMLS_CC);
+               ret = conn->net->m.send(conn, tmp, tmp_len - MYSQLND_HEADER_SIZE TSRMLS_CC);
                if (tmp != net->cmd_buffer.buffer) {
                        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_CMD_BUFFER_TOO_SMALL);
                        mnd_efree(tmp);
@@ -1875,7 +1995,7 @@ php_mysqlnd_chg_user_read(void *_packet, MYSQLND *conn TSRMLS_DC)
        */
 
        /* Should be always 0x0 or ERROR_MARKER for error */
-       packet->field_count= uint1korr(p);
+       packet->response_code = uint1korr(p);
        p++;
 
        if (packet->header.size == 1 && buf[0] == EODATA_MARKER && packet->server_capabilities & CLIENT_SECURE_CONNECTION) {
@@ -1884,7 +2004,7 @@ php_mysqlnd_chg_user_read(void *_packet, MYSQLND *conn TSRMLS_DC)
                DBG_RETURN(FAIL);
        }
 
-       if (ERROR_MARKER == packet->field_count) {
+       if (ERROR_MARKER == packet->response_code) {
                php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
                                                                                 packet->error_info.error,
                                                                                 sizeof(packet->error_info.error),
@@ -1893,6 +2013,18 @@ php_mysqlnd_chg_user_read(void *_packet, MYSQLND *conn TSRMLS_DC)
                                                                                 TSRMLS_CC);
        }
        BAIL_IF_NO_MORE_DATA;
+       if (packet->response_code == 0xFE && packet->header.size > (size_t) (p - buf)) {
+               packet->new_auth_protocol = mnd_pestrdup((char *)p, FALSE);
+               packet->new_auth_protocol_len = strlen(packet->new_auth_protocol);
+               p+= packet->new_auth_protocol_len + 1; /* +1 for the \0 */
+               packet->new_auth_protocol_data_len = packet->header.size - (size_t) (p - buf);
+               if (packet->new_auth_protocol_data_len) {
+                       packet->new_auth_protocol_data = mnd_emalloc(packet->new_auth_protocol_data_len);
+                       memcpy(packet->new_auth_protocol_data, p, packet->new_auth_protocol_data_len);
+               }
+               DBG_INF_FMT("The server requested switching auth plugin to : %s", packet->new_auth_protocol);
+               DBG_INF_FMT("Server salt : [%*s]", packet->new_auth_protocol_data_len, packet->new_auth_protocol_data);
+       }
 
        DBG_RETURN(PASS);
 premature_end:
@@ -1908,8 +2040,22 @@ premature_end:
 static void
 php_mysqlnd_chg_user_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC)
 {
+       MYSQLND_PACKET_CHG_USER_RESPONSE * p = (MYSQLND_PACKET_CHG_USER_RESPONSE *) _packet;
+
+       if (p->new_auth_protocol) {
+               mnd_efree(p->new_auth_protocol);
+               p->new_auth_protocol = NULL;
+       }
+       p->new_auth_protocol_len = 0;
+
+       if (p->new_auth_protocol_data) {
+               mnd_efree(p->new_auth_protocol_data);
+               p->new_auth_protocol_data = NULL;
+       }
+       p->new_auth_protocol_data_len = 0;
+
        if (!stack_allocation) {
-               mnd_pefree(_packet, ((MYSQLND_PACKET_CHG_USER_RESPONSE *)_packet)->header.persistent);
+               mnd_pefree(p, p->header.persistent);
        }
 }
 /* }}} */
@@ -1931,6 +2077,18 @@ mysqlnd_packet_methods packet_methods[PROT_LAST] =
                php_mysqlnd_auth_write,
                php_mysqlnd_auth_free_mem,
        }, /* PROT_AUTH_PACKET */
+       {
+               sizeof(MYSQLND_PACKET_AUTH_RESPONSE),
+               php_mysqlnd_auth_response_read, /* read */
+               NULL, /* write */
+               php_mysqlnd_auth_response_free_mem,
+       }, /* PROT_AUTH_RESP_PACKET */
+       {
+               sizeof(MYSQLND_PACKET_CHANGE_AUTH_RESPONSE),
+               NULL, /* read */
+               php_mysqlnd_change_auth_response_write, /* write */
+               php_mysqlnd_change_auth_response_free_mem,
+       }, /* PROT_CHANGE_AUTH_RESP_PACKET */
        {
                sizeof(MYSQLND_PACKET_OK),
                php_mysqlnd_ok_read, /* read */
@@ -2019,6 +2177,36 @@ MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet)(MYSQLND_PROTOCOL * const proto
 /* }}} */
 
 
+/* {{{ mysqlnd_protocol::get_auth_response_packet */
+static struct st_mysqlnd_packet_auth_response *
+MYSQLND_METHOD(mysqlnd_protocol, get_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
+{
+       struct st_mysqlnd_packet_auth_response * packet = mnd_pecalloc(1, packet_methods[PROT_AUTH_RESP_PACKET].struct_size, persistent);
+       DBG_ENTER("mysqlnd_protocol::get_auth_response_packet");
+       if (packet) {
+               packet->header.m = &packet_methods[PROT_AUTH_RESP_PACKET];
+               packet->header.persistent = persistent;
+       }
+       DBG_RETURN(packet);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_protocol::get_change_auth_response_packet */
+static struct st_mysqlnd_packet_change_auth_response *
+MYSQLND_METHOD(mysqlnd_protocol, get_change_auth_response_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
+{
+       struct st_mysqlnd_packet_change_auth_response * packet = mnd_pecalloc(1, packet_methods[PROT_CHANGE_AUTH_RESP_PACKET].struct_size, persistent);
+       DBG_ENTER("mysqlnd_protocol::get_change_auth_response_packet");
+       if (packet) {
+               packet->header.m = &packet_methods[PROT_CHANGE_AUTH_RESP_PACKET];
+               packet->header.persistent = persistent;
+       }
+       DBG_RETURN(packet);
+}
+/* }}} */
+
+
 /* {{{ mysqlnd_protocol::get_ok_packet */
 static struct st_mysqlnd_packet_ok *
 MYSQLND_METHOD(mysqlnd_protocol, get_ok_packet)(MYSQLND_PROTOCOL * const protocol, zend_bool persistent TSRMLS_DC)
@@ -2158,6 +2346,8 @@ static
 MYSQLND_CLASS_METHODS_START(mysqlnd_protocol)
        MYSQLND_METHOD(mysqlnd_protocol, get_greet_packet),
        MYSQLND_METHOD(mysqlnd_protocol, get_auth_packet),
+       MYSQLND_METHOD(mysqlnd_protocol, get_auth_response_packet),
+       MYSQLND_METHOD(mysqlnd_protocol, get_change_auth_response_packet),
        MYSQLND_METHOD(mysqlnd_protocol, get_ok_packet),
        MYSQLND_METHOD(mysqlnd_protocol, get_command_packet),
        MYSQLND_METHOD(mysqlnd_protocol, get_eof_packet),
index eb1b418166452f8b8293bc579ffc7e4fb0f9146f..7ce5ca16e1da2be7c972cd72996fa59d646dfe61 100644 (file)
@@ -82,7 +82,7 @@ typedef struct st_mysqlnd_packet_greet {
        /* If error packet, we use these */
        char            error[MYSQLND_ERRMSG_SIZE+1];
        char            sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
-       unsigned int    error_no;
+       unsigned int    error_no;
        char            *auth_protocol;
 } MYSQLND_PACKET_GREET;
 
@@ -94,10 +94,10 @@ typedef struct st_mysqlnd_packet_auth {
        uint32_t        max_packet_size;
        uint8_t         charset_no;
        const char      *user;
-       zend_uchar      *auth_data;
+       const zend_uchar        *auth_data;
        size_t          auth_data_len;
        const char      *db;
-       char            *auth_plugin_name;
+       const char      *auth_plugin_name;
        /* Here the packet ends. This is user supplied data */
        size_t          db_len;
        zend_bool       send_auth_data;
@@ -106,6 +106,36 @@ typedef struct st_mysqlnd_packet_auth {
 
 } MYSQLND_PACKET_AUTH;
 
+/* Auth response packet */
+typedef struct st_mysqlnd_packet_auth_response {
+       MYSQLND_PACKET_HEADER           header;
+       uint8_t         response_code;
+       uint64_t        affected_rows;
+       uint64_t        last_insert_id;
+       uint16_t        server_status;
+       uint16_t        warning_count;
+       char            *message;
+       size_t          message_len;
+       /* If error packet, we use these */
+       char            error[MYSQLND_ERRMSG_SIZE+1];
+       char            sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
+       unsigned int    error_no;
+
+       char            *new_auth_protocol;
+       size_t          new_auth_protocol_len;
+       zend_uchar      *new_auth_protocol_data;
+       size_t          new_auth_protocol_data_len;
+} MYSQLND_PACKET_AUTH_RESPONSE;
+
+
+/* Auth response packet */
+typedef struct st_mysqlnd_packet_change_auth_response {
+       MYSQLND_PACKET_HEADER           header;
+       const zend_uchar        *auth_data;
+       size_t                          auth_data_len;
+} MYSQLND_PACKET_CHANGE_AUTH_RESPONSE;
+
+
 /* OK packet */
 typedef struct st_mysqlnd_packet_ok {
        MYSQLND_PACKET_HEADER           header;
@@ -127,7 +157,7 @@ typedef struct st_mysqlnd_packet_ok {
 typedef struct st_mysqlnd_packet_command {
        MYSQLND_PACKET_HEADER                   header;
        enum php_mysqlnd_server_command command;
-       const char                                              *argument;
+       const zend_uchar                                *argument;
        size_t                                                  arg_len;
 } MYSQLND_PACKET_COMMAND;
 
@@ -241,13 +271,18 @@ typedef struct st_mysqlnd_packet_prepare_response {
 /* Statistics packet */
 typedef struct st_mysqlnd_packet_chg_user_resp {
        MYSQLND_PACKET_HEADER   header;
-       uint32_t                        field_count;
+       uint32_t                        response_code;
 
        /* message_len is not part of the packet*/
        uint16_t                        server_capabilities;
        /* If error packet, we use these */
        MYSQLND_ERROR_INFO      error_info;
        zend_bool                       server_asked_323_auth;
+
+       char            *new_auth_protocol;
+       size_t          new_auth_protocol_len;
+       zend_uchar      *new_auth_protocol_data;
+       size_t          new_auth_protocol_data_len;
 } MYSQLND_PACKET_CHG_USER_RESPONSE;