diff options
Diffstat (limited to 'sql/sql_acl.cc')
-rw-r--r-- | sql/sql_acl.cc | 1155 |
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; |