summaryrefslogtreecommitdiff
path: root/sql/sql_acl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_acl.cc')
-rw-r--r--sql/sql_acl.cc1427
1 files changed, 1107 insertions, 320 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 41163ee629e..77c467b7dcf 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -44,11 +44,11 @@
#include "transaction.h"
#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
#include "records.h" // init_read_record, end_read_record
-#include "hostname.h"
-#include "sql_db.h"
-#include "sql_connect.h"
#include <sql_common.h>
#include <mysql/plugin_auth.h>
+#include "sql_connect.h"
+#include "hostname.h"
+#include "sql_db.h"
bool mysql_user_table_is_in_short_password_format= false;
@@ -180,17 +180,17 @@ static LEX_STRING old_password_plugin_name= {
/// @todo make it configurable
LEX_STRING *default_auth_plugin_name= &native_password_plugin_name;
-static plugin_ref native_password_plugin;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
static plugin_ref old_password_plugin;
#endif
+static plugin_ref native_password_plugin;
/* Classes */
struct acl_host_and_ip
{
char *hostname;
- long ip,ip_mask; // Used with masked ip:s
+ long ip, ip_mask; // Used with masked ip:s
};
class ACL_ACCESS {
@@ -215,7 +215,7 @@ public:
uint hostname_length;
USER_RESOURCES user_resource;
char *user;
- uint8 salt[SCRAMBLE_LENGTH+1]; // scrambled password in binary form
+ uint8 salt[SCRAMBLE_LENGTH + 1]; // scrambled password in binary form
uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 4.0, 20 - 4.1.1
enum SSL_type ssl_type;
const char *ssl_cipher, *x509_issuer, *x509_subject;
@@ -224,7 +224,7 @@ public:
ACL_USER *copy(MEM_ROOT *root)
{
- ACL_USER *dst= (ACL_USER *)alloc_root(root, sizeof(ACL_USER));
+ ACL_USER *dst= (ACL_USER *) alloc_root(root, sizeof(ACL_USER));
if (!dst)
return 0;
*dst= *this;
@@ -237,7 +237,7 @@ public:
dst->plugin= plugin;
else
dst->plugin.str= strmake_root(root, plugin.str, plugin.length);
- dst->auth_string.str = safe_strdup_root(root, auth_string.str);
+ dst->auth_string.str= safe_strdup_root(root, auth_string.str);
dst->host.hostname= safe_strdup_root(root, host.hostname);
return dst;
}
@@ -250,7 +250,253 @@ public:
char *user,*db;
};
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
+static void update_hostname(acl_host_and_ip *host, const char *hostname);
+static ulong get_sort(uint count,...);
+static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
+ const char *ip);
+static bool show_proxy_grants (THD *thd, LEX_USER *user,
+ char *buff, size_t buffsize);
+
+class ACL_PROXY_USER :public ACL_ACCESS
+{
+ acl_host_and_ip host;
+ const char *user;
+ acl_host_and_ip proxied_host;
+ const char *proxied_user;
+ bool with_grant;
+
+ typedef enum {
+ MYSQL_PROXIES_PRIV_HOST,
+ MYSQL_PROXIES_PRIV_USER,
+ MYSQL_PROXIES_PRIV_PROXIED_HOST,
+ MYSQL_PROXIES_PRIV_PROXIED_USER,
+ MYSQL_PROXIES_PRIV_WITH_GRANT,
+ MYSQL_PROXIES_PRIV_GRANTOR,
+ MYSQL_PROXIES_PRIV_TIMESTAMP } old_acl_proxy_users;
+public:
+ ACL_PROXY_USER () {};
+
+ void init(const char *host_arg, const char *user_arg,
+ const char *proxied_host_arg, const char *proxied_user_arg,
+ bool with_grant_arg)
+ {
+ user= (user_arg && *user_arg) ? user_arg : NULL;
+ update_hostname (&host,
+ (host_arg && *host_arg) ? host_arg : NULL);
+ proxied_user= (proxied_user_arg && *proxied_user_arg) ?
+ proxied_user_arg : NULL;
+ update_hostname (&proxied_host,
+ (proxied_host_arg && *proxied_host_arg) ?
+ proxied_host_arg : NULL);
+ with_grant= with_grant_arg;
+ sort= get_sort(4, host.hostname, user,
+ proxied_host.hostname, proxied_user);
+ }
+
+ void init(MEM_ROOT *mem, const char *host_arg, const char *user_arg,
+ const char *proxied_host_arg, const char *proxied_user_arg,
+ bool with_grant_arg)
+ {
+ init ((host_arg && *host_arg) ? strdup_root (mem, host_arg) : NULL,
+ (user_arg && *user_arg) ? strdup_root (mem, user_arg) : NULL,
+ (proxied_host_arg && *proxied_host_arg) ?
+ strdup_root (mem, proxied_host_arg) : NULL,
+ (proxied_user_arg && *proxied_user_arg) ?
+ strdup_root (mem, proxied_user_arg) : NULL,
+ with_grant_arg);
+ }
+
+ void init(TABLE *table, MEM_ROOT *mem)
+ {
+ init (get_field(mem, table->field[MYSQL_PROXIES_PRIV_HOST]),
+ get_field(mem, table->field[MYSQL_PROXIES_PRIV_USER]),
+ get_field(mem, table->field[MYSQL_PROXIES_PRIV_PROXIED_HOST]),
+ get_field(mem, table->field[MYSQL_PROXIES_PRIV_PROXIED_USER]),
+ table->field[MYSQL_PROXIES_PRIV_WITH_GRANT]->val_int() != 0);
+ }
+
+ bool get_with_grant() { return with_grant; }
+ const char *get_user() { return user; }
+ const char *get_host() { return host.hostname; }
+ const char *get_proxied_user() { return proxied_user; }
+ const char *get_proxied_host() { return proxied_host.hostname; }
+ void set_user(MEM_ROOT *mem, const char *user_arg)
+ {
+ user= user_arg && *user_arg ? strdup_root(mem, user_arg) : NULL;
+ }
+ void set_host(MEM_ROOT *mem, const char *host_arg)
+ {
+ update_hostname(&host,
+ (host_arg && *host_arg) ?
+ strdup_root(mem, host_arg) : NULL);
+ }
+
+ bool check_validity(bool check_no_resolve)
+ {
+ if (check_no_resolve &&
+ (hostname_requires_resolving(host.hostname) ||
+ hostname_requires_resolving(proxied_host.hostname)))
+ {
+ sql_print_warning("'proxies_priv' entry '%s@%s %s@%s' "
+ "ignored in --skip-name-resolve mode.",
+ proxied_user ? proxied_user : "",
+ proxied_host.hostname ? proxied_host.hostname : "",
+ user ? user : "",
+ host.hostname ? host.hostname : "");
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ bool matches(const char *host_arg, const char *user_arg, const char *ip_arg,
+ const char *proxied_user_arg)
+ {
+ DBUG_ENTER("ACL_PROXY_USER::matches");
+ DBUG_PRINT("info", ("compare_hostname(%s,%s,%s) &&"
+ "compare_hostname(%s,%s,%s) &&"
+ "wild_compare (%s,%s) &&"
+ "wild_compare (%s,%s)",
+ host.hostname ? host.hostname : "<NULL>",
+ host_arg ? host_arg : "<NULL>",
+ ip_arg ? ip_arg : "<NULL>",
+ proxied_host.hostname ? proxied_host.hostname : "<NULL>",
+ host_arg ? host_arg : "<NULL>",
+ ip_arg ? ip_arg : "<NULL>",
+ user_arg ? user_arg : "<NULL>",
+ user ? user : "<NULL>",
+ proxied_user_arg ? proxied_user_arg : "<NULL>",
+ proxied_user ? proxied_user : "<NULL>"));
+ DBUG_RETURN(compare_hostname(&host, host_arg, ip_arg) &&
+ compare_hostname(&proxied_host, host_arg, ip_arg) &&
+ (!user ||
+ (user_arg && !wild_compare(user_arg, user, TRUE))) &&
+ (!proxied_user ||
+ (proxied_user && !wild_compare(proxied_user_arg,
+ proxied_user, TRUE))));
+ }
+
+
+ inline static bool auth_element_equals(const char *a, const char *b)
+ {
+ return (a == b || (a != NULL && b != NULL && !strcmp(a,b)));
+ }
+
+
+ bool pk_equals(ACL_PROXY_USER *grant)
+ {
+ DBUG_ENTER("pk_equals");
+ DBUG_PRINT("info", ("strcmp(%s,%s) &&"
+ "strcmp(%s,%s) &&"
+ "wild_compare (%s,%s) &&"
+ "wild_compare (%s,%s)",
+ user ? user : "<NULL>",
+ grant->user ? grant->user : "<NULL>",
+ proxied_user ? proxied_user : "<NULL>",
+ grant->proxied_user ? grant->proxied_user : "<NULL>",
+ host.hostname ? host.hostname : "<NULL>",
+ grant->host.hostname ? grant->host.hostname : "<NULL>",
+ proxied_host.hostname ? proxied_host.hostname : "<NULL>",
+ grant->proxied_host.hostname ?
+ grant->proxied_host.hostname : "<NULL>"));
+
+ DBUG_RETURN(auth_element_equals(user, grant->user) &&
+ auth_element_equals(proxied_user, grant->proxied_user) &&
+ auth_element_equals(host.hostname, grant->host.hostname) &&
+ auth_element_equals(proxied_host.hostname,
+ grant->proxied_host.hostname));
+ }
+
+
+ bool granted_on(const char *host_arg, const char *user_arg)
+ {
+ return (((!user && (!user_arg || !user_arg[0])) ||
+ (user && user_arg && !strcmp(user, user_arg))) &&
+ ((!host.hostname && (!host_arg || !host_arg[0])) ||
+ (host.hostname && host_arg && !strcmp(host.hostname, host_arg))));
+ }
+
+
+ void print_grant(String *str)
+ {
+ str->append(STRING_WITH_LEN("GRANT PROXY ON '"));
+ if (proxied_user)
+ str->append(proxied_user, strlen(proxied_user));
+ str->append(STRING_WITH_LEN("'@'"));
+ if (proxied_host.hostname)
+ str->append(proxied_host.hostname, strlen(proxied_host.hostname));
+ str->append(STRING_WITH_LEN("' TO '"));
+ if (user)
+ str->append(user, strlen(user));
+ str->append(STRING_WITH_LEN("'@'"));
+ if (host.hostname)
+ str->append(host.hostname, strlen(host.hostname));
+ str->append(STRING_WITH_LEN("'"));
+ if (with_grant)
+ str->append(STRING_WITH_LEN(" WITH GRANT OPTION"));
+ }
+
+ void set_data(ACL_PROXY_USER *grant)
+ {
+ with_grant= grant->with_grant;
+ }
+
+ static int store_pk(TABLE *table,
+ const LEX_STRING *host,
+ const LEX_STRING *user,
+ const LEX_STRING *proxied_host,
+ const LEX_STRING *proxied_user)
+ {
+ DBUG_ENTER("ACL_PROXY_USER::store_pk");
+ DBUG_PRINT("info", ("host=%s, user=%s, proxied_host=%s, proxied_user=%s",
+ host->str ? host->str : "<NULL>",
+ user->str ? user->str : "<NULL>",
+ proxied_host->str ? proxied_host->str : "<NULL>",
+ proxied_user->str ? proxied_user->str : "<NULL>"));
+ if (table->field[MYSQL_PROXIES_PRIV_HOST]->store(host->str,
+ host->length,
+ system_charset_info))
+ DBUG_RETURN(TRUE);
+ if (table->field[MYSQL_PROXIES_PRIV_USER]->store(user->str,
+ user->length,
+ system_charset_info))
+ DBUG_RETURN(TRUE);
+ if (table->field[MYSQL_PROXIES_PRIV_PROXIED_HOST]->store(proxied_host->str,
+ proxied_host->length,
+ system_charset_info))
+ DBUG_RETURN(TRUE);
+ if (table->field[MYSQL_PROXIES_PRIV_PROXIED_USER]->store(proxied_user->str,
+ proxied_user->length,
+ system_charset_info))
+ DBUG_RETURN(TRUE);
+
+ DBUG_RETURN(FALSE);
+ }
+
+ static int store_data_record(TABLE *table,
+ const LEX_STRING *host,
+ const LEX_STRING *user,
+ const LEX_STRING *proxied_host,
+ const LEX_STRING *proxied_user,
+ bool with_grant,
+ const char *grantor)
+ {
+ DBUG_ENTER("ACL_PROXY_USER::store_pk");
+ if (store_pk(table, host, user, proxied_host, proxied_user))
+ DBUG_RETURN(TRUE);
+ DBUG_PRINT("info", ("with_grant=%s", with_grant ? "TRUE" : "FALSE"));
+ if (table->field[MYSQL_PROXIES_PRIV_WITH_GRANT]->store(with_grant ? 1 : 0,
+ TRUE))
+ DBUG_RETURN(TRUE);
+ if (table->field[MYSQL_PROXIES_PRIV_GRANTOR]->store(grantor,
+ strlen(grantor),
+ system_charset_info))
+ DBUG_RETURN(TRUE);
+
+ DBUG_RETURN(FALSE);
+ }
+};
#define FIRST_NON_YN_FIELD 26
@@ -270,17 +516,18 @@ static uchar* acl_entry_get_key(acl_entry *entry, size_t *length,
return (uchar*) entry->key;
}
-#define IP_ADDR_STRLEN (3+1+3+1+3+1+3)
-#define ACL_KEY_LENGTH (IP_ADDR_STRLEN+1+NAME_LEN+1+USERNAME_LENGTH+1)
+#define IP_ADDR_STRLEN (3 + 1 + 3 + 1 + 3 + 1 + 3)
+#define ACL_KEY_LENGTH (IP_ADDR_STRLEN + 1 + NAME_LEN + \
+ 1 + USERNAME_LENGTH + 1)
#if defined(HAVE_OPENSSL)
/*
Without SSL the handshake consists of one packet. This packet
- has both client capabilites and scrambled password.
+ has both client capabilities and scrambled password.
With SSL the handshake might consist of two packets. If the first
packet (client capabilities) has CLIENT_SSL flag set, we have to
switch to SSL and read the second packet. The scrambled password
- is in the second packet and client_capabilites field will be ignored.
+ is in the second packet and client_capabilities field will be ignored.
Maybe it is better to accept flags other than CLIENT_SSL from the
second packet?
*/
@@ -291,7 +538,7 @@ static uchar* acl_entry_get_key(acl_entry *entry, size_t *length,
#define MIN_HANDSHAKE_SIZE 6
#endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
-static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
+static DYNAMIC_ARRAY acl_hosts, acl_users, acl_dbs, acl_proxy_users;
static MEM_ROOT mem, memex;
static bool initialized=0;
static bool allow_all_hosts=1;
@@ -306,11 +553,9 @@ static void init_check_host(void);
static void rebuild_check_host(void);
static ACL_USER *find_acl_user(const char *host, const char *user,
my_bool exact);
-static bool update_user_table(THD *, TABLE *, const char *, const char *,
- const char *, uint);
-static void update_hostname(acl_host_and_ip *host, const char *hostname);
-static bool compare_hostname(const acl_host_and_ip *host,const char *hostname,
- const char *ip);
+static bool update_user_table(THD *thd, TABLE *table, const char *host,
+ const char *user, const char *new_password,
+ uint new_password_len);
static my_bool acl_load(THD *thd, TABLE_LIST *tables);
static my_bool grant_load(THD *thd, TABLE_LIST *tables);
static inline void get_grantor(THD *thd, char* grantor);
@@ -445,6 +690,37 @@ my_bool acl_init(bool dont_read_acl_tables)
DBUG_RETURN(return_val);
}
+/**
+ Choose from either native or old password plugins when assigning a password
+*/
+
+static bool
+set_user_plugin (ACL_USER *user, int password_len)
+{
+ switch (password_len)
+ {
+ case 0: /* no password */
+ case SCRAMBLED_PASSWORD_CHAR_LENGTH:
+ user->plugin= native_password_plugin_name;
+ return FALSE;
+ case SCRAMBLED_PASSWORD_CHAR_LENGTH_323:
+ user->plugin= old_password_plugin_name;
+ return FALSE;
+ case 45: /* 4.1: to be removed */
+ sql_print_warning("Found 4.1.0 style password for user '%s@%s'. "
+ "Ignoring user. "
+ "You should change password for this user.",
+ user->user ? user->user : "",
+ user->host.hostname ? user->host.hostname : "");
+ return TRUE;
+ default:
+ sql_print_warning("Found invalid password for user: '%s@%s'; "
+ "Ignoring user", user->user ? user->user : "",
+ user->host.hostname ? user->host.hostname : "");
+ return TRUE;
+ }
+}
+
/*
Initialize structures responsible for user/db-level privilege checking
@@ -582,9 +858,6 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
while (!(read_record_info.read_record(&read_record_info)))
{
ACL_USER user;
- char *password;
- uint password_len;
-
bzero(&user, sizeof(user));
update_hostname(&user.host, get_field(&mem, table->field[0]));
user.user= get_field(&mem, table->field[1]);
@@ -597,33 +870,14 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
continue;
}
- password= get_field(&mem, table->field[2]);
- password_len= password ? strlen(password) : 0;
+ char *password= get_field(&mem, table->field[2]);
+ uint password_len= password ? strlen(password) : 0;
user.auth_string.str= password ? password : const_cast<char*>("");
user.auth_string.length= password_len;
set_user_salt(&user, password, password_len);
- switch (password_len) {
- case 0: /* no password */
- case SCRAMBLED_PASSWORD_CHAR_LENGTH:
- user.plugin= native_password_plugin_name;
- break;
- case SCRAMBLED_PASSWORD_CHAR_LENGTH_323:
- user.plugin= old_password_plugin_name;
- break;
- case 45: /* 4.1: to be removed */
- sql_print_warning("Found 4.1.0 style password for user '%s@%s'. "
- "Ignoring user. "
- "You should change password for this user.",
- user.user ? user.user : "",
- user.host.hostname ? user.host.hostname : "");
- continue;
- default:
- sql_print_warning("Found invalid password for user: '%s@%s'; "
- "Ignoring user", user.user ? user.user : "",
- user.host.hostname ? user.host.hostname : "");
+ if (set_user_plugin(&user, password_len))
continue;
- }
{
uint next_field;
@@ -816,6 +1070,38 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
sizeof(ACL_DB),(qsort_cmp) acl_compare);
end_read_record(&read_record_info);
freeze_size(&acl_dbs);
+
+ (void) my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER),
+ 50, 100);
+ if (tables[3].table)
+ {
+ init_read_record(&read_record_info, thd, table= tables[3].table, NULL, 1,
+ 0, FALSE);
+ table->use_all_columns();
+ while (!(read_record_info.read_record(&read_record_info)))
+ {
+ ACL_PROXY_USER proxy;
+ proxy.init(table, &mem);
+ if (proxy.check_validity(check_no_resolve))
+ continue;
+ if (push_dynamic(&acl_proxy_users, (uchar*) &proxy))
+ {
+ end_read_record(&read_record_info);
+ goto end;
+ }
+ }
+ my_qsort((uchar*) dynamic_element(&acl_proxy_users, 0, ACL_PROXY_USER*),
+ acl_proxy_users.elements,
+ sizeof(ACL_PROXY_USER), (qsort_cmp) acl_compare);
+ end_read_record(&read_record_info);
+ }
+ else
+ {
+ sql_print_error("Missing system table mysql.proxies_priv; "
+ "please run mysql_upgrade to create it");
+ }
+ freeze_size(&acl_proxy_users);
+
init_check_host();
initialized=1;
@@ -834,6 +1120,7 @@ void acl_free(bool end)
delete_dynamic(&acl_users);
delete_dynamic(&acl_dbs);
delete_dynamic(&acl_wild_hosts);
+ delete_dynamic(&acl_proxy_users);
my_hash_free(&acl_check_hosts);
plugin_unlock(0, native_password_plugin);
plugin_unlock(0, old_password_plugin);
@@ -868,8 +1155,8 @@ void acl_free(bool end)
my_bool acl_reload(THD *thd)
{
- TABLE_LIST tables[3];
- DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs;
+ TABLE_LIST tables[4];
+ DYNAMIC_ARRAY old_acl_hosts, old_acl_users, old_acl_dbs, old_acl_proxy_users;
MEM_ROOT old_mem;
bool old_initialized;
my_bool return_val= TRUE;
@@ -885,9 +1172,15 @@ my_bool acl_reload(THD *thd)
C_STRING_WITH_LEN("user"), "user", TL_READ);
tables[2].init_one_table(C_STRING_WITH_LEN("mysql"),
C_STRING_WITH_LEN("db"), "db", TL_READ);
- tables[0].next_local= tables[0].next_global= tables+1;
- tables[1].next_local= tables[1].next_global= tables+2;
- tables[0].open_type= tables[1].open_type= tables[2].open_type= OT_BASE_ONLY;
+ tables[3].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("proxies_priv"),
+ "proxies_priv", TL_READ);
+ tables[0].next_local= tables[0].next_global= tables + 1;
+ tables[1].next_local= tables[1].next_global= tables + 2;
+ tables[2].next_local= tables[2].next_global= tables + 3;
+ tables[0].open_type= tables[1].open_type= tables[2].open_type=
+ tables[3].open_type= OT_BASE_ONLY;
+ tables[3].open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
{
@@ -904,10 +1197,11 @@ my_bool acl_reload(THD *thd)
if ((old_initialized=initialized))
mysql_mutex_lock(&acl_cache->lock);
- old_acl_hosts=acl_hosts;
- old_acl_users=acl_users;
- old_acl_dbs=acl_dbs;
- old_mem=mem;
+ old_acl_hosts= acl_hosts;
+ old_acl_users= acl_users;
+ old_acl_proxy_users= acl_proxy_users;
+ old_acl_dbs= acl_dbs;
+ old_mem= mem;
delete_dynamic(&acl_wild_hosts);
my_hash_free(&acl_check_hosts);
@@ -915,10 +1209,11 @@ my_bool acl_reload(THD *thd)
{ // Error. Revert to old list
DBUG_PRINT("error",("Reverting to old privileges"));
acl_free(); /* purecov: inspected */
- acl_hosts=old_acl_hosts;
- acl_users=old_acl_users;
- acl_dbs=old_acl_dbs;
- mem=old_mem;
+ acl_hosts= old_acl_hosts;
+ acl_users= old_acl_users;
+ acl_proxy_users= old_acl_proxy_users;
+ acl_dbs= old_acl_dbs;
+ mem= old_mem;
init_check_host();
}
else
@@ -926,6 +1221,7 @@ my_bool acl_reload(THD *thd)
free_root(&old_mem,MYF(0));
delete_dynamic(&old_acl_hosts);
delete_dynamic(&old_acl_users);
+ delete_dynamic(&old_acl_proxy_users);
delete_dynamic(&old_acl_dbs);
}
if (old_initialized)
@@ -1172,6 +1468,7 @@ static void acl_update_user(const char *user, const char *host,
if (fix_user_plugin_ptr(acl_user))
acl_user->plugin.str= strmake_root(&mem, plugin->str, plugin->length);
}
+#if 0
else
if (password)
{
@@ -1179,6 +1476,7 @@ static void acl_update_user(const char *user, const char *host,
acl_user->auth_string.length= password_len;
set_user_salt(acl_user, password, password_len);
}
+#endif
acl_user->access=privileges;
if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
acl_user->user_resource.questions=mqh->questions;
@@ -1198,6 +1496,8 @@ static void acl_update_user(const char *user, const char *host,
acl_user->x509_subject= (x509_subject ?
strdup_root(&mem,x509_subject) : 0);
}
+ if (password)
+ set_user_salt(acl_user, password, password_len);
/* search complete: */
break;
}
@@ -1238,7 +1538,6 @@ static void acl_insert_user(const char *user, const char *host,
old_password_plugin_name : native_password_plugin_name;
acl_user.auth_string.str= strmake_root(&mem, password, password_len);
acl_user.auth_string.length= password_len;
- set_user_salt(&acl_user, password, password_len);
}
acl_user.access=privileges;
@@ -1251,6 +1550,8 @@ static void acl_insert_user(const char *user, const char *host,
acl_user.x509_issuer= x509_issuer ? strdup_root(&mem,x509_issuer) : 0;
acl_user.x509_subject=x509_subject ? strdup_root(&mem,x509_subject) : 0;
+ set_user_salt(&acl_user, password, password_len);
+
(void) push_dynamic(&acl_users,(uchar*) &acl_user);
if (!acl_user.host.hostname ||
(acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1]))
@@ -1635,6 +1936,7 @@ bool change_password(THD *thd, const char *host, const char *user,
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
goto end;
}
+
/* update loaded acl entry: */
if (acl_user->plugin.str == native_password_plugin_name.str ||
acl_user->plugin.str == old_password_plugin_name.str)
@@ -1642,7 +1944,11 @@ bool change_password(THD *thd, const char *host, const char *user,
acl_user->auth_string.str= strmake_root(&mem, new_password, new_password_len);
acl_user->auth_string.length= new_password_len;
set_user_salt(acl_user, new_password, new_password_len);
+ set_user_plugin(acl_user, new_password_len);
}
+ else
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_SET_PASSWORD_AUTH_PLUGIN, ER(ER_SET_PASSWORD_AUTH_PLUGIN));
if (update_user_table(thd, table,
acl_user->host.hostname ? acl_user->host.hostname : "",
@@ -2024,15 +2330,14 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
see also test_if_create_new_users()
*/
- else if (!password_len && no_auto_create)
+ else if (!password_len && !combo.plugin.length && no_auto_create)
{
- my_error(ER_PASSWORD_NO_MATCH, MYF(0), combo.user.str, combo.host.str);
+ my_error(ER_PASSWORD_NO_MATCH, MYF(0));
goto end;
}
else if (!can_create_user)
{
- my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0),
- thd->security_ctx->user, thd->security_ctx->host_or_ip);
+ my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0));
goto end;
}
else if (combo.plugin.str[0])
@@ -2057,6 +2362,15 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
{
old_row_exists = 1;
store_record(table,record[1]); // Save copy for update
+#if 0
+ /* what == 'N' means revoke */
+ if (combo.plugin.length && what != 'N')
+ {
+ my_error(ER_GRANT_PLUGIN_USER_EXISTS, MYF(0),
+ static_cast<int>(combo.user.length), combo.user.str);
+ goto end;
+ }
+#endif
if (combo.password.str) // If password given
table->field[2]->store(password, password_len, system_charset_info);
else if (!rights && !revoke_grant &&
@@ -2139,13 +2453,15 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
table->field[next_field+3]->store((longlong) mqh.user_conn, TRUE);
mqh_used= mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour;
- next_field+=4;
+ next_field+= 4;
if (table->s->fields >= 41 && combo.plugin.str[0])
{
table->field[next_field]->store(combo.plugin.str, combo.plugin.length,
- system_charset_info);
- table->field[next_field+1]->store(combo.auth.str, combo.auth.length,
- system_charset_info);
+ system_charset_info);
+ table->field[next_field]->set_notnull();
+ table->field[next_field + 1]->store(combo.auth.str, combo.auth.length,
+ system_charset_info);
+ table->field[next_field + 1]->set_notnull();
}
}
@@ -2319,6 +2635,164 @@ abort:
}
+static void
+acl_update_proxy_user(ACL_PROXY_USER *new_value, bool is_revoke)
+{
+ mysql_mutex_assert_owner(&acl_cache->lock);
+
+ DBUG_ENTER("acl_update_proxy_user");
+ for (uint i= 0; i < acl_proxy_users.elements; i++)
+ {
+ ACL_PROXY_USER *acl_user=
+ dynamic_element(&acl_proxy_users, i, ACL_PROXY_USER *);
+
+ if (acl_user->pk_equals(new_value))
+ {
+ if (is_revoke)
+ {
+ DBUG_PRINT("info", ("delting ACL_PROXY_USER"));
+ delete_dynamic_element(&acl_proxy_users, i);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("updating ACL_PROXY_USER"));
+ acl_user->set_data(new_value);
+ }
+ break;
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+
+static void
+acl_insert_proxy_user(ACL_PROXY_USER *new_value)
+{
+ DBUG_ENTER("acl_insert_proxy_user");
+ mysql_mutex_assert_owner(&acl_cache->lock);
+ (void) push_dynamic(&acl_proxy_users, (uchar *) new_value);
+ my_qsort((uchar*) dynamic_element(&acl_proxy_users, 0, ACL_PROXY_USER *),
+ acl_proxy_users.elements,
+ sizeof(ACL_PROXY_USER), (qsort_cmp) acl_compare);
+ DBUG_VOID_RETURN;
+}
+
+
+static int
+replace_proxies_priv_table(THD *thd, TABLE *table, const LEX_USER *user,
+ const LEX_USER *proxied_user, bool with_grant_arg,
+ bool revoke_grant)
+{
+ bool old_row_exists= 0;
+ int error;
+ uchar user_key[MAX_KEY_LENGTH];
+ ACL_PROXY_USER new_grant;
+ char grantor[USER_HOST_BUFF_SIZE];
+
+ DBUG_ENTER("replace_proxies_priv_table");
+
+ if (!initialized)
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
+ DBUG_RETURN(-1);
+ }
+
+ /* Check if there is such a user in user table in memory? */
+ if (!find_acl_user(user->host.str,user->user.str, FALSE))
+ {
+ my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ table->use_all_columns();
+ ACL_PROXY_USER::store_pk (table, &user->host, &user->user,
+ &proxied_user->host, &proxied_user->user);
+
+ key_copy(user_key, table->record[0], table->key_info,
+ table->key_info->key_length);
+
+ get_grantor(thd, grantor);
+
+ table->file->ha_index_init(0, 1);
+ if (table->file->index_read_map(table->record[0], user_key,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
+ {
+ DBUG_PRINT ("info", ("Row not found"));
+ if (revoke_grant)
+ { // no row, no revoke
+ my_error(ER_NONEXISTING_GRANT, MYF(0), user->user.str, user->host.str);
+ goto abort;
+ }
+ old_row_exists= 0;
+ restore_record(table, s->default_values);
+ ACL_PROXY_USER::store_data_record(table, &user->host, &user->user,
+ &proxied_user->host,
+ &proxied_user->user,
+ with_grant_arg,
+ grantor);
+ }
+ else
+ {
+ DBUG_PRINT("info", ("Row found"));
+ old_row_exists= 1;
+ store_record(table, record[1]);
+ }
+
+ if (old_row_exists)
+ {
+ /* update old existing row */
+ if (!revoke_grant)
+ {
+ if ((error= table->file->ha_update_row(table->record[1],
+ table->record[0])) &&
+ error != HA_ERR_RECORD_IS_THE_SAME)
+ goto table_error; /* purecov: inspected */
+ }
+ else
+ {
+ if ((error= table->file->ha_delete_row(table->record[1])))
+ goto table_error; /* purecov: inspected */
+ }
+ }
+ else if ((error= table->file->ha_write_row(table->record[0])))
+ {
+ DBUG_PRINT("info", ("error inserting the row"));
+ if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
+ goto table_error; /* purecov: inspected */
+ }
+
+ acl_cache->clear(1); // Clear privilege cache
+ if (old_row_exists)
+ {
+ new_grant.init(user->host.str, user->user.str,
+ proxied_user->host.str, proxied_user->user.str,
+ with_grant_arg);
+ acl_update_proxy_user(&new_grant, revoke_grant);
+ }
+ else
+ {
+ new_grant.init(&mem, user->host.str, user->user.str,
+ proxied_user->host.str, proxied_user->user.str,
+ with_grant_arg);
+ acl_insert_proxy_user(&new_grant);
+ }
+
+ table->file->ha_index_end();
+ DBUG_RETURN(0);
+
+ /* This could only happen if the grant tables got corrupted */
+table_error:
+ DBUG_PRINT("info", ("table error"));
+ table->file->print_error(error, MYF(0)); /* purecov: inspected */
+
+abort:
+ DBUG_PRINT("info", ("aborting replace_proxies_priv_table"));
+ table->file->ha_index_end();
+ DBUG_RETURN(-1);
+}
+
+
class GRANT_COLUMN :public Sql_alloc
{
public:
@@ -3221,6 +3695,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
{ // Should never happen
/* Restore the state of binlog format */
DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
+ thd->lex->restore_backup_query_tables_list(&backup);
if (save_binlog_row_based)
thd->set_current_stmt_binlog_format_row();
DBUG_RETURN(TRUE); /* purecov: deadcode */
@@ -3535,10 +4010,10 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
- ulong rights, bool revoke_grant)
+ ulong rights, bool revoke_grant, bool is_proxy)
{
List_iterator <LEX_USER> str_list (list);
- LEX_USER *Str, *tmp_Str;
+ LEX_USER *Str, *tmp_Str, *proxied_user= NULL;
char tmp_db[SAFE_NAME_LEN+1];
bool create_new_users=0;
TABLE_LIST tables[2];
@@ -3558,11 +4033,26 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
db=tmp_db;
}
- /* open the mysql.user and mysql.db tables */
+ if (is_proxy)
+ {
+ DBUG_ASSERT(!db);
+ proxied_user= str_list++;
+ }
+
+ /* open the mysql.user and mysql.db or mysql.proxies_priv tables */
tables[0].init_one_table(C_STRING_WITH_LEN("mysql"),
C_STRING_WITH_LEN("user"), "user", TL_WRITE);
- tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
- C_STRING_WITH_LEN("db"), "db", TL_WRITE);
+ if (is_proxy)
+
+ tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("proxies_priv"),
+ "proxies_priv",
+ TL_WRITE);
+ else
+ tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("db"),
+ "db",
+ TL_WRITE);
tables[0].next_local= tables[0].next_global= tables+1;
/*
@@ -3648,6 +4138,13 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
result= -1;
}
}
+ else if (is_proxy)
+ {
+ if (replace_proxies_priv_table (thd, tables[1].table, Str, proxied_user,
+ rights & GRANT_ACL ? TRUE : FALSE,
+ revoke_grant))
+ result= -1;
+ }
}
mysql_mutex_unlock(&acl_cache->lock);
@@ -4070,7 +4567,8 @@ end:
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
bool any_combination_will_do, uint number, bool no_errors)
{
- TABLE_LIST *table, *first_not_own_table= thd->lex->first_not_own_table();
+ TABLE_LIST *tl;
+ TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table();
Security_context *sctx= thd->security_ctx;
uint i;
ulong orig_want_access= want_access;
@@ -4087,34 +4585,32 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
the given table list refers to the list for prelocking (contains tables
of other queries). For simple queries first_not_own_table is 0.
*/
- for (i= 0, table= tables;
- i < number && table != first_not_own_table;
- table= table->next_global, i++)
+ for (i= 0, tl= tables;
+ i < number && tl != first_not_own_table;
+ tl= tl->next_global, i++)
{
/*
Save a copy of the privileges without the SHOW_VIEW_ACL attribute.
It will be checked during making view.
*/
- table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
+ tl->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
}
mysql_rwlock_rdlock(&LOCK_grant);
- for (table= tables;
- table && number-- && table != first_not_own_table;
- table= table->next_global)
+ for (tl= tables;
+ tl && number-- && tl != first_not_own_table;
+ tl= tl->next_global)
{
- GRANT_TABLE *grant_table;
- sctx = test(table->security_ctx) ?
- table->security_ctx : thd->security_ctx;
+ sctx = test(tl->security_ctx) ? tl->security_ctx : thd->security_ctx;
- const ACL_internal_table_access *access;
- access= get_cached_table_access(&table->grant.m_internal,
- table->get_db_name(),
- table->get_table_name());
+ const ACL_internal_table_access *access=
+ get_cached_table_access(&tl->grant.m_internal,
+ tl->get_db_name(),
+ tl->get_table_name());
if (access)
{
- switch(access->check(orig_want_access, &table->grant.privilege))
+ switch(access->check(orig_want_access, &tl->grant.privilege))
{
case ACL_INTERNAL_ACCESS_GRANTED:
/*
@@ -4138,29 +4634,33 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
if (!want_access)
continue; // ok
- if (!(~table->grant.privilege & want_access) ||
- table->is_anonymous_derived_table() || table->schema_table)
+ if (!(~tl->grant.privilege & want_access) ||
+ tl->is_anonymous_derived_table() || tl->schema_table)
{
/*
- It is subquery in the FROM clause. VIEW set table->derived after
+ It is subquery in the FROM clause. VIEW set tl->derived after
table opening, but this function always called before table opening.
*/
- if (!table->referencing_view)
+ if (!tl->referencing_view)
{
/*
If it's a temporary table created for a subquery in the FROM
clause, or an INFORMATION_SCHEMA table, drop the request for
a privilege.
*/
- table->grant.want_privilege= 0;
+ tl->grant.want_privilege= 0;
}
continue;
}
- if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
- table->get_db_name(), sctx->priv_user,
- table->get_table_name(), FALSE)))
+ GRANT_TABLE *grant_table= table_hash_search(sctx->host, sctx->ip,
+ tl->get_db_name(),
+ sctx->priv_user,
+ tl->get_table_name(),
+ FALSE);
+
+ if (!grant_table)
{
- want_access &= ~table->grant.privilege;
+ want_access &= ~tl->grant.privilege;
goto err; // No grants
}
@@ -4171,18 +4671,17 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
if (any_combination_will_do)
continue;
- table->grant.grant_table=grant_table; // Remember for column test
- table->grant.version=grant_version;
- table->grant.privilege|= grant_table->privs;
- table->grant.want_privilege= ((want_access & COL_ACLS)
- & ~table->grant.privilege);
+ tl->grant.grant_table= grant_table; // Remember for column test
+ tl->grant.version= grant_version;
+ tl->grant.privilege|= grant_table->privs;
+ tl->grant.want_privilege= ((want_access & COL_ACLS) & ~tl->grant.privilege);
- if (!(~table->grant.privilege & want_access))
+ if (!(~tl->grant.privilege & want_access))
continue;
- if (want_access & ~(grant_table->cols | table->grant.privilege))
+ if (want_access & ~(grant_table->cols | tl->grant.privilege))
{
- want_access &= ~(grant_table->cols | table->grant.privilege);
+ want_access &= ~(grant_table->cols | tl->grant.privilege);
goto err; // impossible
}
}
@@ -4201,7 +4700,7 @@ err:
command,
sctx->priv_user,
sctx->host_or_ip,
- table ? table->get_table_name() : "unknown");
+ tl ? tl->get_table_name() : "unknown");
}
DBUG_RETURN(TRUE);
}
@@ -5093,6 +5592,12 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
goto end;
}
+ if (show_proxy_grants(thd, lex_user, buff, sizeof(buff)))
+ {
+ error= -1;
+ goto end;
+ }
+
end:
mysql_mutex_unlock(&acl_cache->lock);
mysql_rwlock_unlock(&LOCK_grant);
@@ -5250,7 +5755,7 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc)
< 0 Error.
*/
-#define GRANT_TABLES 5
+#define GRANT_TABLES 6
int open_grant_tables(THD *thd, TABLE_LIST *tables)
{
DBUG_ENTER("open_grant_tables");
@@ -5274,10 +5779,16 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables)
(tables+4)->init_one_table(C_STRING_WITH_LEN("mysql"),
C_STRING_WITH_LEN("procs_priv"),
"procs_priv", TL_WRITE);
- tables->next_local= tables->next_global= tables+1;
- (tables+1)->next_local= (tables+1)->next_global= tables+2;
- (tables+2)->next_local= (tables+2)->next_global= tables+3;
- (tables+3)->next_local= (tables+3)->next_global= tables+4;
+ (tables+5)->init_one_table(C_STRING_WITH_LEN("mysql"),
+ C_STRING_WITH_LEN("proxies_priv"),
+ "proxies_priv", TL_WRITE);
+ tables[5].open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
+
+ tables->next_local= tables->next_global= tables + 1;
+ (tables+1)->next_local= (tables+1)->next_global= tables + 2;
+ (tables+2)->next_local= (tables+2)->next_global= tables + 3;
+ (tables+3)->next_local= (tables+3)->next_global= tables + 4;
+ (tables+4)->next_local= (tables+4)->next_global= tables + 5;
#ifdef HAVE_REPLICATION
/*
@@ -5290,12 +5801,12 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables)
The tables must be marked "updating" so that tables_ok() takes them into
account in tests.
*/
- tables[0].updating=tables[1].updating=tables[2].updating=
- tables[3].updating=tables[4].updating=1;
+ tables[0].updating= tables[1].updating= tables[2].updating=
+ tables[3].updating= tables[4].updating= tables[5].updating= 1;
if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
DBUG_RETURN(1);
- tables[0].updating=tables[1].updating=tables[2].updating=
- tables[3].updating=tables[4].updating=0;;
+ tables[0].updating= tables[1].updating= tables[2].updating=
+ tables[3].updating= tables[4].updating= tables[5].updating= 0;
}
#endif
@@ -5424,7 +5935,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
int error;
TABLE *table= tables[table_no].table;
Field *host_field= table->field[0];
- Field *user_field= table->field[table_no ? 2 : 1];
+ Field *user_field= table->field[table_no && table_no != 5 ? 2 : 1];
char *host_str= user_from->host.str;
char *user_str= user_from->user.str;
const char *host;
@@ -5507,12 +6018,15 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
user= "";
#ifdef EXTRA_DEBUG
- DBUG_PRINT("loop",("scan fields: '%s'@'%s' '%s' '%s' '%s'",
- user, host,
- get_field(thd->mem_root, table->field[1]) /*db*/,
- get_field(thd->mem_root, table->field[3]) /*table*/,
- get_field(thd->mem_root,
- table->field[4]) /*column*/));
+ if (table_no != 5)
+ {
+ DBUG_PRINT("loop",("scan fields: '%s'@'%s' '%s' '%s' '%s'",
+ user, host,
+ get_field(thd->mem_root, table->field[1]) /*db*/,
+ get_field(thd->mem_root, table->field[3]) /*table*/,
+ get_field(thd->mem_root,
+ table->field[4]) /*column*/));
+ }
#endif
if (strcmp(user_str, user) ||
my_strcasecmp(system_charset_info, host_str, host))
@@ -5535,18 +6049,15 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
}
-/*
+/**
Handle an in-memory privilege structure.
- SYNOPSIS
- handle_grant_struct()
- struct_no The number of the structure to handle (0..3).
- drop If user_from is to be dropped.
- user_from The the user to be searched/dropped/renamed.
- user_to The new name for the user if to be renamed,
- NULL otherwise.
+ @param struct_no The number of the structure to handle (0..5).
+ @param drop If user_from is to be dropped.
+ @param user_from The the user to be searched/dropped/renamed.
+ @param user_to The new name for the user if to be renamed, NULL otherwise.
- DESCRIPTION
+ @note
Scan through all elements in an in-memory grant structure and apply
the requested operation.
Delete from grant structure if drop is true.
@@ -5556,12 +6067,13 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
0 acl_users
1 acl_dbs
2 column_priv_hash
- 3 procs_priv_hash
+ 3 proc_priv_hash
+ 4 func_priv_hash
+ 5 acl_proxy_users
- RETURN
- > 0 At least one element matched.
- 0 OK, but no element matched.
- -1 Wrong arguments to function
+ @retval > 0 At least one element matched.
+ @retval 0 OK, but no element matched.
+ @retval -1 Wrong arguments to function.
*/
static int handle_grant_struct(uint struct_no, bool drop,
@@ -5574,7 +6086,9 @@ static int handle_grant_struct(uint struct_no, bool drop,
const char *host;
ACL_USER *acl_user= NULL;
ACL_DB *acl_db= NULL;
+ ACL_PROXY_USER *acl_proxy_user= NULL;
GRANT_NAME *grant_name= NULL;
+ HASH *grant_name_hash= NULL;
DBUG_ENTER("handle_grant_struct");
DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'",
struct_no, user_from->user.str, user_from->host.str));
@@ -5594,9 +6108,18 @@ static int handle_grant_struct(uint struct_no, bool drop,
break;
case 2:
elements= column_priv_hash.records;
+ grant_name_hash= &column_priv_hash;
break;
case 3:
elements= proc_priv_hash.records;
+ grant_name_hash= &proc_priv_hash;
+ break;
+ case 4:
+ elements= func_priv_hash.records;
+ grant_name_hash= &func_priv_hash;
+ break;
+ case 5:
+ elements= acl_proxy_users.elements;
break;
default:
return -1;
@@ -5626,16 +6149,19 @@ static int handle_grant_struct(uint struct_no, bool drop,
break;
case 2:
- grant_name= (GRANT_NAME*) my_hash_element(&column_priv_hash, idx);
+ case 3:
+ case 4:
+ grant_name= (GRANT_NAME*) my_hash_element(grant_name_hash, idx);
user= grant_name->user;
host= grant_name->host.hostname;
break;
- case 3:
- grant_name= (GRANT_NAME*) my_hash_element(&proc_priv_hash, idx);
- user= grant_name->user;
- host= grant_name->host.hostname;
+ case 5:
+ acl_proxy_user= dynamic_element(&acl_proxy_users, idx, ACL_PROXY_USER*);
+ user= acl_proxy_user->get_user();
+ host= acl_proxy_user->get_host();
break;
+
default:
DBUG_ASSERT(0);
}
@@ -5665,14 +6191,30 @@ static int handle_grant_struct(uint struct_no, bool drop,
break;
case 2:
- my_hash_delete(&column_priv_hash, (uchar*) grant_name);
- break;
-
case 3:
- my_hash_delete(&proc_priv_hash, (uchar*) grant_name);
+ case 4:
+ my_hash_delete(grant_name_hash, (uchar*) grant_name);
break;
+
+ case 5:
+ delete_dynamic_element(&acl_proxy_users, idx);
+ break;
+
}
elements--;
+ /*
+ - If we are iterating through an array then we just have moved all
+ elements after the current element one position closer to its head.
+ This means that we have to take another look at the element at
+ current position as it is a new element from the array's tail.
+ - If we are iterating through a hash the current element was replaced
+ with one of elements from the tail. So we also have to take a look
+ at the new element in current position.
+ Note that in our HASH implementation hash_delete() won't move any
+ elements with position after current one to position before the
+ current (i.e. from the tail to the head), so it is safe to continue
+ iteration without re-starting.
+ */
idx--;
}
else if ( user_to )
@@ -5690,22 +6232,47 @@ static int handle_grant_struct(uint struct_no, bool drop,
case 2:
case 3:
- /*
- Update the grant structure with the new user name and
- host name
- */
- grant_name->set_user_details(user_to->host.str, grant_name->db,
- user_to->user.str, grant_name->tname,
- TRUE);
+ case 4:
+ {
+ /*
+ Save old hash key and its length to be able properly update
+ element position in hash.
+ */
+ char *old_key= grant_name->hash_key;
+ size_t old_key_length= grant_name->key_length;
+
+ /*
+ Update the grant structure with the new user name and host name.
+ */
+ grant_name->set_user_details(user_to->host.str, grant_name->db,
+ user_to->user.str, grant_name->tname,
+ TRUE);
+
+ /*
+ Since username is part of the hash key, when the user name
+ is renamed, the hash key is changed. Update the hash to
+ ensure that the position matches the new hash key value
+ */
+ my_hash_update(grant_name_hash, (uchar*) grant_name, (uchar*) old_key,
+ old_key_length);
+ /*
+ hash_update() operation could have moved element from the tail
+ of the hash to the current position. So we need to take a look
+ at the element in current position once again.
+ Thanks to the fact that hash_update() for our HASH implementation
+ won't move any elements from the tail of the hash to the positions
+ before the current one (a.k.a. head) it is safe to continue
+ iteration without restarting.
+ */
+ idx--;
+ break;
+ }
+
+ case 5:
+ acl_proxy_user->set_user (&mem, user_to->user.str);
+ acl_proxy_user->set_host (&mem, user_to->host.str);
+ break;
- /*
- Since username is part of the hash key, when the user name
- is renamed, the hash key is changed. Update the hash to
- ensure that the position matches the new hash key value
- */
- my_hash_update(&column_priv_hash, (uchar*) grant_name,
- (uchar*) grant_name->hash_key, grant_name->key_length);
- break;
}
}
else
@@ -5791,7 +6358,7 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop,
}
}
- /* Handle procedures table. */
+ /* Handle stored routines table. */
if ((found= handle_grant_table(tables, 4, drop, user_from, user_to)) < 0)
{
/* Handle of table failed, don't touch in-memory array. */
@@ -5808,6 +6375,15 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop,
if (! drop && ! user_to)
goto end;
}
+ /* Handle funcs array. */
+ if (((handle_grant_struct(4, drop, user_from, user_to) && ! result) ||
+ found) && ! result)
+ {
+ result= 1; /* At least one record/element found. */
+ /* If search is requested, we do not need to search further. */
+ if (! drop && ! user_to)
+ goto end;
+ }
}
/* Handle tables table. */
@@ -5840,6 +6416,23 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop,
result= 1; /* At least one record/element found. */
}
}
+
+ /* Handle proxies_priv table. */
+ if (tables[5].table)
+ {
+ if ((found= handle_grant_table(tables, 5, drop, user_from, user_to)) < 0)
+ {
+ /* Handle of table failed, don't touch the in-memory array. */
+ result= -1;
+ }
+ else
+ {
+ /* Handle proxies_priv array. */
+ if ((handle_grant_struct(5, drop, user_from, user_to) && !result) ||
+ found)
+ result= 1; /* At least one record/element found. */
+ }
+ }
end:
DBUG_RETURN(result);
}
@@ -6596,6 +7189,129 @@ template class List<LEX_COLUMN>;
template class List<LEX_USER>;
#endif
+/**
+ Validate if a user can proxy as another user
+
+ @thd current thread
+ @param user the logged in user (proxy user)
+ @param authenticated_as the effective user a plugin is trying to
+ impersonate as (proxied user)
+ @return proxy user definition
+ @retval NULL proxy user definition not found or not applicable
+ @retval non-null the proxy user data
+*/
+
+static ACL_PROXY_USER *
+acl_find_proxy_user(const char *user, const char *host, const char *ip,
+ const char *authenticated_as, bool *proxy_used)
+{
+ uint i;
+ /* if the proxied and proxy user are the same return OK */
+ DBUG_ENTER("acl_find_proxy_user");
+ DBUG_PRINT("info", ("user=%s host=%s ip=%s authenticated_as=%s",
+ user, host, ip, authenticated_as));
+
+ if (!strcmp(authenticated_as, user))
+ {
+ DBUG_PRINT ("info", ("user is the same as authenticated_as"));
+ DBUG_RETURN (NULL);
+ }
+
+ *proxy_used= TRUE;
+ for (i=0; i < acl_proxy_users.elements; i++)
+ {
+ ACL_PROXY_USER *proxy= dynamic_element(&acl_proxy_users, i,
+ ACL_PROXY_USER *);
+ if (proxy->matches(host, user, ip, authenticated_as))
+ DBUG_RETURN(proxy);
+ }
+
+ DBUG_RETURN(NULL);
+}
+
+
+bool
+acl_check_proxy_grant_access(THD *thd, const char *host, const char *user,
+ bool with_grant)
+{
+ DBUG_ENTER("acl_check_proxy_grant_access");
+ DBUG_PRINT("info", ("user=%s host=%s with_grant=%d", user, host,
+ (int) with_grant));
+ if (!initialized)
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
+ DBUG_RETURN(1);
+ }
+
+ /* replication slave thread can do anything */
+ if (thd->slave_thread)
+ {
+ DBUG_PRINT("info", ("replication slave"));
+ DBUG_RETURN(FALSE);
+ }
+
+ /* one can grant proxy to himself to others */
+ if (!strcmp(thd->security_ctx->user, user) &&
+ !my_strcasecmp(system_charset_info, host,
+ thd->security_ctx->host))
+ {
+ DBUG_PRINT("info", ("strcmp (%s, %s) my_casestrcmp (%s, %s) equal",
+ thd->security_ctx->user, user,
+ host, thd->security_ctx->host));
+ DBUG_RETURN(FALSE);
+ }
+
+ /* check for matching WITH PROXY rights */
+ for (uint i=0; i < acl_proxy_users.elements; i++)
+ {
+ ACL_PROXY_USER *proxy= dynamic_element(&acl_proxy_users, i,
+ ACL_PROXY_USER *);
+ if (proxy->matches(thd->security_ctx->host,
+ thd->security_ctx->user,
+ thd->security_ctx->ip,
+ user) &&
+ proxy->get_with_grant())
+ {
+ DBUG_PRINT("info", ("found"));
+ DBUG_RETURN(FALSE);
+ }
+ }
+
+ my_error(ER_ACCESS_DENIED_NO_PASSWORD_ERROR, MYF(0),
+ thd->security_ctx->user,
+ thd->security_ctx->host_or_ip);
+ DBUG_RETURN(TRUE);
+}
+
+
+static bool
+show_proxy_grants(THD *thd, LEX_USER *user, char *buff, size_t buffsize)
+{
+ Protocol *protocol= thd->protocol;
+ int error= 0;
+
+ for (uint i=0; i < acl_proxy_users.elements; i++)
+ {
+ ACL_PROXY_USER *proxy= dynamic_element(&acl_proxy_users, i,
+ ACL_PROXY_USER *);
+ if (proxy->granted_on(user->host.str, user->user.str))
+ {
+ String global(buff, buffsize, system_charset_info);
+ global.length(0);
+ proxy->print_grant(&global);
+ protocol->prepare_for_resend();
+ protocol->store(global.ptr(), global.length(), global.charset());
+ if (protocol->write())
+ {
+ error= -1;
+ break;
+ }
+ }
+ }
+ return error;
+}
+
+
#endif /*NO_EMBEDDED_ACCESS_CHECKS */
@@ -7183,18 +7899,17 @@ get_cached_table_access(GRANT_INTERNAL_INFO *grant_internal_info,
#ifndef HAVE_OPENSSL
#define ssl_acceptor_fd 0
#define sslaccept(A,B,C,D) 1
-#define NORMAL_HANDSHAKE_SIZE 6
#endif
/**
The internal version of what plugins know as MYSQL_PLUGIN_VIO,
basically the context of the authentication session
*/
-struct MPVIO_EXT : public MYSQL_PLUGIN_VIO
+struct MPVIO_EXT :public MYSQL_PLUGIN_VIO
{
MYSQL_SERVER_AUTH_INFO auth_info;
THD *thd;
- ACL_USER *acl_user; ///< a copy, independent from acl_users array
+ const ACL_USER *acl_user; ///< a copy, independent from acl_users array
plugin_ref plugin; ///< what plugin we're under
LEX_STRING db; ///< db name from the handshake packet
/** when restarting a plugin this caches the last client reply */
@@ -7213,18 +7928,16 @@ struct MPVIO_EXT : public MYSQL_PLUGIN_VIO
enum { SUCCESS, FAILURE, RESTART } status;
};
-
/**
a helper function to report an access denied error in all the proper places
*/
-
-static void login_failed_error(THD *thd, bool passwd_used)
+static void login_failed_error(THD *thd, int passwd_used)
{
- my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
+ my_error(access_denied_error_code(passwd_used), MYF(0),
thd->main_security_ctx.user,
thd->main_security_ctx.host_or_ip,
passwd_used ? ER(ER_YES) : ER(ER_NO));
- general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
+ general_log_print(thd, COM_CONNECT, ER(access_denied_error_code(passwd_used)),
thd->main_security_ctx.user,
thd->main_security_ctx.host_or_ip,
passwd_used ? ER(ER_YES) : ER(ER_NO));
@@ -7236,14 +7949,13 @@ static void login_failed_error(THD *thd, bool passwd_used)
*/
if (global_system_variables.log_warnings > 1)
{
- sql_print_warning(ER(ER_ACCESS_DENIED_ERROR),
+ sql_print_warning(ER(access_denied_error_code(passwd_used)),
thd->main_security_ctx.user,
thd->main_security_ctx.host_or_ip,
passwd_used ? ER(ER_YES) : ER(ER_NO));
}
}
-
/**
sends a server handshake initialization packet, the very first packet
after the connection was established
@@ -7269,7 +7981,6 @@ static void login_failed_error(THD *thd, bool passwd_used)
@retval 0 ok
@retval 1 error
*/
-
static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
const char *data, uint data_len)
{
@@ -7277,14 +7988,26 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
DBUG_ASSERT(data_len <= 255);
THD *thd= mpvio->thd;
- char *buff= (char *)my_alloca(1 + SERVER_VERSION_LENGTH + 1 + data_len + 64);
+ char *buff= (char *) my_alloca(1 + SERVER_VERSION_LENGTH + 1 + data_len + 64);
char scramble_buf[SCRAMBLE_LENGTH];
char *end= buff;
+ DBUG_ENTER("send_server_handshake_packet");
*end++= protocol_version;
thd->client_capabilities= CLIENT_BASIC_FLAGS;
+ if (opt_using_transactions)
+ thd->client_capabilities|= CLIENT_TRANSACTIONS;
+
+ thd->client_capabilities|= CAN_CLIENT_COMPRESS;
+
+ if (ssl_acceptor_fd)
+ {
+ thd->client_capabilities |= CLIENT_SSL;
+ thd->client_capabilities |= CLIENT_SSL_VERIFY_SERVER_CERT;
+ }
+
if (data_len)
{
mpvio->cached_server_packet.pkt= (char*)thd->memdup(data, data_len);
@@ -7294,12 +8017,13 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
if (data_len < SCRAMBLE_LENGTH)
{
if (data_len)
- { /*
+ {
+ /*
the first packet *must* have at least 20 bytes of a scramble.
if a plugin provided less, we pad it to 20 with zeros
*/
memcpy(scramble_buf, data, data_len);
- bzero(scramble_buf+data_len, SCRAMBLE_LENGTH-data_len);
+ bzero(scramble_buf + data_len, SCRAMBLE_LENGTH - data_len);
data= scramble_buf;
}
else
@@ -7319,17 +8043,6 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
data_len= SCRAMBLE_LENGTH;
}
- if (opt_using_transactions)
- thd->client_capabilities|= CLIENT_TRANSACTIONS;
-
- thd->client_capabilities|= CAN_CLIENT_COMPRESS;
-
- if (ssl_acceptor_fd)
- {
- thd->client_capabilities |= CLIENT_SSL;
- thd->client_capabilities |= CLIENT_SSL_VERIFY_SERVER_CERT;
- }
-
end= strnmov(end, server_version, SERVER_VERSION_LENGTH) + 1;
int4store((uchar*) end, mpvio->thd->thread_id);
end+= 4;
@@ -7339,29 +8052,30 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
tail: that's why first part of the scramble is placed here, and second
part at the end of packet.
*/
- end= (char*)memcpy(end, data, SCRAMBLE_LENGTH_323);
+ end= (char*) memcpy(end, data, SCRAMBLE_LENGTH_323);
end+= SCRAMBLE_LENGTH_323;
*end++= 0;
int2store(end, thd->client_capabilities);
/* write server characteristics: up to 16 bytes allowed */
- end[2]=(char) default_charset_info->number;
+ end[2]= (char) default_charset_info->number;
int2store(end+3, mpvio->thd->server_status);
int2store(end+5, thd->client_capabilities >> 16);
end[7]= data_len;
- bzero(end+8, 10);
+ bzero(end + 8, 10);
end+= 18;
/* write scramble tail */
- end= (char*)memcpy(end, data + SCRAMBLE_LENGTH_323,
- data_len - SCRAMBLE_LENGTH_323);
+ end= (char*) memcpy(end, data + SCRAMBLE_LENGTH_323,
+ data_len - SCRAMBLE_LENGTH_323);
end+= data_len - SCRAMBLE_LENGTH_323;
end= strmake(end, plugin_name(mpvio->plugin)->str,
plugin_name(mpvio->plugin)->length);
- int res= my_net_write(&mpvio->thd->net, (uchar*) buff, (size_t) (end-buff)) ||
+ int res= my_net_write(&mpvio->thd->net, (uchar*) buff,
+ (size_t) (end - buff + 1)) ||
net_flush(&mpvio->thd->net);
my_afree(buff);
- return res;
+ DBUG_RETURN (res);
}
static bool secure_auth(THD *thd)
@@ -7411,7 +8125,6 @@ static bool secure_auth(THD *thd)
@retval 0 ok
@retval 1 error
*/
-
static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
const uchar *data, uint data_len)
{
@@ -7419,12 +8132,12 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
DBUG_ASSERT(mpvio->packets_read == 1);
NET *net= &mpvio->thd->net;
static uchar switch_plugin_request_buf[]= { 254 };
-
+ DBUG_ENTER("send_plugin_request_packet");
mpvio->status= MPVIO_EXT::FAILURE; // the status is no longer RESTART
const char *client_auth_plugin=
- ((st_mysql_auth *)(plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
+ ((st_mysql_auth *) (plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
DBUG_ASSERT(client_auth_plugin);
DBUG_ASSERT(my_strcasecmp(system_charset_info, client_auth_plugin,
@@ -7444,9 +8157,9 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
client_auth_plugin == old_password_plugin_name.str;
if (switch_from_long_to_short_scramble)
- return secure_auth(mpvio->thd) ||
- my_net_write(net, switch_plugin_request_buf, 1) ||
- net_flush(net);
+ DBUG_RETURN (secure_auth(mpvio->thd) ||
+ my_net_write(net, switch_plugin_request_buf, 1) ||
+ net_flush(net));
/*
We never request a client to switch from a short to long scramble.
@@ -7461,16 +8174,17 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
{
my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
general_log_print(mpvio->thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
- return 1;
+ DBUG_RETURN (1);
}
- return net_write_command(net, switch_plugin_request_buf[0],
- (uchar*)client_auth_plugin,
- strlen(client_auth_plugin)+1,
- (uchar*)data, data_len);
+ DBUG_PRINT("info", ("requesting client to use the %s plugin",
+ client_auth_plugin));
+ DBUG_RETURN(net_write_command(net, switch_plugin_request_buf[0],
+ (uchar*) client_auth_plugin,
+ strlen(client_auth_plugin) + 1,
+ (uchar*) data, data_len));
}
-
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/**
Finds acl entry in user database for authentication purposes.
@@ -7484,15 +8198,16 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
@retval 0 found
@retval 1 not found
*/
-
-static bool find_mpvio_user(MPVIO_EXT *mpvio, Security_context *sctx)
+static bool find_mpvio_user(MPVIO_EXT *mpvio)
{
+ Security_context *sctx= mpvio->thd->security_ctx;
+ DBUG_ENTER("find_mpvio_user");
DBUG_ASSERT(mpvio->acl_user == 0);
mysql_mutex_lock(&acl_cache->lock);
- for (uint i=0 ; i < acl_users.elements ; i++)
+ for (uint i=0; i < acl_users.elements; i++)
{
- ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
+ ACL_USER *acl_user_tmp= dynamic_element(&acl_users, i, ACL_USER*);
if ((!acl_user_tmp->user || !strcmp(sctx->user, acl_user_tmp->user)) &&
compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip))
{
@@ -7505,7 +8220,7 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio, Security_context *sctx)
if (!mpvio->acl_user)
{
login_failed_error(mpvio->thd, 0);
- return 1;
+ DBUG_RETURN (1);
}
/* user account requires non-default plugin and the client is too old */
@@ -7519,19 +8234,27 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio, Security_context *sctx)
old_password_plugin_name.str));
my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
general_log_print(mpvio->thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
- return 1;
+ DBUG_RETURN (1);
}
mpvio->auth_info.user_name= sctx->user;
+ mpvio->auth_info.user_name_length= user_len;
mpvio->auth_info.auth_string= mpvio->acl_user->auth_string.str;
+ mpvio->auth_info.auth_string_length=
+ (unsigned long) mpvio->acl_user->auth_string.length;
strmake(mpvio->auth_info.authenticated_as, mpvio->acl_user->user ?
mpvio->acl_user->user : "", USERNAME_LENGTH);
- return 0;
+ DBUG_PRINT("info", ("exit: user=%s, auth_string=%s, authenticated as=%s"
+ "plugin=%s",
+ mpvio->auth_info.user_name,
+ mpvio->auth_info.auth_string,
+ mpvio->auth_info.authenticated_as,
+ mpvio->acl_user->plugin.str));
+ DBUG_RETURN(0);
}
#endif
-
/* the packet format is described in send_change_user_packet() */
static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
{
@@ -7542,17 +8265,18 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
char *user= (char*) net->read_pos;
char *end= user + packet_length;
/* Safe because there is always a trailing \0 at the end of the packet */
- char *passwd= strend(user)+1;
+ char *passwd= strend(user) + 1;
uint user_len= passwd - user - 1;
char *db= passwd;
char db_buff[SAFE_NAME_LEN + 1]; // buffer to store db in utf8
char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
uint dummy_errors;
+ DBUG_ENTER ("parse_com_change_user_packet");
if (passwd >= end)
{
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
- return 1;
+ DBUG_RETURN (1);
}
/*
@@ -7566,7 +8290,7 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
*passwd > 127 and become 2**32-127+ after casting to uint.
*/
uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
- (uchar)(*passwd++) : strlen(passwd));
+ (uchar) (*passwd++) : strlen(passwd));
db+= passwd_len + 1;
/*
@@ -7576,37 +8300,37 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
if (db >= end)
{
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
- return 1;
+ DBUG_RETURN (1);
}
uint db_len= strlen(db);
char *ptr= db + db_len + 1;
- if (ptr+1 < end)
+ if (ptr + 1 < end)
{
- uint cs_number= uint2korr(ptr);
- thd_init_client_charset(thd, cs_number);
+ if (thd_init_client_charset(thd, uint2korr(ptr)))
+ DBUG_RETURN(1);
thd->update_charset();
}
/* Convert database and user names to utf8 */
- db_len= copy_and_convert(db_buff, sizeof(db_buff)-1, system_charset_info,
+ db_len= copy_and_convert(db_buff, sizeof(db_buff) - 1, system_charset_info,
db, db_len, thd->charset(), &dummy_errors);
- user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
+ user_len= copy_and_convert(user_buff, sizeof(user_buff) - 1,
system_charset_info, user, user_len,
thd->charset(), &dummy_errors);
if (!(sctx->user= my_strndup(user_buff, user_len, MYF(MY_WME))))
- return 1;
+ DBUG_RETURN(1);
/* Clear variables that are allocated */
thd->user_connect= 0;
strmake(sctx->priv_user, sctx->user, USERNAME_LENGTH);
if (thd->make_lex_string(&mpvio->db, db_buff, db_len, 0) == 0)
- return 1; /* The error is set by make_lex_string(). */
+ DBUG_RETURN(1); /* The error is set by make_lex_string(). */
/*
Clear thd->db as it points to something, that will be freed when
@@ -7619,12 +8343,12 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
{
// if mysqld's been started with --skip-grant-tables option
mpvio->status= MPVIO_EXT::SUCCESS;
- return 0;
+ DBUG_RETURN(0);
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (find_mpvio_user(mpvio, sctx))
- return 1;
+ if (find_mpvio_user(mpvio))
+ DBUG_RETURN(1);
char *client_plugin;
if (thd->client_capabilities & CLIENT_PLUGIN_AUTH)
@@ -7633,7 +8357,7 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
if (client_plugin >= end)
{
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
- return 1;
+ DBUG_RETURN(1);
}
client_plugin= fix_plugin_ptr(client_plugin);
}
@@ -7654,15 +8378,19 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
mpvio->acl_user->plugin= old_password_plugin_name;
}
}
-
- /* remember the data part of the packet, to present it to plugin in read_packet() */
+
+ DBUG_PRINT("info", ("client_plugin=%s, restart", client_plugin));
+ /*
+ Remember the data part of the packet, to present it to plugin in
+ read_packet()
+ */
mpvio->cached_client_reply.pkt= passwd;
mpvio->cached_client_reply.pkt_len= passwd_len;
mpvio->cached_client_reply.plugin= client_plugin;
mpvio->status= MPVIO_EXT::RESTART;
#endif
- return 0;
+ DBUG_RETURN (0);
}
@@ -7686,36 +8414,34 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
ulong client_capabilities= uint2korr(net->read_pos);
if (client_capabilities & CLIENT_PROTOCOL_41)
{
- client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
- thd->max_client_packet_length= uint4korr(net->read_pos+4);
+ client_capabilities|= ((ulong) uint2korr(net->read_pos + 2)) << 16;
+ thd->max_client_packet_length= uint4korr(net->read_pos + 4);
DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
- thd_init_client_charset(thd, (uint) net->read_pos[8]);
+ if (thd_init_client_charset(thd, (uint) net->read_pos[8]))
+ return packet_error;
thd->update_charset();
- end= (char*) net->read_pos+32;
+ end= (char*) net->read_pos + 32;
}
else
{
- thd->max_client_packet_length= uint3korr(net->read_pos+2);
- end= (char*) net->read_pos+5;
+ mpvio->max_client_packet_length= uint3korr(net->read_pos + 2);
+ end= (char*) net->read_pos + 5;
}
/* Disable those bits which are not supported by the client. */
thd->client_capabilities&= client_capabilities;
- if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
- thd->variables.sql_mode|= MODE_IGNORE_SPACE;
-
DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
if (thd->client_capabilities & CLIENT_SSL)
{
- char error_string[1024] __attribute__((unused));
+ unsigned long errptr __attribute__((unused));
/* Do the SSL layering. */
if (!ssl_acceptor_fd)
return packet_error;
DBUG_PRINT("info", ("IO layer change in progress..."));
- if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout, error_string))
+ if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout, &errptr))
{
DBUG_PRINT("error", ("Failed to accept new SSL connection"));
return packet_error;
@@ -7731,11 +8457,14 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
}
}
+ if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
+ thd->variables.sql_mode|= MODE_IGNORE_SPACE;
+ if (thd->client_capabilities & CLIENT_INTERACTIVE)
+ thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
+
if (end >= (char*) net->read_pos+ pkt_len +2)
return packet_error;
- if (thd->client_capabilities & CLIENT_INTERACTIVE)
- thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
opt_using_transactions)
net->return_status= &thd->server_status;
@@ -7781,12 +8510,12 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
/* Since 4.1 all database names are stored in utf8 */
if (db)
{
- db_len= copy_and_convert(db_buff, sizeof(db_buff)-1, system_charset_info,
+ db_len= copy_and_convert(db_buff, sizeof(db_buff) - 1, system_charset_info,
db, db_len, thd->charset(), &dummy_errors);
db= db_buff;
}
- user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
+ user_len= copy_and_convert(user_buff, sizeof(user_buff) - 1,
system_charset_info, user, user_len,
thd->charset(), &dummy_errors);
user= user_buff;
@@ -7806,6 +8535,7 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
if (!(sctx->user= my_strndup(user, user_len, MYF(MY_WME))))
return packet_error; /* The error is set by my_strdup(). */
+
/*
Clear thd->db as it points to something, that will be freed when
connection is closed. We don't want to accidentally free a wrong
@@ -7820,7 +8550,7 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
return packet_error;
}
- if (find_mpvio_user(mpvio, sctx))
+ if (find_mpvio_user(mpvio))
return packet_error;
if (thd->client_capabilities & CLIENT_PLUGIN_AUTH)
@@ -7874,22 +8604,22 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
doesn't need to know.
*/
const char *client_auth_plugin=
- ((st_mysql_auth *)(plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
+ ((st_mysql_auth *) (plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
if (client_auth_plugin &&
my_strcasecmp(system_charset_info, client_plugin, client_auth_plugin))
{
mpvio->cached_client_reply.plugin= client_plugin;
if (send_plugin_request_packet(mpvio,
- (uchar*)mpvio->cached_server_packet.pkt,
+ (uchar*) mpvio->cached_server_packet.pkt,
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= (char*)mpvio->thd->net.read_pos;
}
- *buff= (uchar*)passwd;
+ *buff= (uchar*) passwd;
return passwd_len;
#else
return 0;
@@ -7907,18 +8637,19 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
and handles plugin negotiation with the client. If necessary,
it escapes the plugin data, if it starts with a mysql protocol packet byte.
*/
-
static int server_mpvio_write_packet(MYSQL_PLUGIN_VIO *param,
const uchar *packet, int packet_len)
{
- MPVIO_EXT *mpvio= (MPVIO_EXT*)param;
+ MPVIO_EXT *mpvio= (MPVIO_EXT *) param;
int res;
+ DBUG_ENTER("server_mpvio_write_packet");
/* reset cached_client_reply */
mpvio->cached_client_reply.pkt= 0;
+
/* for the 1st packet we wrap plugin data into the handshake packet */
if (mpvio->packets_written == 0)
- res= send_server_handshake_packet(mpvio, (char*)packet, packet_len);
+ res= send_server_handshake_packet(mpvio, (char*) packet, packet_len);
else if (mpvio->status == MPVIO_EXT::RESTART)
res= send_plugin_request_packet(mpvio, packet, packet_len);
else if (packet_len > 0 && (*packet == 1 || *packet == 255 || *packet == 254))
@@ -7938,10 +8669,9 @@ static int server_mpvio_write_packet(MYSQL_PLUGIN_VIO *param,
net_flush(&mpvio->thd->net);
}
mpvio->packets_written++;
- return res;
+ DBUG_RETURN(res);
}
-
/**
vio->read_packet() callback method for server authentication plugins
@@ -7952,12 +8682,11 @@ static int server_mpvio_write_packet(MYSQL_PLUGIN_VIO *param,
a client authentication handshake packet, and handles plugin negotiation
with the client, if necessary.
*/
-
static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
{
- MPVIO_EXT *mpvio= (MPVIO_EXT*)param;
+ MPVIO_EXT *mpvio= (MPVIO_EXT *) param;
ulong pkt_len;
-
+ DBUG_ENTER("server_mpvio_read_packet");
if (mpvio->packets_written == 0)
{
/*
@@ -7969,8 +8698,7 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
else
pkt_len= my_net_read(&mpvio->thd->net);
}
- else
- if (mpvio->cached_client_reply.pkt)
+ else if (mpvio->cached_client_reply.pkt)
{
DBUG_ASSERT(mpvio->status == MPVIO_EXT::RESTART);
DBUG_ASSERT(mpvio->packets_read > 0);
@@ -7981,17 +8709,18 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
cached data straight away and avoid one round trip.
*/
const char *client_auth_plugin=
- ((st_mysql_auth *)(plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
+ ((st_mysql_auth *) (plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
if (client_auth_plugin == 0 ||
my_strcasecmp(system_charset_info, mpvio->cached_client_reply.plugin,
client_auth_plugin) == 0)
{
mpvio->status= MPVIO_EXT::FAILURE;
- *buf= (uchar*)mpvio->cached_client_reply.pkt;
+ *buf= (uchar*) mpvio->cached_client_reply.pkt;
mpvio->cached_client_reply.pkt= 0;
mpvio->packets_read++;
- return (int)mpvio->cached_client_reply.pkt_len;
+ DBUG_RETURN ((int) mpvio->cached_client_reply.pkt_len);
}
+
/*
But if the client has used the wrong plugin, the cached data are
useless. Furthermore, we have to send a "change plugin" request
@@ -8021,39 +8750,36 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
goto err;
}
else
- *buf = mpvio->thd->net.read_pos;
+ *buf= mpvio->thd->net.read_pos;
- return (int)pkt_len;
+ DBUG_RETURN((int)pkt_len);
err:
- if (mpvio->status == MPVIO_EXT::FAILURE && !mpvio->thd->is_error())
+ if (mpvio->status == MPVIO_EXT::FAILURE)
{
- inc_host_errors(mpvio->thd->main_security_ctx.ip);
- my_error(ER_HANDSHAKE_ERROR, MYF(0),
- mpvio->thd->security_ctx->host_or_ip);
+ inc_host_errors(mpvio->thd->security_ctx.ip);
+ if (!mpvio->thd->is_error())
+ my_error(ER_HANDSHAKE_ERROR, MYF(0));
}
- return -1;
+ DBUG_RETURN(-1);
}
-
/**
fills MYSQL_PLUGIN_VIO_INFO structure with the information about the
connection
*/
-
static void server_mpvio_info(MYSQL_PLUGIN_VIO *vio,
MYSQL_PLUGIN_VIO_INFO *info)
{
- MPVIO_EXT *mpvio= (MPVIO_EXT*)vio;
+ MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
mpvio_info(mpvio->thd->net.vio, info);
}
-
-static bool acl_check_ssl(THD *thd, ACL_USER *acl_user)
+static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user)
{
-#if defined(HAVE_OPENSSL)
- Vio *vio=thd->net.vio;
- SSL *ssl= (SSL*) vio->ssl_arg;
+#ifdef HAVE_OPENSSL
+ Vio *vio= thd->net.vio;
+ SSL *ssl= (SSL *) vio->ssl_arg;
X509 *cert;
#endif
@@ -8067,7 +8793,7 @@ static bool acl_check_ssl(THD *thd, ACL_USER *acl_user)
case SSL_TYPE_NOT_SPECIFIED: // Impossible
case SSL_TYPE_NONE: // SSL is not required
return 0;
-#if defined(HAVE_OPENSSL)
+#ifdef HAVE_OPENSSL
case SSL_TYPE_ANY: // Any kind of SSL is ok
return vio_type(vio) != VIO_TYPE_SSL;
case SSL_TYPE_X509: /* Client should have any valid certificate. */
@@ -8093,9 +8819,9 @@ static bool acl_check_ssl(THD *thd, ACL_USER *acl_user)
return 1;
if (acl_user->ssl_cipher)
{
- DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
- acl_user->ssl_cipher,SSL_get_cipher(ssl)));
- if (strcmp(acl_user->ssl_cipher,SSL_get_cipher(ssl)))
+ DBUG_PRINT("info", ("comparing ciphers: '%s' and '%s'",
+ acl_user->ssl_cipher, SSL_get_cipher(ssl)));
+ if (strcmp(acl_user->ssl_cipher, SSL_get_cipher(ssl)))
{
if (global_system_variables.log_warnings)
sql_print_information("X509 ciphers mismatch: should be '%s' but is '%s'",
@@ -8109,8 +8835,8 @@ static bool acl_check_ssl(THD *thd, ACL_USER *acl_user)
/* If X509 issuer is specified, we check it... */
if (acl_user->x509_issuer)
{
- char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
- DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
+ char *ptr= X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
+ DBUG_PRINT("info", ("comparing issuers: '%s' and '%s'",
acl_user->x509_issuer, ptr));
if (strcmp(acl_user->x509_issuer, ptr))
{
@@ -8127,9 +8853,9 @@ static bool acl_check_ssl(THD *thd, ACL_USER *acl_user)
if (acl_user->x509_subject)
{
char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
- DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
+ DBUG_PRINT("info", ("comparing subjects: '%s' and '%s'",
acl_user->x509_subject, ptr));
- if (strcmp(acl_user->x509_subject,ptr))
+ if (strcmp(acl_user->x509_subject, ptr))
{
if (global_system_variables.log_warnings)
sql_print_information("X509 subject mismatch: should be '%s' but is '%s'",
@@ -8154,18 +8880,17 @@ static bool acl_check_ssl(THD *thd, ACL_USER *acl_user)
return 1;
}
-static int do_auth_once(THD *thd, LEX_STRING *auth_plugin_name,
+
+static int do_auth_once(THD *thd, const LEX_STRING *auth_plugin_name,
MPVIO_EXT *mpvio)
{
int res= CR_OK, old_status= MPVIO_EXT::FAILURE;
bool unlock_plugin= false;
- plugin_ref plugin;
+ plugin_ref plugin= NULL;
-#ifdef EMBEDDED_LIBRARY
- plugin= native_password_plugin;
-#else
if (auth_plugin_name->str == native_password_plugin_name.str)
plugin= native_password_plugin;
+#ifndef EMBEDDED_LIBRARY
else if (auth_plugin_name->str == old_password_plugin_name.str)
plugin= old_password_plugin;
else if ((plugin= my_plugin_lock_by_name(thd, auth_plugin_name,
@@ -8178,7 +8903,7 @@ static int do_auth_once(THD *thd, LEX_STRING *auth_plugin_name,
if (plugin)
{
- st_mysql_auth *auth= (st_mysql_auth*)plugin_decl(plugin)->info;
+ st_mysql_auth *auth= (st_mysql_auth *) plugin_decl(plugin)->info;
res= auth->authenticate_user(mpvio, &mpvio->auth_info);
if (unlock_plugin)
@@ -8205,6 +8930,7 @@ static int do_auth_once(THD *thd, LEX_STRING *auth_plugin_name,
return res;
}
+
/**
Perform the handshake, authorize the client and update thd sctx variables.
@@ -8219,12 +8945,12 @@ static int do_auth_once(THD *thd, LEX_STRING *auth_plugin_name,
@retval 0 success, thd is updated.
@retval 1 error
*/
-
-bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
+bool acl_authenticate(THD *thd, uint connect_errors,
+ uint com_change_user_pkt_len)
{
int res= CR_OK;
MPVIO_EXT mpvio;
- LEX_STRING *auth_plugin_name= default_auth_plugin_name;
+ const LEX_STRING *auth_plugin_name= default_auth_plugin_name;
enum enum_server_command command= com_change_user_pkt_len ? COM_CHANGE_USER
: COM_CONNECT;
DBUG_ENTER("acl_authenticate");
@@ -8239,6 +8965,8 @@ bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_le
mpvio.connect_errors= connect_errors;
mpvio.status= MPVIO_EXT::FAILURE;
+ DBUG_PRINT("info", ("com_change_user_pkt_len=%u", com_change_user_pkt_len));
+
if (command == COM_CHANGE_USER)
{
mpvio.packets_written++; // pretend that a server handshake packet was sent
@@ -8261,7 +8989,8 @@ bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_le
with a user name, and performs the authentication if everyone has used
the correct plugin.
*/
- res= do_auth_once(thd, auth_plugin_name, &mpvio);
+
+ res= do_auth_once(thd, auth_plugin_name, &mpvio);
}
/*
@@ -8279,7 +9008,7 @@ bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_le
}
Security_context *sctx= thd->security_ctx;
- ACL_USER *acl_user= mpvio.acl_user;
+ const ACL_USER *acl_user= mpvio.acl_user;
thd->password= mpvio.auth_info.password_used; // remember for error messages
@@ -8313,12 +9042,59 @@ bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_le
DBUG_RETURN(1);
}
+ sctx->proxy_user[0]= 0;
+
if (initialized) // if not --skip-grant-tables
{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ bool is_proxy_user= FALSE;
+ const char *auth_user = acl_user->user ? acl_user->user : "";
+ ACL_PROXY_USER *proxy_user;
+ /* check if the user is allowed to proxy as another user */
+ proxy_user= acl_find_proxy_user(auth_user, sctx->host, sctx->ip,
+ mpvio.auth_info.authenticated_as,
+ &is_proxy_user);
+ if (is_proxy_user)
+ {
+ ACL_USER *acl_proxy_user;
+
+ /* we need to find the proxy user, but there was none */
+ if (!proxy_user)
+ {
+ if (!thd->is_error())
+ login_failed_error(&mpvio, mpvio.auth_info.password_used);
+ DBUG_RETURN(1);
+ }
+
+ my_snprintf(sctx->proxy_user, sizeof(sctx->proxy_user) - 1,
+ "'%s'@'%s'", auth_user,
+ acl_user->host.hostname ? acl_user->host.hostname : "");
+
+ /* we're proxying : find the proxy user definition */
+ mysql_mutex_lock(&acl_cache->lock);
+ acl_proxy_user= find_acl_user(proxy_user->get_proxied_host() ?
+ proxy_user->get_proxied_host() : "",
+ mpvio.auth_info.authenticated_as, TRUE);
+ if (!acl_proxy_user)
+ {
+ if (!thd->is_error())
+ login_failed_error(&mpvio, mpvio.auth_info.password_used);
+ mysql_mutex_unlock(&acl_cache->lock);
+ DBUG_RETURN(1);
+ }
+ acl_user= acl_proxy_user->copy(thd->mem_root);
+ mysql_mutex_unlock(&acl_cache->lock);
+ }
+#endif
+
sctx->master_access= acl_user->access;
- strmake(sctx->priv_user, mpvio.auth_info.authenticated_as, USERNAME_LENGTH);
+ if (acl_user->user)
+ strmake(sctx->priv_user, acl_user->user, USERNAME_LENGTH - 1);
+ else
+ *sctx->priv_user= 0;
+
if (acl_user->host.hostname)
- strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
+ strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME - 1);
else
*sctx->priv_host= 0;
@@ -8405,6 +9181,9 @@ bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_le
thd->net.net_skip_rest_factor= 2; // skip at most 2*max_packet_size
+ if (mpvio.auth_info.external_user[0])
+ sctx->external_user= my_strdup(mpvio.auth_info.external_user, MYF(0));
+
if (res == CR_OK_HANDSHAKE_COMPLETE)
thd->stmt_da->disable_status();
else
@@ -8414,7 +9193,6 @@ bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_le
DBUG_RETURN(0);
}
-
/**
MySQL Server Password Authentication Plugin
@@ -8423,14 +9201,14 @@ bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_le
2. client sends the encrypted password back to the server
3. the server checks the password.
*/
-
-static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
+static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
MYSQL_SERVER_AUTH_INFO *info)
{
uchar *pkt;
int pkt_len;
- MPVIO_EXT *mpvio=(MPVIO_EXT*)vio;
+ MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
THD *thd=mpvio->thd;
+ DBUG_ENTER("native_password_authenticate");
/* generate the scramble, or reuse the old one */
if (thd->scramble[SCRAMBLE_LENGTH])
@@ -8480,33 +9258,37 @@ static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
/* read the reply with the encrypted password */
if ((pkt_len= mpvio->read_packet(mpvio, &pkt)) < 0)
- return CR_ERROR;
+ DBUG_RETURN(CR_ERROR);
+ DBUG_PRINT("info", ("reply read : pkt_len=%d", pkt_len));
#ifdef NO_EMBEDDED_ACCESS_CHECKS
- return CR_OK;
+ DBUG_RETURN(CR_OK);
#endif
if (pkt_len == 0) /* no password */
- return info->auth_string[0] ? CR_ERROR : CR_OK;
+ DBUG_RETURN(info->auth_string[0] ? CR_ERROR : CR_OK);
- info->password_used = 1;
+ info->password_used= PASSWORD_USED_YES;
if (pkt_len == SCRAMBLE_LENGTH)
- return info->auth_string[0] == 0 ||
- check_scramble(pkt, thd->scramble, mpvio->acl_user->salt) ?
- CR_ERROR : CR_OK;
+ {
+ if (!mpvio->acl_user->salt_len)
+ DBUG_RETURN(CR_ERROR);
+
+ DBUG_RETURN(check_scramble(pkt, thd->scramble, mpvio->acl_user->salt) ?
+ CR_ERROR : CR_OK);
+ }
inc_host_errors(mpvio->thd->main_security_ctx.ip);
- my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
- return CR_ERROR;
+ my_error(ER_HANDSHAKE_ERROR, MYF(0));
+ DBUG_RETURN(CR_ERROR);
}
-
static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
MYSQL_SERVER_AUTH_INFO *info)
{
uchar *pkt;
int pkt_len;
- MPVIO_EXT *mpvio=(MPVIO_EXT*)vio;
+ MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
THD *thd=mpvio->thd;
/* generate the scramble, or reuse the old one */
@@ -8531,7 +9313,7 @@ static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
the password is sent \0-terminated, the pkt_len is always 9 bytes.
We need to figure out the correct scramble length here.
*/
- if (pkt_len == SCRAMBLE_LENGTH_323+1)
+ if (pkt_len == SCRAMBLE_LENGTH_323 + 1)
pkt_len= strnlen((char*)pkt, pkt_len);
if (pkt_len == 0) /* no password */
@@ -8540,15 +9322,20 @@ static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
if (secure_auth(thd))
return CR_ERROR;
- info->password_used = 1;
+ info->password_used= PASSWORD_USED_YES;
if (pkt_len == SCRAMBLE_LENGTH_323)
- return info->auth_string[0] == 0 ||
- check_scramble_323(pkt, thd->scramble,
- (ulong *)mpvio->acl_user->salt) ? CR_ERROR : CR_OK;
+ {
+ if (!mpvio->acl_user->salt_len)
+ return CR_ERROR;
+
+ return check_scramble_323(pkt, thd->scramble,
+ (ulong *) mpvio->acl_user->salt) ?
+ CR_ERROR : CR_OK;
+ }
inc_host_errors(mpvio->thd->main_security_ctx.ip);
- my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
+ my_error(ER_HANDSHAKE_ERROR, MYF(0));
return CR_ERROR;
}