diff options
author | Andrey Hristov <andrey@php.net> | 2015-11-10 14:25:06 +0100 |
---|---|---|
committer | Andrey Hristov <andrey@php.net> | 2015-11-12 16:19:16 +0100 |
commit | 2e3fc57c5c205e352a805830fd3ec4c7dbfa2efa (patch) | |
tree | 871b7179fb291215280c53c7b4cdead0964cfb4d /ext/mysqlnd/mysqlnd_auth.c | |
parent | e8ace2d4db77789f1d8ae452c008a2b952dbe29d (diff) | |
download | php-git-2e3fc57c5c205e352a805830fd3ec4c7dbfa2efa.tar.gz |
MNDR:
- move things out of mysqlnd_priv.h
Diffstat (limited to 'ext/mysqlnd/mysqlnd_auth.c')
-rw-r--r-- | ext/mysqlnd/mysqlnd_auth.c | 207 |
1 files changed, 205 insertions, 2 deletions
diff --git a/ext/mysqlnd/mysqlnd_auth.c b/ext/mysqlnd/mysqlnd_auth.c index e7d44becc3..fb70884df8 100644 --- a/ext/mysqlnd/mysqlnd_auth.c +++ b/ext/mysqlnd/mysqlnd_auth.c @@ -12,20 +12,223 @@ | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Authors: Georg Richter <georg@mysql.com> | - | Andrey Hristov <andrey@mysql.com> | + | Authors: Andrey Hristov <andrey@mysql.com> | | Ulf Wendel <uwendel@mysql.com> | + | Georg Richter <georg@mysql.com> | +----------------------------------------------------------------------+ */ #include "php.h" #include "mysqlnd.h" #include "mysqlnd_structs.h" +#include "mysqlnd_auth.h" #include "mysqlnd_wireprotocol.h" +#include "mysqlnd_connection.h" #include "mysqlnd_priv.h" #include "mysqlnd_charset.h" #include "mysqlnd_debug.h" +static const char * const mysqlnd_old_passwd = "mysqlnd cannot connect to MySQL 4.1+ using the old insecure authentication. " +"Please use an administration tool to reset your password with the command SET PASSWORD = PASSWORD('your_existing_password'). This will " +"store a new, and more secure, hash value in mysql.user. If this user is used in other scripts executed by PHP 5.2 or earlier you might need to remove the old-passwords " +"flag from your my.cnf file"; + + +/* {{{ mysqlnd_run_authentication */ +enum_func_status +mysqlnd_run_authentication( + MYSQLND_CONN_DATA * conn, + const char * const user, + const char * const passwd, + const size_t passwd_len, + const char * const db, + const size_t db_len, + const MYSQLND_STRING auth_plugin_data, + const char * const auth_protocol, + unsigned int charset_no, + const MYSQLND_SESSION_OPTIONS * const session_options, + zend_ulong mysql_flags, + zend_bool silent, + zend_bool is_change_user + ) +{ + enum_func_status ret = FAIL; + 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; + + DBG_ENTER("mysqlnd_run_authentication"); + + 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.s, plugin_data_len); + plugin_data[plugin_data_len] = '\0'; + + requested_protocol = mnd_pestrdup(auth_protocol? auth_protocol : MYSQLND_DEFAULT_AUTH_PROTOCOL, FALSE); + if (!requested_protocol) { + goto end; + } + + do { + struct st_mysqlnd_authentication_plugin * auth_plugin = conn->m->fetch_auth_plugin_by_name(requested_protocol); + + if (!auth_plugin) { + php_error_docref(NULL, 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 unknown to the client"); + goto end; + } + DBG_INF("plugin found"); + + { + 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->authentication_plugin_data.s) { + mnd_pefree(conn->authentication_plugin_data.s, conn->persistent); + conn->authentication_plugin_data.s = NULL; + } + 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->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() */ + scrambled_data = + auth_plugin->methods.get_auth_data(NULL, &scrambled_data_len, conn, user, passwd, passwd_len, + plugin_data, plugin_data_len, session_options, + conn->protocol_frame_codec->data, mysql_flags); + if (conn->error_info->error_no) { + goto end; + } + if (FALSE == is_change_user) { + ret = mysqlnd_auth_handshake(conn, user, passwd, passwd_len, db, db_len, session_options, mysql_flags, + 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 + ); + } else { + ret = mysqlnd_auth_change_user(conn, user, strlen(user), passwd, passwd_len, db, db_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 + ); + } + 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 && switch_to_auth_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 (ret == PASS) { + DBG_INF_FMT("saving requested_protocol=%s", requested_protocol); + conn->m->set_client_option(conn, MYSQLND_OPT_AUTH_PROTOCOL, requested_protocol); + } +end: + if (plugin_data) { + mnd_efree(plugin_data); + } + if (requested_protocol) { + mnd_efree(requested_protocol); + } + + DBG_RETURN(ret); +} +/* }}} */ + + +/* {{{ mysqlnd_switch_to_ssl_if_needed */ +static enum_func_status +mysqlnd_switch_to_ssl_if_needed(MYSQLND_CONN_DATA * conn, + 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; + 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; + } + + { + size_t client_capabilities = mysql_flags; + 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); + command->free_command(command); + } + } + DBG_RETURN(ret); +} +/* }}} */ + + +/* {{{ mysqlnd_connect_run_authentication */ +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 + ) +{ + enum_func_status ret = FAIL; + DBG_ENTER("mysqlnd_connect_run_authentication"); + + 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, + authentication_plugin_data, authentication_protocol, + charset_no, session_options, mysql_flags, FALSE /*silent*/, FALSE/*is_change*/); + } + DBG_RETURN(ret); +} +/* }}} */ + + /* {{{ mysqlnd_auth_handshake */ enum_func_status mysqlnd_auth_handshake(MYSQLND_CONN_DATA * conn, |