diff options
author | Sergei Golubchik <sergii@pisem.net> | 2013-01-25 10:20:45 +0100 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2013-01-25 10:20:45 +0100 |
commit | de10e214115ecc89087386ecad8bddee2a1e1608 (patch) | |
tree | 7920f7d3b1d8ff90329b00177a8cc4242368d87b /sql | |
parent | 746152959a8787f3c7cf6b1c710fc1ee6c54419f (diff) | |
parent | 9142c50b0751c1ee964b9b56ef2378fc2bef202c (diff) | |
download | mariadb-git-de10e214115ecc89087386ecad8bddee2a1e1608.tar.gz |
5.2 merge
Diffstat (limited to 'sql')
-rw-r--r-- | sql/sql_acl.cc | 48 | ||||
-rw-r--r-- | sql/sql_class.cc | 1 | ||||
-rw-r--r-- | sql/sql_class.h | 1 | ||||
-rw-r--r-- | sql/sql_parse.cc | 17 |
4 files changed, 58 insertions, 9 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index c06453fb19f..31af9f1c137 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7058,6 +7058,7 @@ struct MPVIO_EXT : public MYSQL_PLUGIN_VIO } cached_server_packet; int packets_read, packets_written; ///< counters for send/received packets uint connect_errors; ///< if there were connect errors for this host + bool make_it_fail; /** when plugin returns a failure this tells us what really happened */ enum { SUCCESS, FAILURE, RESTART } status; }; @@ -7324,14 +7325,14 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio, /** Finds acl entry in user database for authentication purposes. - Finds a user and copies it into mpvio. Reports an authentication - failure if a user is not found. + Finds a user and copies it into mpvio. Creates a fake user + if no matching user account is found. @note find_acl_user is not the same, because it doesn't take into account the case when user is not empty, but acl_user->user is empty @retval 0 found - @retval 1 not found + @retval 1 error */ static bool find_mpvio_user(MPVIO_EXT *mpvio, Security_context *sctx) @@ -7353,8 +7354,27 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio, Security_context *sctx) if (!mpvio->acl_user) { - login_failed_error(mpvio->thd); - return 1; + /* + A matching user was not found. Fake it. Take any user, make the + authentication fail later. + This way we get a realistically looking failure, with occasional + "change auth plugin" requests even for nonexistent users. The ratio + of "change auth plugin" request will be the same for real and + nonexistent users. + Note, that we cannot pick any user at random, it must always be + the same user account for the incoming sctx->user name. + */ + ulong nr1=1, nr2=4; + CHARSET_INFO *cs= &my_charset_latin1; + cs->coll->hash_sort(cs, (uchar*) sctx->user, strlen(sctx->user), &nr1, &nr2); + + pthread_mutex_lock(&acl_cache->lock); + uint i= nr1 % acl_users.elements; + ACL_USER *acl_user_tmp= dynamic_element(&acl_users, i, ACL_USER*); + mpvio->acl_user= acl_user_tmp->copy(mpvio->thd->mem_root); + pthread_mutex_unlock(&acl_cache->lock); + + mpvio->make_it_fail= true; } /* user account requires non-default plugin and the client is too old */ @@ -7473,6 +7493,7 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length) } #ifndef NO_EMBEDDED_ACCESS_CHECKS + thd->password= passwd_len > 0; if (find_mpvio_user(mpvio, sctx)) return 1; @@ -7763,8 +7784,8 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, mpvio->cached_server_packet.pkt_len)) return packet_error; - passwd_len= my_net_read(&mpvio->thd->net); - passwd = (char*)mpvio->thd->net.read_pos; + passwd_len= my_net_read(&thd->net); + passwd= (char*)thd->net.read_pos; } *buff= (uchar*)passwd; @@ -7868,6 +7889,10 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf) *buf= (uchar*)mpvio->cached_client_reply.pkt; mpvio->cached_client_reply.pkt= 0; mpvio->packets_read++; + + if (mpvio->make_it_fail) + goto err; + return (int)mpvio->cached_client_reply.pkt_len; } /* @@ -7901,13 +7926,19 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf) else *buf = mpvio->thd->net.read_pos; + if (mpvio->make_it_fail) + goto err; + return (int)pkt_len; err: if (mpvio->status == MPVIO_EXT::FAILURE && !mpvio->thd->is_error()) { inc_host_errors(&mpvio->thd->net.vio->remote.sin_addr); - my_error(ER_HANDSHAKE_ERROR, MYF(0)); + if (mpvio->make_it_fail) + login_failed_error(mpvio->thd); + else + my_error(ER_HANDSHAKE_ERROR, MYF(0)); } return -1; } @@ -8116,6 +8147,7 @@ bool acl_authenticate(THD *thd, uint connect_errors, mpvio.thd= thd; mpvio.connect_errors= connect_errors; mpvio.status= MPVIO_EXT::FAILURE; + mpvio.make_it_fail= false; if (command == COM_CHANGE_USER) { diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 8d24e8a83e0..1d3fbec1156 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -678,6 +678,7 @@ THD::THD() examined_row_count(0), global_read_lock(0), global_disable_checkpoint(0), + failed_com_change_user(0), is_fatal_error(0), transaction_rollback_request(0), is_fatal_sub_stmt_error(0), diff --git a/sql/sql_class.h b/sql/sql_class.h index 5224c2ecf47..4c8fe9cd164 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -2032,6 +2032,7 @@ public: bool no_errors, password; bool extra_port; /* If extra connection */ + uint8 failed_com_change_user; /** Set to TRUE if execution of the current compound statement can not continue. In particular, disables activation of diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5489e96d05c..1c16e055d30 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1138,6 +1138,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, uint save_db_length= thd->db_length; char *save_db= thd->db; + int rc; USER_CONN *save_user_connect= thd->user_connect; Security_context save_security_ctx= *thd->security_ctx; CHARSET_INFO *save_character_set_client= @@ -1151,7 +1152,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->security_ctx->user= 0; thd->user_connect= 0; - if (acl_authenticate(thd, 0, packet_length)) + /* + to limit COM_CHANGE_USER ability to brute-force passwords, + we only allow three unsuccessful COM_CHANGE_USER per connection. + */ + if (thd->failed_com_change_user >= 3) + { + my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); + rc= 1; + } + else + rc= acl_authenticate(thd, 0, packet_length); + + if (rc) { /* Free user if allocated by acl_authenticate */ x_free(thd->security_ctx->user); @@ -1164,6 +1177,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->variables.collation_connection= save_collation_connection; thd->variables.character_set_results= save_character_set_results; thd->update_charset(); + thd->failed_com_change_user++; + my_sleep(1000000); } else { |