summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2013-01-25 10:20:45 +0100
committerSergei Golubchik <sergii@pisem.net>2013-01-25 10:20:45 +0100
commitde10e214115ecc89087386ecad8bddee2a1e1608 (patch)
tree7920f7d3b1d8ff90329b00177a8cc4242368d87b /sql
parent746152959a8787f3c7cf6b1c710fc1ee6c54419f (diff)
parent9142c50b0751c1ee964b9b56ef2378fc2bef202c (diff)
downloadmariadb-git-de10e214115ecc89087386ecad8bddee2a1e1608.tar.gz
5.2 merge
Diffstat (limited to 'sql')
-rw-r--r--sql/sql_acl.cc48
-rw-r--r--sql/sql_class.cc1
-rw-r--r--sql/sql_class.h1
-rw-r--r--sql/sql_parse.cc17
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
{