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.cc1155
1 files changed, 454 insertions, 701 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 7ccb396b036..77c467b7dcf 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -553,9 +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 *thd, TABLE *table,
- const char *host, const char *user,
- const char *new_password, uint new_password_len);
+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);
@@ -583,6 +583,48 @@ set_user_salt(ACL_USER *acl_user, const char *password, uint password_len)
acl_user->salt_len= 0;
}
+static char *fix_plugin_ptr(char *name)
+{
+ if (my_strcasecmp(system_charset_info, name,
+ native_password_plugin_name.str) == 0)
+ return native_password_plugin_name.str;
+ else
+ if (my_strcasecmp(system_charset_info, name,
+ old_password_plugin_name.str) == 0)
+ return old_password_plugin_name.str;
+ else
+ return name;
+}
+
+/**
+ Fix ACL::plugin pointer to point to a hard-coded string, if appropriate
+
+ Make sure that if ACL_USER's plugin is a built-in, then it points
+ to a hard coded string, not to an allocated copy. Run-time, for
+ authentication, we want to be able to detect built-ins by comparing
+ pointers, not strings.
+
+ Additionally - update the salt if the plugin is built-in.
+
+ @retval 0 the pointers were fixed
+ @retval 1 this ACL_USER uses a not built-in plugin
+*/
+static bool fix_user_plugin_ptr(ACL_USER *user)
+{
+ if (my_strcasecmp(system_charset_info, user->plugin.str,
+ native_password_plugin_name.str) == 0)
+ user->plugin= native_password_plugin_name;
+ else
+ if (my_strcasecmp(system_charset_info, user->plugin.str,
+ old_password_plugin_name.str) == 0)
+ user->plugin= old_password_plugin_name;
+ else
+ return true;
+
+ set_user_salt(user, user->auth_string.str, user->auth_string.length);
+ return false;
+}
+
/*
Initialize structures responsible for user/db-level privilege checking and
load privilege information for them from tables in the 'mysql' database.
@@ -701,7 +743,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
READ_RECORD read_record_info;
my_bool return_val= TRUE;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
- char tmp_name[NAME_LEN+1];
+ char tmp_name[SAFE_NAME_LEN+1];
int password_length;
ulong old_sql_mode= thd->variables.sql_mode;
DBUG_ENTER("acl_load");
@@ -713,8 +755,10 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
acl_cache->clear(1); // Clear locked hostname cache
init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
- init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0,
- FALSE);
+ if (init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0,
+ FALSE))
+ goto end;
+
table->use_all_columns();
(void) my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50);
while (!(read_record_info.read_record(&read_record_info)))
@@ -763,7 +807,10 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
end_read_record(&read_record_info);
freeze_size(&acl_hosts);
- init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0,FALSE);
+ if (init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0,
+ FALSE))
+ goto end;
+
table->use_all_columns();
(void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100);
password_length= table->field[2]->field_length /
@@ -915,6 +962,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
char *tmpstr= get_field(&mem, table->field[next_field++]);
if (tmpstr)
{
+ user.plugin.str= tmpstr;
+ user.plugin.length= strlen(user.plugin.str);
if (user.auth_string.length)
{
sql_print_warning("'user' entry '%s@%s' has both a password "
@@ -923,22 +972,12 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
user.user ? user.user : "",
user.host.hostname ? user.host.hostname : "");
}
- if (my_strcasecmp(system_charset_info, tmpstr,
- native_password_plugin_name.str) == 0)
- user.plugin= native_password_plugin_name;
- else
- if (my_strcasecmp(system_charset_info, tmpstr,
- old_password_plugin_name.str) == 0)
- user.plugin= old_password_plugin_name;
- else
- {
- user.plugin.str= tmpstr;
- user.plugin.length= strlen(tmpstr);
- }
user.auth_string.str= get_field(&mem, table->field[next_field++]);
if (!user.auth_string.str)
user.auth_string.str= const_cast<char*>("");
user.auth_string.length= strlen(user.auth_string.str);
+
+ fix_user_plugin_ptr(&user);
}
}
}
@@ -970,7 +1009,10 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
end_read_record(&read_record_info);
freeze_size(&acl_users);
- init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0,FALSE);
+ if (init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0,
+ FALSE))
+ goto end;
+
table->use_all_columns();
(void) my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100);
while (!(read_record_info.read_record(&read_record_info)))
@@ -1415,16 +1457,26 @@ static void acl_update_user(const char *user, const char *host,
{
if ((!acl_user->host.hostname && !host[0]) ||
(acl_user->host.hostname &&
- !my_strcasecmp(system_charset_info, host, acl_user->host.hostname)))
+ !my_strcasecmp(system_charset_info, host, acl_user->host.hostname)))
{
if (plugin->str[0])
{
- acl_user->plugin.str= strmake_root(&mem, plugin->str, plugin->length);
- acl_user->plugin.length= plugin->length;
+ acl_user->plugin= *plugin;
acl_user->auth_string.str= auth->str ?
strmake_root(&mem, auth->str, auth->length) : const_cast<char*>("");
acl_user->auth_string.length= auth->length;
+ if (fix_user_plugin_ptr(acl_user))
+ acl_user->plugin.str= strmake_root(&mem, plugin->str, plugin->length);
}
+#if 0
+ else
+ if (password)
+ {
+ 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);
+ }
+#endif
acl_user->access=privileges;
if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
acl_user->user_resource.questions=mqh->questions;
@@ -1473,11 +1525,12 @@ static void acl_insert_user(const char *user, const char *host,
update_hostname(&acl_user.host, *host ? strdup_root(&mem, host): 0);
if (plugin->str[0])
{
- acl_user.plugin.str= strmake_root(&mem, plugin->str, plugin->length);
- acl_user.plugin.length= plugin->length;
+ acl_user.plugin= *plugin;
acl_user.auth_string.str= auth->str ?
strmake_root(&mem, auth->str, auth->length) : const_cast<char*>("");
acl_user.auth_string.length= auth->length;
+ if (fix_user_plugin_ptr(&acl_user))
+ acl_user.plugin.str= strmake_root(&mem, plugin->str, plugin->length);
}
else
{
@@ -1525,10 +1578,11 @@ static void acl_update_db(const char *user, const char *host, const char *db,
{
if ((!acl_db->host.hostname && !host[0]) ||
(acl_db->host.hostname &&
- !strcmp(host, acl_db->host.hostname)))
+ !strcmp(host, acl_db->host.hostname)))
{
if ((!acl_db->db && !db[0]) ||
(acl_db->db && !strcmp(db,acl_db->db)))
+
{
if (privileges)
acl_db->access=privileges;
@@ -1883,17 +1937,18 @@ bool change_password(THD *thd, const char *host, const char *user,
goto end;
}
- if (my_strcasecmp(system_charset_info, acl_user->plugin.str,
- native_password_plugin_name.str) &&
- my_strcasecmp(system_charset_info, acl_user->plugin.str,
- old_password_plugin_name.str))
+ /* update loaded acl entry: */
+ if (acl_user->plugin.str == native_password_plugin_name.str ||
+ acl_user->plugin.str == old_password_plugin_name.str)
{
+ 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));
- }
- /* update loaded acl entry: */
- set_user_salt(acl_user, new_password, new_password_len);
- set_user_plugin(acl_user, new_password_len);
if (update_user_table(thd, table,
acl_user->host.hostname ? acl_user->host.hostname : "",
@@ -1909,10 +1964,12 @@ bool change_password(THD *thd, const char *host, const char *user,
result= 0;
if (mysql_bin_log.is_open())
{
- query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'",
- acl_user->user ? acl_user->user : "",
- acl_user->host.hostname ? acl_user->host.hostname : "",
- new_password);
+ query_length=
+ my_sprintf(buff,
+ (buff,"SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'",
+ acl_user->user ? acl_user->user : "",
+ acl_user->host.hostname ? acl_user->host.hostname : "",
+ new_password));
thd->clear_error();
result= thd->binlog_query(THD::STMT_QUERY_TYPE, buff, query_length,
FALSE, FALSE, FALSE, 0);
@@ -2158,9 +2215,9 @@ static bool update_user_table(THD *thd, TABLE *table,
key_copy((uchar *) user_key, table->record[0], table->key_info,
table->key_info->key_length);
- if (table->file->index_read_idx_map(table->record[0], 0,
- (uchar *) user_key, HA_WHOLE_KEY,
- HA_READ_KEY_EXACT))
+ if (table->file->ha_index_read_idx_map(table->record[0], 0,
+ (uchar *) user_key, HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
{
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
MYF(0)); /* purecov: deadcode */
@@ -2250,9 +2307,9 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- if (table->file->index_read_idx_map(table->record[0], 0, user_key,
- HA_WHOLE_KEY,
- HA_READ_KEY_EXACT))
+ if (table->file->ha_index_read_idx_map(table->record[0], 0, user_key,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
{
/* what == 'N' means revoke */
if (what == 'N')
@@ -2305,6 +2362,7 @@ 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')
{
@@ -2312,6 +2370,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
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 &&
@@ -2395,22 +2454,14 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
mqh_used= mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour;
next_field+= 4;
- if (combo.plugin.str[0])
+ if (table->s->fields >= 41 && combo.plugin.str[0])
{
- 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]->set_notnull();
- table->field[next_field + 1]->store(combo.auth.str, combo.auth.length,
- system_charset_info);
- table->field[next_field + 1]->set_notnull();
- }
- else
- {
- my_error(ER_BAD_FIELD_ERROR, MYF(0), "plugin", "mysql.user");
- goto end;
- }
+ table->field[next_field]->store(combo.plugin.str, combo.plugin.length,
+ 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();
}
}
@@ -2513,9 +2564,9 @@ static int replace_db_table(TABLE *table, const char *db,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- if (table->file->index_read_idx_map(table->record[0],0, user_key,
- HA_WHOLE_KEY,
- HA_READ_KEY_EXACT))
+ if (table->file->ha_index_read_idx_map(table->record[0],0, user_key,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
{
if (what == 'N')
{ // no row, no revoke
@@ -2905,8 +2956,9 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
col_privs->field[4]->store("",0, &my_charset_latin1);
col_privs->file->ha_index_init(0, 1);
- if (col_privs->file->index_read_map(col_privs->record[0], (uchar*) key,
- (key_part_map)15, HA_READ_KEY_EXACT))
+ if (col_privs->file->ha_index_read_map(col_privs->record[0], (uchar*) key,
+ (key_part_map)15,
+ HA_READ_KEY_EXACT))
{
cols = 0; /* purecov: deadcode */
col_privs->file->ha_index_end();
@@ -2932,7 +2984,7 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
privs= cols= 0;
return;
}
- } while (!col_privs->file->index_next(col_privs->record[0]) &&
+ } while (!col_privs->file->ha_index_next(col_privs->record[0]) &&
!key_cmp_if_same(col_privs,key,0,key_prefix_len));
col_privs->file->ha_index_end();
}
@@ -2967,7 +3019,7 @@ static GRANT_NAME *name_hash_search(HASH *name_hash,
const char *user, const char *tname,
bool exact, bool name_tolower)
{
- char helping [NAME_LEN*2+USERNAME_LENGTH+3], *name_ptr;
+ char helping [SAFE_NAME_LEN*2+USERNAME_LENGTH+3], *name_ptr;
uint len;
GRANT_NAME *grant_name,*found=0;
HASH_SEARCH_STATE state;
@@ -3077,8 +3129,8 @@ static int replace_column_table(GRANT_TABLE *g_t,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- if (table->file->index_read_map(table->record[0], user_key, HA_WHOLE_KEY,
- HA_READ_KEY_EXACT))
+ if (table->file->ha_index_read_map(table->record[0], user_key,
+ HA_WHOLE_KEY, HA_READ_KEY_EXACT))
{
if (revoke_grant)
{
@@ -3159,9 +3211,9 @@ static int replace_column_table(GRANT_TABLE *g_t,
key_copy(user_key, table->record[0], table->key_info,
key_prefix_length);
- if (table->file->index_read_map(table->record[0], user_key,
- (key_part_map)15,
- HA_READ_KEY_EXACT))
+ if (table->file->ha_index_read_map(table->record[0], user_key,
+ (key_part_map)15,
+ HA_READ_KEY_EXACT))
goto end;
/* Scan through all rows with the same host,db,user and table */
@@ -3212,7 +3264,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
my_hash_delete(&g_t->hash_columns,(uchar*) grant_column);
}
}
- } while (!table->file->index_next(table->record[0]) &&
+ } while (!table->file->ha_index_next(table->record[0]) &&
!key_cmp_if_same(table, key, 0, key_prefix_length));
}
@@ -3274,9 +3326,9 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- if (table->file->index_read_idx_map(table->record[0], 0, user_key,
- HA_WHOLE_KEY,
- HA_READ_KEY_EXACT))
+ if (table->file->ha_index_read_idx_map(table->record[0], 0, user_key,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
{
/*
The following should never happen as we first check the in memory
@@ -3399,10 +3451,10 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
TRUE);
store_record(table,record[1]); // store at pos 1
- if (table->file->index_read_idx_map(table->record[0], 0,
- (uchar*) table->field[0]->ptr,
- HA_WHOLE_KEY,
- HA_READ_KEY_EXACT))
+ if (table->file->ha_index_read_idx_map(table->record[0], 0,
+ (uchar*) table->field[0]->ptr,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
{
/*
The following should never happen as we first check the in memory
@@ -3962,7 +4014,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
{
List_iterator <LEX_USER> str_list (list);
LEX_USER *Str, *tmp_Str, *proxied_user= NULL;
- char tmp_db[NAME_LEN+1];
+ char tmp_db[SAFE_NAME_LEN+1];
bool create_new_users=0;
TABLE_LIST tables[2];
bool save_binlog_row_based;
@@ -4186,7 +4238,7 @@ static my_bool grant_load_procs_priv(TABLE *p_table)
p_table->file->ha_index_init(0, 1);
p_table->use_all_columns();
- if (!p_table->file->index_first(p_table->record[0]))
+ if (!p_table->file->ha_index_first(p_table->record[0]))
{
memex_ptr= &memex;
my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
@@ -4238,7 +4290,7 @@ static my_bool grant_load_procs_priv(TABLE *p_table)
goto end_unlock;
}
}
- while (!p_table->file->index_next(p_table->record[0]));
+ while (!p_table->file->ha_index_next(p_table->record[0]));
}
/* Return ok */
return_val= 0;
@@ -4288,7 +4340,7 @@ static my_bool grant_load(THD *thd, TABLE_LIST *tables)
t_table->use_all_columns();
c_table->use_all_columns();
- if (!t_table->file->index_first(t_table->record[0]))
+ if (!t_table->file->ha_index_first(t_table->record[0]))
{
memex_ptr= &memex;
my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
@@ -4323,7 +4375,7 @@ static my_bool grant_load(THD *thd, TABLE_LIST *tables)
goto end_unlock;
}
}
- while (!t_table->file->index_next(t_table->record[0]));
+ while (!t_table->file->ha_index_next(t_table->record[0]));
}
return_val=0; // Return ok
@@ -4642,6 +4694,8 @@ err:
{
char command[128];
get_privilege_desc(command, sizeof(command), want_access);
+ status_var_increment(thd->status_var.access_denied_errors);
+
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
command,
sctx->priv_user,
@@ -4918,7 +4972,7 @@ static bool check_grant_db_routine(THD *thd, const char *db, HASH *hash)
bool check_grant_db(THD *thd,const char *db)
{
Security_context *sctx= thd->security_ctx;
- char helping [NAME_LEN+USERNAME_LENGTH+2];
+ char helping [SAFE_NAME_LEN + USERNAME_LENGTH+2];
uint len;
bool error= TRUE;
@@ -5256,16 +5310,27 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append(lex_user->host.str,lex_user->host.length,
system_charset_info);
global.append ('\'');
- if (acl_user->salt_len)
+ if (acl_user->plugin.str == native_password_plugin_name.str ||
+ acl_user->plugin.str == old_password_plugin_name.str)
{
- char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
- if (acl_user->salt_len == SCRAMBLE_LENGTH)
- make_password_from_salt(passwd_buff, acl_user->salt);
- else
- make_password_from_salt_323(passwd_buff, (ulong *) acl_user->salt);
- global.append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '"));
- global.append(passwd_buff);
- global.append('\'');
+ if (acl_user->auth_string.length)
+ {
+ DBUG_ASSERT(acl_user->salt_len);
+ global.append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '"));
+ global.append(acl_user->auth_string.str, acl_user->auth_string.length);
+ global.append('\'');
+ }
+ }
+ else
+ {
+ global.append(STRING_WITH_LEN(" IDENTIFIED VIA "));
+ global.append(acl_user->plugin.str, acl_user->plugin.length);
+ if (acl_user->auth_string.length)
+ {
+ global.append(STRING_WITH_LEN(" USING '"));
+ global.append(acl_user->auth_string.str, acl_user->auth_string.length);
+ global.append('\'');
+ }
}
/* "show grants" SSL related stuff */
if (acl_user->ssl_type == SSL_TYPE_ANY)
@@ -5901,9 +5966,9 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
table->key_info->key_part[1].store_length);
key_copy(user_key, table->record[0], table->key_info, key_prefix_length);
- if ((error= table->file->index_read_idx_map(table->record[0], 0,
- user_key, (key_part_map)3,
- HA_READ_KEY_EXACT)))
+ if ((error= table->file->ha_index_read_idx_map(table->record[0], 0,
+ user_key, (key_part_map)3,
+ HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
{
@@ -5938,7 +6003,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
DBUG_PRINT("info",("scan table: '%s' search: '%s'@'%s'",
table->s->table_name.str, user_str, host_str));
#endif
- while ((error= table->file->rnd_next(table->record[0])) !=
+ while ((error= table->file->ha_rnd_next(table->record[0])) !=
HA_ERR_END_OF_FILE)
{
if (error)
@@ -6098,7 +6163,7 @@ static int handle_grant_struct(uint struct_no, bool drop,
break;
default:
- MY_ASSERT_UNREACHABLE();
+ DBUG_ASSERT(0);
}
if (! user)
user= "";
@@ -7827,32 +7892,15 @@ get_cached_table_access(GRANT_INTERNAL_INFO *grant_internal_info,
#ifdef NO_EMBEDDED_ACCESS_CHECKS
#define initialized 0
#define decrease_user_connections(X) /* nothing */
-#define check_for_max_user_connections(X, Y) 0
+#define check_for_max_user_connections(X,Y) 0
+#define get_or_create_user_conn(A,B,C,D) 0
#endif
#endif
#ifndef HAVE_OPENSSL
#define ssl_acceptor_fd 0
-#define sslaccept(A,B,C) 1
+#define sslaccept(A,B,C,D) 1
#endif
-
-class Thd_charset_adapter
-{
- THD *thd;
-public:
- Thd_charset_adapter(THD *thd_arg) : thd (thd_arg) {}
- bool init_client_charset(uint cs_number)
- {
- if (thd_init_client_charset(thd, cs_number))
- return true;
- thd->update_charset();
- return thd->is_error();
- }
-
- CHARSET_INFO *charset() { return thd->charset(); }
-};
-
-
/**
The internal version of what plugins know as MYSQL_PLUGIN_VIO,
basically the context of the authentication session
@@ -7860,7 +7908,8 @@ public:
struct MPVIO_EXT :public MYSQL_PLUGIN_VIO
{
MYSQL_SERVER_AUTH_INFO auth_info;
- const ACL_USER *acl_user;
+ THD *thd;
+ 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 */
@@ -7877,70 +7926,33 @@ struct MPVIO_EXT :public MYSQL_PLUGIN_VIO
uint connect_errors; ///< if there were connect errors for this host
/** when plugin returns a failure this tells us what really happened */
enum { SUCCESS, FAILURE, RESTART } status;
-
- /* encapsulation members */
- ulong client_capabilities;
- char *scramble;
- MEM_ROOT *mem_root;
- struct rand_struct *rand;
- my_thread_id thread_id;
- uint *server_status;
- NET *net;
- ulong max_client_packet_length;
- char *ip;
- char *host;
- Thd_charset_adapter *charset_adapter;
- LEX_STRING acl_user_plugin;
};
/**
a helper function to report an access denied error in all the proper places
*/
-static void login_failed_error(MPVIO_EXT *mpvio, int passwd_used)
-{
- THD *thd= current_thd;
- if (passwd_used == 2)
+static void login_failed_error(THD *thd, int passwd_used)
+{
+ 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(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));
+ status_var_increment(thd->status_var.access_denied_errors);
+ /*
+ Log access denied messages to the error log when log-warnings = 2
+ so that the overhead of the general query log is not required to track
+ failed connections.
+ */
+ if (global_system_variables.log_warnings > 1)
{
- my_error(ER_ACCESS_DENIED_NO_PASSWORD_ERROR, MYF(0),
- mpvio->auth_info.user_name,
- mpvio->auth_info.host_or_ip);
- general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_NO_PASSWORD_ERROR),
- mpvio->auth_info.user_name,
- mpvio->auth_info.host_or_ip);
- /*
- Log access denied messages to the error log when log-warnings = 2
- so that the overhead of the general query log is not required to track
- failed connections.
- */
- if (global_system_variables.log_warnings > 1)
- {
- sql_print_warning(ER(ER_ACCESS_DENIED_NO_PASSWORD_ERROR),
- mpvio->auth_info.user_name,
- mpvio->auth_info.host_or_ip);
- }
- }
- else
- {
- my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
- mpvio->auth_info.user_name,
- mpvio->auth_info.host_or_ip,
- passwd_used ? ER(ER_YES) : ER(ER_NO));
- general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
- mpvio->auth_info.user_name,
- mpvio->auth_info.host_or_ip,
- passwd_used ? ER(ER_YES) : ER(ER_NO));
- /*
- Log access denied messages to the error log when log-warnings = 2
- so that the overhead of the general query log is not required to track
- failed connections.
- */
- if (global_system_variables.log_warnings > 1)
- {
- sql_print_warning(ER(ER_ACCESS_DENIED_ERROR),
- mpvio->auth_info.user_name,
- mpvio->auth_info.host_or_ip,
- passwd_used ? ER(ER_YES) : ER(ER_NO));
- }
+ 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));
}
}
@@ -7975,30 +7987,30 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
DBUG_ASSERT(mpvio->status == MPVIO_EXT::FAILURE);
DBUG_ASSERT(data_len <= 255);
- char *buff= (char *) my_alloca(1 + SERVER_VERSION_LENGTH + data_len + 64);
+ THD *thd= mpvio->thd;
+ 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;
- mpvio->client_capabilities= CLIENT_BASIC_FLAGS;
+ thd->client_capabilities= CLIENT_BASIC_FLAGS;
if (opt_using_transactions)
- mpvio->client_capabilities|= CLIENT_TRANSACTIONS;
+ thd->client_capabilities|= CLIENT_TRANSACTIONS;
- mpvio->client_capabilities|= CAN_CLIENT_COMPRESS;
+ thd->client_capabilities|= CAN_CLIENT_COMPRESS;
if (ssl_acceptor_fd)
{
- mpvio->client_capabilities|= CLIENT_SSL;
- mpvio->client_capabilities|= CLIENT_SSL_VERIFY_SERVER_CERT;
+ thd->client_capabilities |= CLIENT_SSL;
+ thd->client_capabilities |= CLIENT_SSL_VERIFY_SERVER_CERT;
}
if (data_len)
{
- mpvio->cached_server_packet.pkt= (char*) memdup_root(mpvio->mem_root,
- data, data_len);
+ mpvio->cached_server_packet.pkt= (char*)thd->memdup(data, data_len);
mpvio->cached_server_packet.pkt_len= data_len;
}
@@ -8025,14 +8037,14 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
native_password_plugin will have to send it in a separate packet,
adding one more round trip.
*/
- create_random_string(mpvio->scramble, SCRAMBLE_LENGTH, mpvio->rand);
- data= mpvio->scramble;
+ create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
+ data= thd->scramble;
}
data_len= SCRAMBLE_LENGTH;
}
end= strnmov(end, server_version, SERVER_VERSION_LENGTH) + 1;
- int4store((uchar*) end, mpvio->thread_id);
+ int4store((uchar*) end, mpvio->thd->thread_id);
end+= 4;
/*
@@ -8044,11 +8056,11 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
end+= SCRAMBLE_LENGTH_323;
*end++= 0;
- int2store(end, mpvio->client_capabilities);
+ int2store(end, thd->client_capabilities);
/* write server characteristics: up to 16 bytes allowed */
end[2]= (char) default_charset_info->number;
- int2store(end + 3, mpvio->server_status[0]);
- int2store(end + 5, mpvio->client_capabilities >> 16);
+ int2store(end+3, mpvio->thd->server_status);
+ int2store(end+5, thd->client_capabilities >> 16);
end[7]= data_len;
bzero(end + 8, 10);
end+= 18;
@@ -8059,31 +8071,30 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
end= strmake(end, plugin_name(mpvio->plugin)->str,
plugin_name(mpvio->plugin)->length);
- int res= my_net_write(mpvio->net, (uchar*) buff, (size_t) (end - buff + 1)) ||
- net_flush(mpvio->net);
+ int res= my_net_write(&mpvio->thd->net, (uchar*) buff,
+ (size_t) (end - buff + 1)) ||
+ net_flush(&mpvio->thd->net);
my_afree(buff);
DBUG_RETURN (res);
}
-static bool secure_auth(MPVIO_EXT *mpvio)
+static bool secure_auth(THD *thd)
{
- THD *thd;
if (!opt_secure_auth)
return 0;
+
/*
If the server is running in secure auth mode, short scrambles are
forbidden. Extra juggling to report the same error as the old code.
*/
-
- thd= current_thd;
- if (mpvio->client_capabilities & CLIENT_PROTOCOL_41)
+ if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
my_error(ER_SERVER_IS_IN_SECURE_AUTH_MODE, MYF(0),
- mpvio->auth_info.user_name,
- mpvio->auth_info.host_or_ip);
+ thd->security_ctx->user,
+ thd->security_ctx->host_or_ip);
general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
- mpvio->auth_info.user_name,
- mpvio->auth_info.host_or_ip);
+ thd->security_ctx->user,
+ thd->security_ctx->host_or_ip);
}
else
{
@@ -8119,16 +8130,18 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
{
DBUG_ASSERT(mpvio->packets_written == 1);
DBUG_ASSERT(mpvio->packets_read == 1);
- NET *net= mpvio->net;
+ 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;
DBUG_ASSERT(client_auth_plugin);
+ DBUG_ASSERT(my_strcasecmp(system_charset_info, client_auth_plugin,
+ mpvio->cached_client_reply.plugin));
/*
we send an old "short 4.0 scramble request", if we need to request a
@@ -8144,7 +8157,7 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
client_auth_plugin == old_password_plugin_name.str;
if (switch_from_long_to_short_scramble)
- DBUG_RETURN (secure_auth(mpvio) ||
+ DBUG_RETURN (secure_auth(mpvio->thd) ||
my_net_write(net, switch_plugin_request_buf, 1) ||
net_flush(net));
@@ -8154,34 +8167,16 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
ask an old 4.0 client to use the new 4.1 authentication protocol.
*/
bool switch_from_short_to_long_scramble=
- old_password_plugin_name.str == mpvio->cached_client_reply.plugin &&
+ old_password_plugin_name.str == mpvio->cached_client_reply.plugin &&
client_auth_plugin == native_password_plugin_name.str;
if (switch_from_short_to_long_scramble)
{
my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
- general_log_print(current_thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ general_log_print(mpvio->thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
DBUG_RETURN (1);
}
- /*
- If we're dealing with an older client we can't just send a change plugin
- packet to re-initiate the authentication handshake, because the client
- won't understand it. The good thing is that we don't need to : the old client
- expects us to just check the user credentials here, which we can do by just reading
- the cached data that are placed there by parse_com_change_user_packet()
- In this case we just do nothing and behave as if normal authentication
- should continue.
- */
- if (!(mpvio->client_capabilities & CLIENT_PLUGIN_AUTH))
- {
- DBUG_PRINT("info", ("old client sent a COM_CHANGE_USER"));
- DBUG_ASSERT(mpvio->cached_client_reply.pkt);
- /* get the status back so the read can process the cached result */
- mpvio->status= MPVIO_EXT::RESTART;
- DBUG_RETURN(0);
- }
-
DBUG_PRINT("info", ("requesting client to use the %s plugin",
client_auth_plugin));
DBUG_RETURN(net_write_command(net, switch_plugin_request_buf[0],
@@ -8205,26 +8200,18 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
*/
static bool find_mpvio_user(MPVIO_EXT *mpvio)
{
+ Security_context *sctx= mpvio->thd->security_ctx;
DBUG_ENTER("find_mpvio_user");
- DBUG_PRINT("info", ("entry: %s", mpvio->auth_info.user_name));
DBUG_ASSERT(mpvio->acl_user == 0);
+
mysql_mutex_lock(&acl_cache->lock);
for (uint i=0; i < acl_users.elements; i++)
{
ACL_USER *acl_user_tmp= dynamic_element(&acl_users, i, ACL_USER*);
- if ((!acl_user_tmp->user ||
- !strcmp(mpvio->auth_info.user_name, acl_user_tmp->user)) &&
- compare_hostname(&acl_user_tmp->host, mpvio->host, mpvio->ip))
- {
- mpvio->acl_user= acl_user_tmp->copy(mpvio->mem_root);
- if (acl_user_tmp->plugin.str == native_password_plugin_name.str ||
- acl_user_tmp->plugin.str == old_password_plugin_name.str)
- mpvio->acl_user_plugin= acl_user_tmp->plugin;
- else
- make_lex_string_root(mpvio->mem_root,
- &mpvio->acl_user_plugin,
- acl_user_tmp->plugin.str,
- acl_user_tmp->plugin.length, 0);
+ if ((!acl_user_tmp->user || !strcmp(sctx->user, acl_user_tmp->user)) &&
+ compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip))
+ {
+ mpvio->acl_user= acl_user_tmp->copy(mpvio->thd->mem_root);
break;
}
}
@@ -8232,29 +8219,32 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio)
if (!mpvio->acl_user)
{
- login_failed_error(mpvio, 0);
+ login_failed_error(mpvio->thd, 0);
DBUG_RETURN (1);
}
/* user account requires non-default plugin and the client is too old */
if (mpvio->acl_user->plugin.str != native_password_plugin_name.str &&
mpvio->acl_user->plugin.str != old_password_plugin_name.str &&
- !(mpvio->client_capabilities & CLIENT_PLUGIN_AUTH))
+ !(mpvio->thd->client_capabilities & CLIENT_PLUGIN_AUTH))
{
DBUG_ASSERT(my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
native_password_plugin_name.str));
DBUG_ASSERT(my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
old_password_plugin_name.str));
my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
- general_log_print(current_thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ general_log_print(mpvio->thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
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);
+
DBUG_PRINT("info", ("exit: user=%s, auth_string=%s, authenticated as=%s"
"plugin=%s",
mpvio->auth_info.user_name,
@@ -8268,7 +8258,9 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio)
/* the packet format is described in send_change_user_packet() */
static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
{
- NET *net= mpvio->net;
+ THD *thd= mpvio->thd;
+ NET *net= &thd->net;
+ Security_context *sctx= thd->security_ctx;
char *user= (char*) net->read_pos;
char *end= user + packet_length;
@@ -8276,11 +8268,11 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
char *passwd= strend(user) + 1;
uint user_len= passwd - user - 1;
char *db= passwd;
- char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
+ 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));
@@ -8297,7 +8289,7 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
Cast *passwd to an unsigned char, so that it doesn't extend the sign for
*passwd > 127 and become 2**32-127+ after casting to uint.
*/
- uint passwd_len= (mpvio->client_capabilities & CLIENT_SECURE_CONNECTION ?
+ uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
(uchar) (*passwd++) : strlen(passwd));
db+= passwd_len + 1;
@@ -8317,38 +8309,39 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
if (ptr + 1 < end)
{
- if (mpvio->charset_adapter->init_client_charset(uint2korr(ptr)))
+ 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, db_len, mpvio->charset_adapter->charset(),
- &dummy_errors);
- db_buff[db_len]= 0;
+ db, db_len, thd->charset(), &dummy_errors);
user_len= copy_and_convert(user_buff, sizeof(user_buff) - 1,
- system_charset_info, user, user_len,
- mpvio->charset_adapter->charset(),
- &dummy_errors);
- user_buff[user_len]= 0;
+ system_charset_info, user, user_len,
+ thd->charset(), &dummy_errors);
- /* we should not free mpvio->user here: it's saved by dispatch_command() */
- if (!(mpvio->auth_info.user_name= my_strndup(user_buff, user_len, MYF(MY_WME))))
- return 1;
- mpvio->auth_info.user_name_length= user_len;
+ if (!(sctx->user= my_strndup(user_buff, user_len, MYF(MY_WME))))
+ DBUG_RETURN(1);
+
+ /* Clear variables that are allocated */
+ thd->user_connect= 0;
+ strmake(sctx->priv_user, sctx->user, USERNAME_LENGTH);
- if (make_lex_string_root(mpvio->mem_root,
- &mpvio->db, db_buff, db_len, 0) == 0)
+ if (thd->make_lex_string(&mpvio->db, db_buff, db_len, 0) == 0)
DBUG_RETURN(1); /* The error is set by make_lex_string(). */
+ /*
+ 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
+ pointer if connect failed.
+ */
+ thd->reset_db(NULL, 0);
+
if (!initialized)
{
// if mysqld's been started with --skip-grant-tables option
- strmake(mpvio->auth_info.authenticated_as,
- mpvio->auth_info.user_name, USERNAME_LENGTH);
-
mpvio->status= MPVIO_EXT::SUCCESS;
DBUG_RETURN(0);
}
@@ -8358,7 +8351,7 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
DBUG_RETURN(1);
char *client_plugin;
- if (mpvio->client_capabilities & CLIENT_PLUGIN_AUTH)
+ if (thd->client_capabilities & CLIENT_PLUGIN_AUTH)
{
client_plugin= ptr + 2;
if (client_plugin >= end)
@@ -8366,10 +8359,11 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
DBUG_RETURN(1);
}
+ client_plugin= fix_plugin_ptr(client_plugin);
}
else
{
- if (mpvio->client_capabilities & CLIENT_SECURE_CONNECTION)
+ if (thd->client_capabilities & CLIENT_SECURE_CONNECTION)
client_plugin= native_password_plugin_name.str;
else
{
@@ -8381,7 +8375,7 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
and client plugins don't match.
*/
if (mpvio->acl_user->auth_string.length == 0)
- mpvio->acl_user_plugin= old_password_plugin_name;
+ mpvio->acl_user->plugin= old_password_plugin_name;
}
}
@@ -8399,160 +8393,14 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
DBUG_RETURN (0);
}
-#ifndef EMBEDDED_LIBRARY
-
-/** Get a string according to the protocol of the underlying buffer. */
-typedef char * (*get_proto_string_func_t) (char **, size_t *, size_t *);
-
-/**
- Get a string formatted according to the 4.1 version of the MySQL protocol.
-
- @param buffer[in, out] Pointer to the user-supplied buffer to be scanned.
- @param max_bytes_available[in, out] Limit the bytes to scan.
- @param string_length[out] The number of characters scanned not including
- the null character.
-
- @remark Strings are always null character terminated in this version of the
- protocol.
-
- @remark The string_length does not include the terminating null character.
- However, after the call, the buffer is increased by string_length+1
- bytes, beyond the null character if there still available bytes to
- scan.
-
- @return pointer to beginning of the string scanned.
- @retval NULL The buffer content is malformed
-*/
-
-static
-char *get_41_protocol_string(char **buffer,
- size_t *max_bytes_available,
- size_t *string_length)
-{
- char *str= (char *)memchr(*buffer, '\0', *max_bytes_available);
-
- if (str == NULL)
- return NULL;
-
- *string_length= (size_t)(str - *buffer);
- *max_bytes_available-= *string_length + 1;
- str= *buffer;
- *buffer += *string_length + 1;
-
- return str;
-}
-
-
-/**
- Get a string formatted according to the 4.0 version of the MySQL protocol.
-
- @param buffer[in, out] Pointer to the user-supplied buffer to be scanned.
- @param max_bytes_available[in, out] Limit the bytes to scan.
- @param string_length[out] The number of characters scanned not including
- the null character.
-
- @remark If there are not enough bytes left after the current position of
- the buffer to satisfy the current string, the string is considered
- to be empty and a pointer to empty_c_string is returned.
-
- @remark A string at the end of the packet is not null terminated.
-
- @return Pointer to beginning of the string scanned, or a pointer to a empty
- string.
-*/
-static
-char *get_40_protocol_string(char **buffer,
- size_t *max_bytes_available,
- size_t *string_length)
-{
- char *str;
- size_t len;
-
- /* No bytes to scan left, treat string as empty. */
- if ((*max_bytes_available) == 0)
- {
- *string_length= 0;
- return empty_c_string;
- }
-
- str= (char *) memchr(*buffer, '\0', *max_bytes_available);
-
- /*
- If the string was not null terminated by the client,
- the remainder of the packet is the string. Otherwise,
- advance the buffer past the end of the null terminated
- string.
- */
- if (str == NULL)
- len= *string_length= *max_bytes_available;
- else
- len= (*string_length= (size_t)(str - *buffer)) + 1;
-
- str= *buffer;
- *buffer+= len;
- *max_bytes_available-= len;
-
- return str;
-}
-
-/**
- Get a length encoded string from a user-supplied buffer.
-
- @param buffer[in, out] The buffer to scan; updates position after scan.
- @param max_bytes_available[in, out] Limit the number of bytes to scan
- @param string_length[out] Number of characters scanned
-
- @remark In case the length is zero, then the total size of the string is
- considered to be 1 byte; the size byte.
-
- @return pointer to first byte after the header in buffer.
- @retval NULL The buffer content is malformed
-*/
-
-static
-char *get_length_encoded_string(char **buffer,
- size_t *max_bytes_available,
- size_t *string_length)
-{
- if (*max_bytes_available == 0)
- return NULL;
-
- /* Do double cast to prevent overflow from signed / unsigned conversion */
- size_t str_len= (size_t)(unsigned char)**buffer;
-
- /*
- If the length encoded string has the length 0
- the total size of the string is only one byte long (the size byte)
- */
- if (str_len == 0)
- {
- ++*buffer;
- *string_length= 0;
- /*
- Return a pointer to the 0 character so the return value will be
- an empty string.
- */
- return *buffer-1;
- }
-
- if (str_len >= *max_bytes_available)
- return NULL;
-
- char *str= *buffer+1;
- *string_length= str_len;
- *max_bytes_available-= *string_length + 1;
- *buffer+= *string_length + 1;
- return str;
-}
-#endif
-
/* the packet format is described in send_client_reply_packet() */
static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
uchar **buff, ulong pkt_len)
{
#ifndef EMBEDDED_LIBRARY
- NET *net= mpvio->net;
+ THD *thd= mpvio->thd;
+ NET *net= &thd->net;
char *end;
DBUG_ASSERT(mpvio->status == MPVIO_EXT::FAILURE);
@@ -8561,16 +8409,17 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
return packet_error;
if (mpvio->connect_errors)
- reset_host_errors(mpvio->ip);
+ reset_host_errors(thd->main_security_ctx.ip);
ulong client_capabilities= uint2korr(net->read_pos);
if (client_capabilities & CLIENT_PROTOCOL_41)
{
client_capabilities|= ((ulong) uint2korr(net->read_pos + 2)) << 16;
- mpvio->max_client_packet_length= uint4korr(net->read_pos + 4);
+ thd->max_client_packet_length= uint4korr(net->read_pos + 4);
DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
- if (mpvio->charset_adapter->init_client_charset((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;
}
else
@@ -8580,14 +8429,12 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
}
/* Disable those bits which are not supported by the client. */
- mpvio->client_capabilities&= client_capabilities;
-
+ thd->client_capabilities&= client_capabilities;
-#if defined(HAVE_OPENSSL)
- DBUG_PRINT("info", ("client capabilities: %lu", mpvio->client_capabilities));
- if (mpvio->client_capabilities & CLIENT_SSL)
+ DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
+ if (thd->client_capabilities & CLIENT_SSL)
{
- unsigned long errptr;
+ unsigned long errptr __attribute__((unused));
/* Do the SSL layering. */
if (!ssl_acceptor_fd)
@@ -8609,126 +8456,92 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
return packet_error;
}
}
-#endif
- if (end > (char *)net->read_pos + pkt_len)
+ 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 ((mpvio->client_capabilities & CLIENT_TRANSACTIONS) &&
+ if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
opt_using_transactions)
- net->return_status= mpvio->server_status;
-
- /*
- The 4.0 and 4.1 versions of the protocol differ on how strings
- are terminated. In the 4.0 version, if a string is at the end
- of the packet, the string is not null terminated. Do not assume
- that the returned string is always null terminated.
- */
- get_proto_string_func_t get_string;
-
- if (mpvio->client_capabilities & CLIENT_PROTOCOL_41)
- get_string= get_41_protocol_string;
- else
- get_string= get_40_protocol_string;
+ net->return_status= &thd->server_status;
- /*
- In order to safely scan a head for '\0' string terminators
- we must keep track of how many bytes remain in the allocated
- buffer or we might read past the end of the buffer.
- */
- size_t bytes_remaining_in_packet= pkt_len - (end - (char *)net->read_pos);
-
- size_t user_len;
- char *user= get_string(&end, &bytes_remaining_in_packet, &user_len);
- if (user == NULL)
- return packet_error;
+ char *user= end;
+ char *passwd= strend(user)+1;
+ uint user_len= passwd - user - 1, db_len;
+ 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;
/*
- Old clients send a null-terminated string as password; new clients send
+ Old clients send null-terminated string as password; new clients send
the size (1 byte) + string (not null-terminated). Hence in case of empty
password both send '\0'.
+
+ This strlen() can't be easily deleted without changing protocol.
+
+ Cast *passwd to an unsigned char, so that it doesn't extend the sign for
+ *passwd > 127 and become 2**32-127+ after casting to uint.
*/
- size_t passwd_len= 0;
- char *passwd= NULL;
+ uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
+ (uchar)(*passwd++) : strlen(passwd);
- if (mpvio->client_capabilities & CLIENT_SECURE_CONNECTION)
+ if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
{
- /*
- 4.1+ password. First byte is password length.
- */
- passwd= get_length_encoded_string(&end, &bytes_remaining_in_packet,
- &passwd_len);
+ db= db + passwd_len + 1;
+ /* strlen() can't be easily deleted without changing protocol */
+ db_len= strlen(db);
}
else
{
- /*
- Old passwords are zero terminated strings.
- */
- passwd= get_string(&end, &bytes_remaining_in_packet, &passwd_len);
+ db= 0;
+ db_len= 0;
}
- if (passwd == NULL)
+ if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
return packet_error;
- size_t db_len= 0;
- char *db= NULL;
-
- if (mpvio->client_capabilities & CLIENT_CONNECT_WITH_DB)
- {
- db= get_string(&end, &bytes_remaining_in_packet, &db_len);
- if (db == NULL)
- return packet_error;
- }
-
- size_t client_plugin_len= 0;
- char *client_plugin= get_string(&end, &bytes_remaining_in_packet,
- &client_plugin_len);
- if (client_plugin == NULL)
- client_plugin= &empty_c_string[0];
+ char *client_plugin= passwd + passwd_len + (db ? db_len + 1 : 0);
- char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
- char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
- uint dummy_errors;
-
-
- /*
- Copy and convert the user and database names to the character set used
- by the server. Since 4.1 all database names are stored in UTF-8. Also,
- ensure that the names are properly null-terminated as this is relied
- upon later.
- */
+ /* 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, db_len, mpvio->charset_adapter->charset(),
- &dummy_errors);
- db_buff[db_len]= '\0';
+ db, db_len, thd->charset(), &dummy_errors);
db= db_buff;
}
user_len= copy_and_convert(user_buff, sizeof(user_buff) - 1,
system_charset_info, user, user_len,
- mpvio->charset_adapter->charset(),
- &dummy_errors);
- user_buff[user_len]= '\0';
+ thd->charset(), &dummy_errors);
user= user_buff;
/* If username starts and ends in "'", chop them off */
if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
{
- user[user_len - 1]= 0;
user++;
user_len-= 2;
}
- if (make_lex_string_root(mpvio->mem_root,
- &mpvio->db, db, db_len, 0) == 0)
+ Security_context *sctx= thd->security_ctx;
+
+ if (thd->make_lex_string(&mpvio->db, db, db_len, 0) == 0)
return packet_error; /* The error is set by make_lex_string(). */
- if (mpvio->auth_info.user_name)
- my_free(mpvio->auth_info.user_name);
- if (!(mpvio->auth_info.user_name= my_strndup(user, user_len, MYF(MY_WME))))
+ my_free(sctx->user);
+ if (!(sctx->user= my_strndup(user, user_len, MYF(MY_WME))))
return packet_error; /* The error is set by my_strdup(). */
- mpvio->auth_info.user_name_length= user_len;
+
+
+ /*
+ 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
+ pointer if connect failed.
+ */
+ thd->reset_db(NULL, 0);
if (!initialized)
{
@@ -8740,19 +8553,20 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
if (find_mpvio_user(mpvio))
return packet_error;
- if (!(mpvio->client_capabilities & CLIENT_PLUGIN_AUTH))
+ if (thd->client_capabilities & CLIENT_PLUGIN_AUTH)
{
- /*
- An old client is connecting
- */
- if (mpvio->client_capabilities & CLIENT_SECURE_CONNECTION)
+ if ((client_plugin + strlen(client_plugin)) >
+ (char *)net->read_pos + pkt_len)
+ return packet_error;
+ client_plugin= fix_plugin_ptr(client_plugin);
+ }
+ else
+ {
+ if (thd->client_capabilities & CLIENT_SECURE_CONNECTION)
client_plugin= native_password_plugin_name.str;
else
{
- /*
- A really old client is connecting
- */
- client_plugin= old_password_plugin_name.str;
+ client_plugin= old_password_plugin_name.str;
/*
For a passwordless accounts we use native_password_plugin.
But when an old 4.0 client connects to it, we change it to
@@ -8760,7 +8574,7 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
and client plugins don't match.
*/
if (mpvio->acl_user->auth_string.length == 0)
- mpvio->acl_user_plugin= old_password_plugin_name;
+ mpvio->acl_user->plugin= old_password_plugin_name;
}
}
@@ -8773,7 +8587,7 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
restarted and a server auth plugin will read the data that the client
has just send. Cache them to return in the next server_mpvio_read_packet().
*/
- if (my_strcasecmp(system_charset_info, mpvio->acl_user_plugin.str,
+ if (my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
plugin_name(mpvio->plugin)->str) != 0)
{
mpvio->cached_client_reply.pkt= passwd;
@@ -8801,8 +8615,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->net);
- passwd = (char*) mpvio->net->read_pos;
+ passwd_len= my_net_read(&mpvio->thd->net);
+ passwd= (char*)mpvio->thd->net.read_pos;
}
*buff= (uchar*) passwd;
@@ -8814,29 +8628,6 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
/**
- Make sure that when sending plugin supplued data to the client they
- are not considered a special out-of-band command, like e.g.
- \255 (error) or \254 (change user request packet).
- To avoid this we send plugin data packets starting with one of these
- 2 bytes "wrapped" in a command \1.
- For the above reason we have to wrap plugin data packets starting with
- \1 as well.
-*/
-
-#define IS_OUT_OF_BAND_PACKET(packet,packet_len) \
- ((packet_len) > 0 && \
- (*(packet) == 1 || *(packet) == 255 || *(packet) == 254))
-
-static inline int
-wrap_plguin_data_into_proper_command(NET *net,
- const uchar *packet, int packet_len)
-{
- DBUG_ASSERT(IS_OUT_OF_BAND_PACKET(packet, packet_len));
- return net_write_command(net, 1, (uchar *) "", 0, packet, packet_len);
-}
-
-
-/**
vio->write_packet() callback method for server authentication plugins
This function is called by a server authentication plugin, when it wants
@@ -8851,29 +8642,31 @@ static int server_mpvio_write_packet(MYSQL_PLUGIN_VIO *param,
{
MPVIO_EXT *mpvio= (MPVIO_EXT *) param;
int res;
-
DBUG_ENTER("server_mpvio_write_packet");
- /*
- Reset cached_client_reply if not an old client doing mysql_change_user,
- as this is where the password from COM_CHANGE_USER is stored.
- */
- if (!((!(mpvio->client_capabilities & CLIENT_PLUGIN_AUTH)) &&
- mpvio->status == MPVIO_EXT::RESTART &&
- mpvio->cached_client_reply.plugin ==
- ((st_mysql_auth *) (plugin_decl(mpvio->plugin)->info))->client_auth_plugin
- ))
- mpvio->cached_client_reply.pkt= 0;
+
+ /* 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);
else if (mpvio->status == MPVIO_EXT::RESTART)
res= send_plugin_request_packet(mpvio, packet, packet_len);
- else if (IS_OUT_OF_BAND_PACKET(packet, packet_len))
- res= wrap_plguin_data_into_proper_command(mpvio->net, packet, packet_len);
+ else if (packet_len > 0 && (*packet == 1 || *packet == 255 || *packet == 254))
+ {
+ /*
+ we cannot allow plugin data packet to start from 255 or 254 -
+ as the client will treat it as an error or "change plugin" packet.
+ We'll escape these bytes with \1. Consequently, we
+ have to escape \1 byte too.
+ */
+ res= net_write_command(&mpvio->thd->net, 1, (uchar*)"", 0,
+ packet, packet_len);
+ }
else
{
- res= my_net_write(mpvio->net, packet, packet_len) ||
- net_flush(mpvio->net);
+ res= my_net_write(&mpvio->thd->net, packet, packet_len) ||
+ net_flush(&mpvio->thd->net);
}
mpvio->packets_written++;
DBUG_RETURN(res);
@@ -8893,7 +8686,6 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
{
MPVIO_EXT *mpvio= (MPVIO_EXT *) param;
ulong pkt_len;
-
DBUG_ENTER("server_mpvio_read_packet");
if (mpvio->packets_written == 0)
{
@@ -8901,10 +8693,10 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
plugin wants to read the data without sending anything first.
send an empty packet to force a server handshake packet to be sent
*/
- if (mpvio->write_packet(mpvio, 0, 0))
+ if (server_mpvio_write_packet(mpvio, 0, 0))
pkt_len= packet_error;
else
- pkt_len= my_net_read(mpvio->net);
+ pkt_len= my_net_read(&mpvio->thd->net);
}
else if (mpvio->cached_client_reply.pkt)
{
@@ -8929,26 +8721,18 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
DBUG_RETURN ((int) mpvio->cached_client_reply.pkt_len);
}
- /* older clients don't support change of client plugin request */
- if (!(mpvio->client_capabilities & CLIENT_PLUGIN_AUTH))
- {
- mpvio->status= MPVIO_EXT::FAILURE;
- pkt_len= packet_error;
- goto err;
- }
-
/*
But if the client has used the wrong plugin, the cached data are
useless. Furthermore, we have to send a "change plugin" request
to the client.
*/
- if (mpvio->write_packet(mpvio, 0, 0))
+ if (server_mpvio_write_packet(mpvio, 0, 0))
pkt_len= packet_error;
else
- pkt_len= my_net_read(mpvio->net);
+ pkt_len= my_net_read(&mpvio->thd->net);
}
else
- pkt_len= my_net_read(mpvio->net);
+ pkt_len= my_net_read(&mpvio->thd->net);
if (pkt_len == packet_error)
goto err;
@@ -8966,15 +8750,16 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
goto err;
}
else
- *buf= mpvio->net->read_pos;
+ *buf= mpvio->thd->net.read_pos;
DBUG_RETURN((int)pkt_len);
err:
if (mpvio->status == MPVIO_EXT::FAILURE)
{
- inc_host_errors(mpvio->ip);
- my_error(ER_HANDSHAKE_ERROR, MYF(0));
+ inc_host_errors(mpvio->thd->security_ctx.ip);
+ if (!mpvio->thd->is_error())
+ my_error(ER_HANDSHAKE_ERROR, MYF(0));
}
DBUG_RETURN(-1);
}
@@ -8987,13 +8772,12 @@ static void server_mpvio_info(MYSQL_PLUGIN_VIO *vio,
MYSQL_PLUGIN_VIO_INFO *info)
{
MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
- mpvio_info(mpvio->net->vio, info);
+ mpvio_info(mpvio->thd->net.vio, info);
}
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user)
{
-#if defined(HAVE_OPENSSL)
+#ifdef HAVE_OPENSSL
Vio *vio= thd->net.vio;
SSL *ssl= (SSL *) vio->ssl_arg;
X509 *cert;
@@ -9009,7 +8793,7 @@ static bool acl_check_ssl(THD *thd, const 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. */
@@ -9095,7 +8879,6 @@ static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user)
}
return 1;
}
-#endif
static int do_auth_once(THD *thd, const LEX_STRING *auth_plugin_name,
@@ -9103,24 +8886,21 @@ static int do_auth_once(THD *thd, const LEX_STRING *auth_plugin_name,
{
int res= CR_OK, old_status= MPVIO_EXT::FAILURE;
bool unlock_plugin= false;
- plugin_ref plugin;
+ plugin_ref plugin= NULL;
if (auth_plugin_name->str == native_password_plugin_name.str)
plugin= native_password_plugin;
- else
#ifndef EMBEDDED_LIBRARY
- if (auth_plugin_name->str == old_password_plugin_name.str)
+ 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,
MYSQL_AUTHENTICATION_PLUGIN)))
unlock_plugin= true;
- else
#endif
- plugin= NULL;
-
+
mpvio->plugin= plugin;
old_status= mpvio->status;
-
+
if (plugin)
{
st_mysql_auth *auth= (st_mysql_auth *) plugin_decl(plugin)->info;
@@ -9151,47 +8931,6 @@ static int do_auth_once(THD *thd, const LEX_STRING *auth_plugin_name,
}
-static void
-server_mpvio_initialize(THD *thd, MPVIO_EXT *mpvio, uint connect_errors,
- Thd_charset_adapter *charset_adapter)
-{
- memset(mpvio, 0, sizeof(MPVIO_EXT));
- mpvio->read_packet= server_mpvio_read_packet;
- mpvio->write_packet= server_mpvio_write_packet;
- mpvio->info= server_mpvio_info;
- mpvio->auth_info.host_or_ip= thd->security_ctx->host_or_ip;
- mpvio->auth_info.host_or_ip_length=
- (unsigned int) strlen(thd->security_ctx->host_or_ip);
- mpvio->auth_info.user_name= NULL;
- mpvio->auth_info.user_name_length= 0;
- mpvio->connect_errors= connect_errors;
- mpvio->status= MPVIO_EXT::FAILURE;
-
- mpvio->client_capabilities= thd->client_capabilities;
- mpvio->mem_root= thd->mem_root;
- mpvio->scramble= thd->scramble;
- mpvio->rand= &thd->rand;
- mpvio->thread_id= thd->thread_id;
- mpvio->server_status= &thd->server_status;
- mpvio->net= &thd->net;
- mpvio->ip= thd->security_ctx->ip;
- mpvio->host= thd->security_ctx->host;
- mpvio->charset_adapter= charset_adapter;
-}
-
-
-static void
-server_mpvio_update_thd(THD *thd, MPVIO_EXT *mpvio)
-{
- thd->client_capabilities= mpvio->client_capabilities;
- thd->max_client_packet_length= mpvio->max_client_packet_length;
- if (mpvio->client_capabilities & CLIENT_INTERACTIVE)
- thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
- thd->security_ctx->user= mpvio->auth_info.user_name;
- if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
- thd->variables.sql_mode|= MODE_IGNORE_SPACE;
-}
-
/**
Perform the handshake, authorize the client and update thd sctx variables.
@@ -9206,44 +8945,35 @@ server_mpvio_update_thd(THD *thd, MPVIO_EXT *mpvio)
@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;
- Thd_charset_adapter charset_adapter(thd);
-
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");
+
compile_time_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH);
- server_mpvio_initialize(thd, &mpvio, connect_errors, &charset_adapter);
+ bzero(&mpvio, sizeof(mpvio));
+ mpvio.read_packet= server_mpvio_read_packet;
+ mpvio.write_packet= server_mpvio_write_packet;
+ mpvio.info= server_mpvio_info;
+ mpvio.thd= thd;
+ mpvio.connect_errors= connect_errors;
+ mpvio.status= MPVIO_EXT::FAILURE;
DBUG_PRINT("info", ("com_change_user_pkt_len=%u", com_change_user_pkt_len));
- /*
- 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
- pointer if connect failed.
- */
- thd->reset_db(NULL, 0);
-
if (command == COM_CHANGE_USER)
{
mpvio.packets_written++; // pretend that a server handshake packet was sent
mpvio.packets_read++; // take COM_CHANGE_USER packet into account
- /* Clear variables that are allocated */
- thd->user_connect= 0;
-
if (parse_com_change_user_packet(&mpvio, com_change_user_pkt_len))
- {
- server_mpvio_update_thd(thd, &mpvio);
DBUG_RETURN(1);
- }
DBUG_ASSERT(mpvio.status == MPVIO_EXT::RESTART ||
mpvio.status == MPVIO_EXT::SUCCESS);
@@ -9251,21 +8981,21 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
else
{
/* mark the thd as having no scramble yet */
- mpvio.scramble[SCRAMBLE_LENGTH]= 1;
-
+ thd->scramble[SCRAMBLE_LENGTH]= 1;
+
/*
- perform the first authentication attempt, with the default plugin.
- This sends the server handshake packet, reads the client reply
- with a user name, and performs the authentication if everyone has used
- the correct plugin.
+ perform the first authentication attempt, with the default plugin.
+ This sends the server handshake packet, reads the client reply
+ with a user name, and performs the authentication if everyone has used
+ the correct plugin.
*/
res= do_auth_once(thd, auth_plugin_name, &mpvio);
}
/*
- retry the authentication, if - after receiving the user name -
- we found that we need to switch to a non-default plugin
+ retry the authentication, if - after receiving the user name -
+ we found that we need to switch to a non-default plugin
*/
if (mpvio.status == MPVIO_EXT::RESTART)
{
@@ -9277,8 +9007,6 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
res= do_auth_once(thd, auth_plugin_name, &mpvio);
}
- server_mpvio_update_thd(thd, &mpvio);
-
Security_context *sctx= thd->security_ctx;
const ACL_USER *acl_user= mpvio.acl_user;
@@ -9290,19 +9018,18 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
if sctx->user is unset it's protocol failure, bad packet.
*/
- if (mpvio.auth_info.user_name)
+ if (sctx->user)
{
- if (strcmp(mpvio.auth_info.authenticated_as, mpvio.auth_info.user_name))
+ if (strcmp(sctx->priv_user, sctx->user))
{
general_log_print(thd, command, "%s@%s as %s on %s",
- mpvio.auth_info.user_name, mpvio.auth_info.host_or_ip,
- mpvio.auth_info.authenticated_as ?
- mpvio.auth_info.authenticated_as : "anonymous",
+ sctx->user, sctx->host_or_ip,
+ sctx->priv_user[0] ? sctx->priv_user : "anonymous",
mpvio.db.str ? mpvio.db.str : (char*) "");
}
else
general_log_print(thd, command, (char*) "%s@%s on %s",
- mpvio.auth_info.user_name, mpvio.auth_info.host_or_ip,
+ sctx->user, sctx->host_or_ip,
mpvio.db.str ? mpvio.db.str : (char*) "");
}
@@ -9311,8 +9038,8 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
DBUG_ASSERT(mpvio.status == MPVIO_EXT::FAILURE);
if (!thd->is_error())
- login_failed_error(&mpvio, mpvio.auth_info.password_used);
- DBUG_RETURN (1);
+ login_failed_error(thd, thd->password);
+ DBUG_RETURN(1);
}
sctx->proxy_user[0]= 0;
@@ -9371,7 +9098,6 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
else
*sctx->priv_host= 0;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
OK. Let's check the SSL. Historically it was checked after the password,
as an additional layer, not instead of the password
@@ -9379,23 +9105,20 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
*/
if (acl_check_ssl(thd, acl_user))
{
- if (!thd->is_error())
- login_failed_error(&mpvio, thd->password);
+ login_failed_error(thd, thd->password);
DBUG_RETURN(1);
}
/* Don't allow the user to connect if he has done too many queries */
if ((acl_user->user_resource.questions || acl_user->user_resource.updates ||
acl_user->user_resource.conn_per_hour ||
- acl_user->user_resource.user_conn ||
+ acl_user->user_resource.user_conn ||
global_system_variables.max_user_connections) &&
get_or_create_user_conn(thd,
(opt_old_style_user_limits ? sctx->user : sctx->priv_user),
(opt_old_style_user_limits ? sctx->host_or_ip : sctx->priv_host),
&acl_user->user_resource))
DBUG_RETURN(1); // The error is set by get_or_create_user_conn()
-
-#endif
}
else
sctx->skip_grants();
@@ -9406,6 +9129,7 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
global_system_variables.max_user_connections) &&
check_for_max_user_connections(thd, thd->user_connect))
{
+ status_var_increment(denied_connections);
DBUG_RETURN(1); // The error is set in check_for_max_user_connections()
}
@@ -9422,7 +9146,8 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
!(thd->main_security_ctx.master_access & SUPER_ACL))
{
mysql_mutex_lock(&LOCK_connection_count);
- bool count_ok= (connection_count <= max_connections);
+ bool count_ok= (*thd->scheduler->connection_count <=
+ *thd->scheduler->max_connections);
mysql_mutex_unlock(&LOCK_connection_count);
if (!count_ok)
{ // too many connections
@@ -9446,6 +9171,7 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
/* mysql_change_db() has pushed the error message. */
if (thd->user_connect)
{
+ status_var_increment(thd->status_var.access_denied_errors);
decrease_user_connections(thd->user_connect);
thd->user_connect= 0;
}
@@ -9453,6 +9179,8 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
}
}
+ 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));
@@ -9461,16 +9189,6 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
else
my_ok(thd);
-#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY)
- /*
- Allow the network layer to skip big packets. Although a malicious
- authenticated session might use this to trick the server to read
- big packets indefinitely, this is a previously established behavior
- that needs to be preserved as to not break backwards compatibility.
- */
- thd->net.skip_big_packet= TRUE;
-#endif
-
/* Ready to handle queries */
DBUG_RETURN(0);
}
@@ -9489,16 +9207,17 @@ static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
uchar *pkt;
int pkt_len;
MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
-
+ THD *thd=mpvio->thd;
DBUG_ENTER("native_password_authenticate");
/* generate the scramble, or reuse the old one */
- if (mpvio->scramble[SCRAMBLE_LENGTH])
- create_random_string(mpvio->scramble, SCRAMBLE_LENGTH, mpvio->rand);
-
- /* send it to the client */
- if (mpvio->write_packet(mpvio, (uchar*) mpvio->scramble, SCRAMBLE_LENGTH + 1))
- DBUG_RETURN(CR_ERROR);
+ if (thd->scramble[SCRAMBLE_LENGTH])
+ {
+ create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
+ /* and send it to the client */
+ if (mpvio->write_packet(mpvio, (uchar*)thd->scramble, SCRAMBLE_LENGTH + 1))
+ return CR_ERROR;
+ }
/* reply and authenticate */
@@ -9532,7 +9251,7 @@ static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
plugins are involved.
Anyway, it still looks simple from a plugin point of view:
- "send the scramble, read the reply and authenticate"
+ "send the scramble, read the reply and authenticate".
All the magic is transparently handled by the server.
</digression>
*/
@@ -9555,11 +9274,11 @@ static int native_password_authenticate(MYSQL_PLUGIN_VIO *vio,
if (!mpvio->acl_user->salt_len)
DBUG_RETURN(CR_ERROR);
- DBUG_RETURN(check_scramble(pkt, mpvio->scramble, mpvio->acl_user->salt) ?
+ DBUG_RETURN(check_scramble(pkt, thd->scramble, mpvio->acl_user->salt) ?
CR_ERROR : CR_OK);
}
- inc_host_errors(mpvio->ip);
+ inc_host_errors(mpvio->thd->main_security_ctx.ip);
my_error(ER_HANDSHAKE_ERROR, MYF(0));
DBUG_RETURN(CR_ERROR);
}
@@ -9570,14 +9289,16 @@ static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
uchar *pkt;
int pkt_len;
MPVIO_EXT *mpvio= (MPVIO_EXT *) vio;
+ THD *thd=mpvio->thd;
/* generate the scramble, or reuse the old one */
- if (mpvio->scramble[SCRAMBLE_LENGTH])
- create_random_string(mpvio->scramble, SCRAMBLE_LENGTH, mpvio->rand);
-
- /* send it to the client */
- if (mpvio->write_packet(mpvio, (uchar*) mpvio->scramble, SCRAMBLE_LENGTH + 1))
- return CR_ERROR;
+ if (thd->scramble[SCRAMBLE_LENGTH])
+ {
+ create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
+ /* and send it to the client */
+ if (mpvio->write_packet(mpvio, (uchar*)thd->scramble, SCRAMBLE_LENGTH + 1))
+ return CR_ERROR;
+ }
/* read the reply and authenticate */
if ((pkt_len= mpvio->read_packet(mpvio, &pkt)) < 0)
@@ -9598,7 +9319,7 @@ static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
if (pkt_len == 0) /* no password */
return info->auth_string[0] ? CR_ERROR : CR_OK;
- if (secure_auth(mpvio))
+ if (secure_auth(thd))
return CR_ERROR;
info->password_used= PASSWORD_USED_YES;
@@ -9608,12 +9329,12 @@ static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
if (!mpvio->acl_user->salt_len)
return CR_ERROR;
- return check_scramble_323(pkt, mpvio->scramble,
+ return check_scramble_323(pkt, thd->scramble,
(ulong *) mpvio->acl_user->salt) ?
CR_ERROR : CR_OK;
}
- inc_host_errors(mpvio->ip);
+ inc_host_errors(mpvio->thd->main_security_ctx.ip);
my_error(ER_HANDSHAKE_ERROR, MYF(0));
return CR_ERROR;
}
@@ -9663,3 +9384,35 @@ mysql_declare_plugin(mysql_password)
}
mysql_declare_plugin_end;
+maria_declare_plugin(mysql_password)
+{
+ MYSQL_AUTHENTICATION_PLUGIN, /* type constant */
+ &native_password_handler, /* type descriptor */
+ native_password_plugin_name.str, /* Name */
+ "R.J.Silk, Sergei Golubchik", /* Author */
+ "Native MySQL authentication", /* Description */
+ PLUGIN_LICENSE_GPL, /* License */
+ NULL, /* Init function */
+ NULL, /* Deinit function */
+ 0x0100, /* Version (1.0) */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ "1.0", /* String version */
+ MariaDB_PLUGIN_MATURITY_BETA /* Maturity */
+},
+{
+ MYSQL_AUTHENTICATION_PLUGIN, /* type constant */
+ &old_password_handler, /* type descriptor */
+ old_password_plugin_name.str, /* Name */
+ "R.J.Silk, Sergei Golubchik", /* Author */
+ "Old MySQL-4.0 authentication", /* Description */
+ PLUGIN_LICENSE_GPL, /* License */
+ NULL, /* Init function */
+ NULL, /* Deinit function */
+ 0x0100, /* Version (1.0) */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ "1.0", /* String version */
+ MariaDB_PLUGIN_MATURITY_BETA /* Maturity */
+}
+maria_declare_plugin_end;