sql_acl.cc | sql_acl.cc | |||
---|---|---|---|---|
skipping to change at line 863 | skipping to change at line 863 | |||
static ulong get_sort(uint count,...); | static ulong get_sort(uint count,...); | |||
static void init_check_host(void); | static void init_check_host(void); | |||
static void rebuild_check_host(void); | static void rebuild_check_host(void); | |||
static ACL_USER *find_acl_user(const char *host, const char *user, | static ACL_USER *find_acl_user(const char *host, const char *user, | |||
my_bool exact); | my_bool exact); | |||
static bool update_user_table(THD *, TABLE *table, const char *host, | static bool update_user_table(THD *, TABLE *table, const char *host, | |||
const char *user, | const char *user, | |||
const char *new_password, | const char *new_password, | |||
uint new_password_len, | uint new_password_len, | |||
enum mysql_user_table_field password_field, | enum mysql_user_table_field password_field, | |||
bool password_expired); | bool password_expired, bool is_user_table_pos itioned); | |||
static my_bool acl_load(THD *thd, TABLE_LIST *tables); | static my_bool acl_load(THD *thd, TABLE_LIST *tables); | |||
static my_bool grant_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); | static inline void get_grantor(THD *thd, char* grantor); | |||
/* | /* | |||
Enumeration of various ACL's and Hashes used in handle_grant_struct() | Enumeration of various ACL's and Hashes used in handle_grant_struct() | |||
*/ | */ | |||
enum enum_acl_lists | enum enum_acl_lists | |||
{ | { | |||
USER_ACL= 0, | USER_ACL= 0, | |||
DB_ACL, | DB_ACL, | |||
skipping to change at line 893 | skipping to change at line 893 | |||
@param acl_user The object where to store the salt | @param acl_user The object where to store the salt | |||
@param password The password hash containing the salt | @param password The password hash containing the salt | |||
@param password_len The length of the password hash | @param password_len The length of the password hash | |||
Despite the name of the function it is used when loading ACLs from disk | Despite the name of the function it is used when loading ACLs from disk | |||
to store the password hash in the ACL_USER object. | to store the password hash in the ACL_USER object. | |||
Note that it works only for native and "old" mysql authentication built-i n | Note that it works only for native and "old" mysql authentication built-i n | |||
plugins. | plugins. | |||
Assumption : user's authentication plugin information is available. | ||||
@return Password hash validation | @return Password hash validation | |||
@retval false Hash is of suitable length | @retval false Hash is of suitable length | |||
@retval true Hash is of wrong length or format | @retval true Hash is of wrong length or format | |||
*/ | */ | |||
static | static | |||
bool | bool | |||
set_user_salt(ACL_USER *acl_user, const char *password, uint password_len) | set_user_salt(ACL_USER *acl_user, const char *password, uint password_len) | |||
{ | { | |||
bool result= false; | bool result= false; | |||
skipping to change at line 1023 | skipping to change at line 1025 | |||
*/ | */ | |||
static my_bool acl_load(THD *thd, TABLE_LIST *tables) | static my_bool acl_load(THD *thd, TABLE_LIST *tables) | |||
{ | { | |||
TABLE *table; | TABLE *table; | |||
READ_RECORD read_record_info; | READ_RECORD read_record_info; | |||
my_bool return_val= TRUE; | my_bool return_val= TRUE; | |||
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; | bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; | |||
char tmp_name[NAME_LEN+1]; | char tmp_name[NAME_LEN+1]; | |||
int password_length; | int password_length; | |||
char *password; | ||||
uint password_len; | ||||
sql_mode_t old_sql_mode= thd->variables.sql_mode; | sql_mode_t old_sql_mode= thd->variables.sql_mode; | |||
bool password_expired= false; | ||||
DBUG_ENTER("acl_load"); | DBUG_ENTER("acl_load"); | |||
thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; | thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; | |||
grant_version++; /* Privileges updated */ | grant_version++; /* Privileges updated */ | |||
acl_cache->clear(1); // Clear locked hostname cac he | acl_cache->clear(1); // Clear locked hostname cac he | |||
init_sql_alloc(&global_acl_memory, ACL_ALLOC_BLOCK_SIZE, 0); | init_sql_alloc(&global_acl_memory, ACL_ALLOC_BLOCK_SIZE, 0); | |||
/* | /* | |||
skipping to change at line 1045 | skipping to change at line 1050 | |||
*/ | */ | |||
if (init_read_record(&read_record_info, thd, table=tables[0].table, | if (init_read_record(&read_record_info, thd, table=tables[0].table, | |||
NULL, 1, 1, FALSE)) | NULL, 1, 1, FALSE)) | |||
goto end; | goto end; | |||
table->use_all_columns(); | table->use_all_columns(); | |||
(void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100); | (void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100); | |||
allow_all_hosts=0; | allow_all_hosts=0; | |||
while (!(read_record_info.read_record(&read_record_info))) | while (!(read_record_info.read_record(&read_record_info))) | |||
{ | { | |||
password_expired= false; | ||||
/* Reading record from mysql.user */ | /* Reading record from mysql.user */ | |||
ACL_USER user; | ACL_USER user; | |||
memset(&user, 0, sizeof(user)); | memset(&user, 0, sizeof(user)); | |||
user.host.update_hostname(get_field(&global_acl_memory, | user.host.update_hostname(get_field(&global_acl_memory, | |||
table->field[MYSQL_USER_FIELD_HOST] )); | table->field[MYSQL_USER_FIELD_HOST] )); | |||
user.user= get_field(&global_acl_memory, | user.user= get_field(&global_acl_memory, | |||
table->field[MYSQL_USER_FIELD_USER]); | table->field[MYSQL_USER_FIELD_USER]); | |||
if (check_no_resolve && hostname_requires_resolving(user.host.get_host( ))) | if (check_no_resolve && hostname_requires_resolving(user.host.get_host( ))) | |||
{ | { | |||
sql_print_warning("'user' entry '%s@%s' " | sql_print_warning("'user' entry '%s@%s' " | |||
"ignored in --skip-name-resolve mode.", | "ignored in --skip-name-resolve mode.", | |||
user.user ? user.user : "", | user.user ? user.user : "", | |||
user.host.get_host() ? user.host.get_host() : ""); | user.host.get_host() ? user.host.get_host() : ""); | |||
continue; | continue; | |||
} | } | |||
/* Read legacy password */ | /* Read legacy password */ | |||
{ | password= get_field(&global_acl_memory, | |||
char *password= get_field(&global_acl_memory, | table->field[MYSQL_USER_FIELD_PASSWORD]); | |||
table->field[MYSQL_USER_FIELD_PASSWORD]); | password_len= password ? strlen(password) : 0; | |||
uint password_len= password ? strlen(password) : 0; | user.auth_string.str= password ? password : const_cast<char*>(""); | |||
user.auth_string.str= password ? password : const_cast<char*>(""); | user.auth_string.length= password_len; | |||
user.auth_string.length= password_len; | ||||
/* | ||||
Transform hex to octets and adjust the format. | ||||
*/ | ||||
if (set_user_salt(&user, password, password_len)) | ||||
{ | ||||
sql_print_warning("Found invalid password for user: '%s@%s'; " | ||||
"Ignoring user", user.user ? user.user : "", | ||||
user.host.get_host() ? user.host.get_host() : "") | ||||
; | ||||
continue; | ||||
} | ||||
/* | ||||
Set temporary plugin deduced from password length. If there are | ||||
enough fields in the user table the real plugin will be read later. | ||||
*/ | ||||
user.plugin= native_password_plugin_name; | ||||
if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323) | ||||
user.plugin= old_password_plugin_name; | ||||
} | ||||
{ | { | |||
uint next_field; | uint next_field; | |||
user.access= get_access(table,3,&next_field) & GLOBAL_ACLS; | user.access= get_access(table,3,&next_field) & GLOBAL_ACLS; | |||
/* | /* | |||
if it is pre 5.0.1 privilege table then map CREATE privilege on | if it is pre 5.0.1 privilege table then map CREATE privilege on | |||
CREATE VIEW & SHOW VIEW privileges | CREATE VIEW & SHOW VIEW privileges | |||
*/ | */ | |||
if (table->s->fields <= 31 && (user.access & CREATE_ACL)) | if (table->s->fields <= 31 && (user.access & CREATE_ACL)) | |||
user.access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL); | user.access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL); | |||
skipping to change at line 1220 | skipping to change at line 1206 | |||
get_field(&global_acl_memory, | get_field(&global_acl_memory, | |||
table->field[MYSQL_USER_FIELD_AUTHENTICATION_STRING ]); | table->field[MYSQL_USER_FIELD_AUTHENTICATION_STRING ]); | |||
if (!user.auth_string.str) | if (!user.auth_string.str) | |||
user.auth_string.str= const_cast<char*>(""); | user.auth_string.str= const_cast<char*>(""); | |||
user.auth_string.length= strlen(user.auth_string.str); | user.auth_string.length= strlen(user.auth_string.str); | |||
} | } | |||
else /* skip auth_string if there's no plugin */ | else /* skip auth_string if there's no plugin */ | |||
next_field++; | next_field++; | |||
} | } | |||
if (table->s->fields >= 43) | if (table->s->fields > MYSQL_USER_FIELD_PASSWORD_EXPIRED) | |||
{ | { | |||
char *tmpstr= get_field(&global_acl_memory, | char *tmpstr= get_field(&global_acl_memory, | |||
table->field[MYSQL_USER_FIELD_PASSWORD_EX PIRED]); | table->field[MYSQL_USER_FIELD_PASSWORD_EX PIRED]); | |||
if (tmpstr && (*tmpstr == 'Y' || *tmpstr == 'y')) | if (tmpstr && (*tmpstr == 'Y' || *tmpstr == 'y')) | |||
{ | { | |||
user.password_expired= true; | user.password_expired= true; | |||
if (!auth_plugin_supports_expiration(user.plugin.str)) | if (!auth_plugin_supports_expiration(user.plugin.str)) | |||
{ | { | |||
sql_print_warning("'user' entry '%s@%s' has the password igno re " | sql_print_warning("'user' entry '%s@%s' has the password igno re " | |||
"flag raised, but its authentication plugin " | "flag raised, but its authentication plugin " | |||
"doesn't support password expiration. " | "doesn't support password expiration. " | |||
"The user id will be ignored.", | "The user id will be ignored.", | |||
user.user ? user.user : "", | user.user ? user.user : "", | |||
user.host.get_host() ? user.host.get_host() : ""); | user.host.get_host() ? user.host.get_host() : ""); | |||
continue; | continue; | |||
} | } | |||
password_expired= true; | ||||
} | } | |||
} | } | |||
} // end if (table->s->fields >= 31) | } // end if (table->s->fields >= 31) | |||
else | else | |||
{ | { | |||
user.ssl_type=SSL_TYPE_NONE; | user.ssl_type=SSL_TYPE_NONE; | |||
#ifndef TO_BE_REMOVED | #ifndef TO_BE_REMOVED | |||
if (table->s->fields <= 13) | if (table->s->fields <= 13) | |||
{ // Without grant | { // Without grant | |||
if (user.access & CREATE_ACL) | if (user.access & CREATE_ACL) | |||
user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; | user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; | |||
} | } | |||
/* Convert old privileges */ | /* Convert old privileges */ | |||
user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL; | user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL; | |||
if (user.access & FILE_ACL) | if (user.access & FILE_ACL) | |||
user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL; | user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL; | |||
if (user.access & PROCESS_ACL) | if (user.access & PROCESS_ACL) | |||
user.access|= SUPER_ACL | EXECUTE_ACL; | user.access|= SUPER_ACL | EXECUTE_ACL; | |||
#endif | #endif | |||
} | } | |||
if (!user.plugin.length) | ||||
{ | ||||
/* | ||||
Set plugin deduced from password length. | ||||
We can reach here in two cases: | ||||
1. mysql.user doesn't have plugin field | ||||
2. Plugin field is empty | ||||
*/ | ||||
user.plugin= native_password_plugin_name; | ||||
if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323) | ||||
user.plugin= old_password_plugin_name; | ||||
} | ||||
/* | ||||
Transform hex to octets and adjust the format. | ||||
*/ | ||||
if (set_user_salt(&user, password, password_len)) | ||||
{ | ||||
sql_print_warning("Found invalid password for user: '%s@%s'; " | ||||
"Ignoring user", user.user ? user.user : "", | ||||
user.host.get_host() ? user.host.get_host() : "") | ||||
; | ||||
continue; | ||||
} | ||||
/* set_user_salt resets expiration flag so restore it */ | ||||
user.password_expired= password_expired; | ||||
(void) push_dynamic(&acl_users,(uchar*) &user); | (void) push_dynamic(&acl_users,(uchar*) &user); | |||
if (user.host.check_allow_all_hosts()) | if (user.host.check_allow_all_hosts()) | |||
allow_all_hosts=1; // Anyone can connect | allow_all_hosts=1; // Anyone can connect | |||
} | } | |||
} // END while reading records from the mysql.user table | } // END while reading records from the mysql.user table | |||
my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.eleme nts, | my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.eleme nts, | |||
sizeof(ACL_USER),(qsort_cmp) acl_compare); | sizeof(ACL_USER),(qsort_cmp) acl_compare); | |||
end_read_record(&read_record_info); | end_read_record(&read_record_info); | |||
freeze_size(&acl_users); | freeze_size(&acl_users); | |||
skipping to change at line 2263 | skipping to change at line 2277 | |||
bool change_password(THD *thd, const char *host, const char *user, | bool change_password(THD *thd, const char *host, const char *user, | |||
char *new_password) | char *new_password) | |||
{ | { | |||
TABLE_LIST tables; | TABLE_LIST tables; | |||
TABLE *table; | TABLE *table; | |||
/* Buffer should be extended when password length is extended. */ | /* Buffer should be extended when password length is extended. */ | |||
char buff[512]; | char buff[512]; | |||
ulong query_length; | ulong query_length; | |||
bool save_binlog_row_based; | bool save_binlog_row_based; | |||
uchar user_key[MAX_KEY_LENGTH]; | ||||
char *plugin_temp= NULL; | ||||
bool plugin_empty; | ||||
uint new_password_len= (uint) strlen(new_password); | uint new_password_len= (uint) strlen(new_password); | |||
bool result= 1; | bool result= 1; | |||
enum mysql_user_table_field password_field= MYSQL_USER_FIELD_PASSWORD; | enum mysql_user_table_field password_field= MYSQL_USER_FIELD_PASSWORD; | |||
DBUG_ENTER("change_password"); | DBUG_ENTER("change_password"); | |||
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'", | DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'", | |||
host,user,new_password)); | host,user,new_password)); | |||
DBUG_ASSERT(host != 0); // Ensured by parent | DBUG_ASSERT(host != 0); // Ensured by parent | |||
if (check_change_password(thd, host, user, new_password, new_password_len )) | if (check_change_password(thd, host, user, new_password, new_password_len )) | |||
DBUG_RETURN(1); | DBUG_RETURN(1); | |||
skipping to change at line 2312 | skipping to change at line 2329 | |||
thd->clear_current_stmt_binlog_format_row(); | thd->clear_current_stmt_binlog_format_row(); | |||
mysql_mutex_lock(&acl_cache->lock); | mysql_mutex_lock(&acl_cache->lock); | |||
ACL_USER *acl_user; | ACL_USER *acl_user; | |||
if (!(acl_user= find_acl_user(host, user, TRUE))) | if (!(acl_user= find_acl_user(host, user, TRUE))) | |||
{ | { | |||
mysql_mutex_unlock(&acl_cache->lock); | mysql_mutex_unlock(&acl_cache->lock); | |||
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0)); | my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0)); | |||
goto end; | goto end; | |||
} | } | |||
mysql_mutex_assert_owner(&acl_cache->lock); | ||||
table->use_all_columns(); | ||||
DBUG_ASSERT(host != '\0'); | ||||
table->field[MYSQL_USER_FIELD_HOST]->store(host, strlen(host), | ||||
system_charset_info); | ||||
table->field[MYSQL_USER_FIELD_USER]->store(user, strlen(user), | ||||
system_charset_info); | ||||
key_copy((uchar *) user_key, table->record[0], table->key_info, | ||||
table->key_info->key_length); | ||||
if (!table->file->ha_index_read_idx_map(table->record[0], 0, user_key, | ||||
HA_WHOLE_KEY, | ||||
HA_READ_KEY_EXACT)) | ||||
plugin_temp= (table->s->fields > MYSQL_USER_FIELD_PLUGIN) ? | ||||
get_field(&global_acl_memory, table->field[MYSQL_USER_FIEL | ||||
D_PLUGIN]) : NULL; | ||||
else | ||||
DBUG_ASSERT(FALSE); | ||||
plugin_empty= plugin_temp ? false: true; | ||||
if (acl_user->plugin.length == 0) | if (acl_user->plugin.length == 0) | |||
{ | { | |||
acl_user->plugin.length= default_auth_plugin_name.length; | acl_user->plugin.length= default_auth_plugin_name.length; | |||
acl_user->plugin.str= default_auth_plugin_name.str; | acl_user->plugin.str= default_auth_plugin_name.str; | |||
} | } | |||
if (new_password_len == 0) | if (new_password_len == 0) | |||
{ | { | |||
String *password_str= new (thd->mem_root) String(new_password, | String *password_str= new (thd->mem_root) String(new_password, | |||
skipping to change at line 2395 | skipping to change at line 2431 | |||
old_password_plugin_name.str) == 0) | old_password_plugin_name.str) == 0) | |||
{ | { | |||
password_field= MYSQL_USER_FIELD_PASSWORD; | password_field= MYSQL_USER_FIELD_PASSWORD; | |||
/* | /* | |||
Legacy code produced an error if the password hash didn't match the | Legacy code produced an error if the password hash didn't match the | |||
expectations. | expectations. | |||
*/ | */ | |||
if (new_password_len != 0) | if (new_password_len != 0) | |||
{ | { | |||
if (my_strcasecmp(system_charset_info, acl_user->plugin.str, | if (plugin_empty) | |||
native_password_plugin_name.str) == 0 && | ||||
new_password_len != SCRAMBLED_PASSWORD_CHAR_LENGTH) | ||||
{ | { | |||
my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH); | if (new_password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH) | |||
result= 1; | acl_user->plugin= native_password_plugin_name; | |||
mysql_mutex_unlock(&acl_cache->lock); | else if (new_password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323) | |||
goto end; | acl_user->plugin= old_password_plugin_name; | |||
else | ||||
{ | ||||
my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH | ||||
); | ||||
result= 1; | ||||
mysql_mutex_unlock(&acl_cache->lock); | ||||
goto end; | ||||
} | ||||
} | } | |||
else | else | |||
if (my_strcasecmp(system_charset_info, acl_user->plugin.str, | ||||
old_password_plugin_name.str) == 0 && | ||||
new_password_len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323) | ||||
{ | { | |||
my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH_3 | if (my_strcasecmp(system_charset_info, acl_user->plugin.str, | |||
23); | native_password_plugin_name.str) == 0 && | |||
result= 1; | new_password_len != SCRAMBLED_PASSWORD_CHAR_LENGTH) | |||
mysql_mutex_unlock(&acl_cache->lock); | { | |||
goto end; | my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH | |||
); | ||||
result= 1; | ||||
mysql_mutex_unlock(&acl_cache->lock); | ||||
goto end; | ||||
} | ||||
else if (my_strcasecmp(system_charset_info, acl_user->plugin.str, | ||||
old_password_plugin_name.str) == 0 && | ||||
new_password_len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323) | ||||
{ | ||||
my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH | ||||
_323); | ||||
result= 1; | ||||
mysql_mutex_unlock(&acl_cache->lock); | ||||
goto end; | ||||
} | ||||
} | } | |||
} | } | |||
else if (plugin_empty) | ||||
acl_user->plugin= native_password_plugin_name; | ||||
/* | /* | |||
Update loaded acl entry in memory. | Update loaded acl entry in memory. | |||
set_user_salt() stores a binary (compact) representation of the passw ord | set_user_salt() stores a binary (compact) representation of the passw ord | |||
in memory (acl_user->salt and salt_len). | in memory (acl_user->salt and salt_len). | |||
set_user_plugin() sets the appropriate plugin based on password lengt h and | set_user_plugin() sets the appropriate plugin based on password lengt h and | |||
if the length doesn't match a warning is issued. | if the length doesn't match a warning is issued. | |||
*/ | */ | |||
if (set_user_salt(acl_user, new_password, new_password_len)) | if (set_user_salt(acl_user, new_password, new_password_len)) | |||
{ | { | |||
skipping to change at line 2446 | skipping to change at line 2500 | |||
/* | /* | |||
An undefined password factory could very well mean that the password | An undefined password factory could very well mean that the password | |||
field is empty. | field is empty. | |||
*/ | */ | |||
new_password_len= 0; | new_password_len= 0; | |||
} | } | |||
if (update_user_table(thd, table, | if (update_user_table(thd, table, | |||
acl_user->host.get_host() ? acl_user->host.get_host () : "", | acl_user->host.get_host() ? acl_user->host.get_host () : "", | |||
acl_user->user ? acl_user->user : "", | acl_user->user ? acl_user->user : "", | |||
new_password, new_password_len, password_field, fal se)) | new_password, new_password_len, password_field, fal se, true)) | |||
{ | { | |||
mysql_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */ | mysql_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */ | |||
goto end; | goto end; | |||
} | } | |||
acl_cache->clear(1); // Clear locked hostname cac he | acl_cache->clear(1); // Clear locked hostname cac he | |||
mysql_mutex_unlock(&acl_cache->lock); | mysql_mutex_unlock(&acl_cache->lock); | |||
result= 0; | result= 0; | |||
query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120 s'", | query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120 s'", | |||
acl_user->user ? acl_user->user : "", | acl_user->user ? acl_user->user : "", | |||
skipping to change at line 2633 | skipping to change at line 2687 | |||
@see change_password | @see change_password | |||
*/ | */ | |||
static bool | static bool | |||
update_user_table(THD *thd, TABLE *table, | update_user_table(THD *thd, TABLE *table, | |||
const char *host, const char *user, | const char *host, const char *user, | |||
const char *new_password, uint new_password_len, | const char *new_password, uint new_password_len, | |||
enum mysql_user_table_field password_field, | enum mysql_user_table_field password_field, | |||
bool password_expired) | bool password_expired, bool is_user_table_positioned) | |||
{ | { | |||
char user_key[MAX_KEY_LENGTH]; | char user_key[MAX_KEY_LENGTH]; | |||
int error; | int error; | |||
DBUG_ENTER("update_user_table"); | DBUG_ENTER("update_user_table"); | |||
DBUG_PRINT("enter",("user: %s host: %s",user,host)); | DBUG_PRINT("enter",("user: %s host: %s",user,host)); | |||
table->use_all_columns(); | /* ALTER USER PASSWORD EXPIRE makes no sense on old system tables */ | |||
DBUG_ASSERT(host != '\0'); | if (table->s->fields <= MYSQL_USER_FIELD_PASSWORD_EXPIRED && | |||
table->field[MYSQL_USER_FIELD_HOST]->store(host, (uint) strlen(host), | password_expired) | |||
system_charset_info); | { | |||
table->field[MYSQL_USER_FIELD_USER]->store(user, (uint) strlen(user), | my_error(ER_BAD_FIELD_ERROR, MYF(0), "password_expired", "mysql.user"); | |||
system_charset_info); | DBUG_RETURN(1); | |||
key_copy((uchar *) user_key, table->record[0], table->key_info, | } | |||
table->key_info->key_length); | ||||
if (table->file->ha_index_read_idx_map(table->record[0], 0, | /* | |||
(uchar *) user_key, HA_WHOLE_KEY, | If this function is reached through change_password, the user record is | |||
HA_READ_KEY_EXACT)) | already available and hence need not be read again. | |||
*/ | ||||
if (!is_user_table_positioned) | ||||
{ | { | |||
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), | table->use_all_columns(); | |||
MYF(0)); /* purecov: deadcode */ | DBUG_ASSERT(host != '\0'); | |||
DBUG_RETURN(1); /* purecov: deadcode */ | table->field[MYSQL_USER_FIELD_HOST]->store(host, (uint) strlen(host), | |||
system_charset_info); | ||||
table->field[MYSQL_USER_FIELD_USER]->store(user, (uint) strlen(user), | ||||
system_charset_info); | ||||
key_copy((uchar *) user_key, table->record[0], table->key_info, | ||||
table->key_info->key_length); | ||||
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 */ | ||||
DBUG_RETURN(1); /* purecov: deadcode */ | ||||
} | ||||
} | } | |||
store_record(table,record[1]); | store_record(table,record[1]); | |||
/* | /* | |||
When the flag is on we're inside ALTER TABLE ... PASSWORD EXPIRE and we | When the flag is on we're inside ALTER TABLE ... PASSWORD EXPIRE and we | |||
have no password to update. | have no password to update. | |||
*/ | */ | |||
if (!password_expired) | if (!password_expired) | |||
{ | { | |||
table->field[(int) password_field]->store(new_password, new_password_le n, | table->field[(int) password_field]->store(new_password, new_password_le n, | |||
system_charset_info); | system_charset_info); | |||
if (new_password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323 && | if (new_password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323 && | |||
password_field == MYSQL_USER_FIELD_PASSWORD) | password_field == MYSQL_USER_FIELD_PASSWORD) | |||
{ | { | |||
WARN_DEPRECATED_41_PWD_HASH(thd); | WARN_DEPRECATED_41_PWD_HASH(thd); | |||
} | } | |||
} | } | |||
/* password_expired */ | if (table->s->fields > MYSQL_USER_FIELD_PASSWORD_EXPIRED) | |||
table->field[MYSQL_USER_FIELD_PASSWORD_EXPIRED]->store(password_expired ? | { | |||
"Y" : "N", 1, | /* update password_expired if present */ | |||
system_charset_inf | table->field[MYSQL_USER_FIELD_PASSWORD_EXPIRED]->store(password_expired | |||
o); | ? | |||
"Y" : "N", 1, | ||||
system_charset_i | ||||
nfo); | ||||
} | ||||
if ((error=table->file->ha_update_row(table->record[1],table->record[0])) && | if ((error=table->file->ha_update_row(table->record[1],table->record[0])) && | |||
error != HA_ERR_RECORD_IS_THE_SAME) | error != HA_ERR_RECORD_IS_THE_SAME) | |||
{ | { | |||
table->file->print_error(error,MYF(0)); /* purecov: deadcode */ | table->file->print_error(error,MYF(0)); /* purecov: deadcode */ | |||
DBUG_RETURN(1); | DBUG_RETURN(1); | |||
} | } | |||
DBUG_RETURN(0); | DBUG_RETURN(0); | |||
} | } | |||
skipping to change at line 2878 | skipping to change at line 2951 | |||
} | } | |||
else // if (table->file->ha_index_read_idx_map [..] | else // if (table->file->ha_index_read_idx_map [..] | |||
{ | { | |||
/* | /* | |||
There is a matching user record ------------------------------------- ----- | There is a matching user record ------------------------------------- ----- | |||
*/ | */ | |||
old_row_exists = 1; | old_row_exists = 1; | |||
store_record(table,record[1]); // Save copy for upd ate | store_record(table,record[1]); // Save copy for upd ate | |||
/* | ||||
GRANT statement using IDENTIFIED WITH clause can be used only to crea | ||||
te | ||||
user and apply privileges to it. Hence it throws an error when used o | ||||
n | ||||
existing users. | ||||
*/ | ||||
if (combo->uses_identified_with_clause) | ||||
{ | ||||
error= 1; | ||||
my_error(ER_GRANT_PLUGIN_USER_EXISTS, MYF(0), combo->user.length, | ||||
combo->user.str); | ||||
goto end; | ||||
} | ||||
/* 1. resolve plugins in the LEX_USER struct if needed */ | /* 1. resolve plugins in the LEX_USER struct if needed */ | |||
if (!combo->uses_identified_with_clause) | LEX_STRING old_plugin; | |||
/* | ||||
Get old plugin value from storage. | ||||
*/ | ||||
old_plugin.str= | ||||
get_field(thd->mem_root, table->field[MYSQL_USER_FIELD_PLUGIN]); | ||||
/* | ||||
It is important not to include the trailing '\0' in the string length | ||||
because otherwise the plugin hash search will fail. | ||||
*/ | ||||
if (old_plugin.str) | ||||
{ | { | |||
LEX_STRING old_plugin; | old_plugin.length= strlen(old_plugin.str); | |||
/* | /* | |||
Get old plugin value from storage. | Optimize for pointer comparision of built-in plugin name | |||
*/ | */ | |||
old_plugin.str= | optimize_plugin_compare_by_pointer(&old_plugin); | |||
get_field(thd->mem_root, table->field[MYSQL_USER_FIELD_PLUGIN]); | ||||
/* | /* | |||
It is important not to include the trailing '\0' in the string leng | Disable plugin change for existing rows with anything but | |||
th | the built in plugins. | |||
because otherwise the plugin hash search will fail. | The idea is that all built in plugins support | |||
IDENTIFIED BY ... and none of the external ones currently do. | ||||
*/ | */ | |||
if (old_plugin.str) | if ((combo->uses_identified_by_clause || | |||
combo->uses_identified_by_password_clause) && | ||||
!auth_plugin_is_built_in(old_plugin.str)) | ||||
{ | { | |||
old_plugin.length= strlen(old_plugin.str); | const char *new_plugin= (combo->plugin.str && combo->plugin.str[0]) | |||
? | ||||
/* | combo->plugin.str : default_auth_plugin_name.str; | |||
Optimize for pointer comparision of built-in plugin name | ||||
*/ | ||||
optimize_plugin_compare_by_pointer(&old_plugin); | ||||
/* | ||||
Disable plugin change for existing rows with anything but | ||||
the built in plugins. | ||||
The idea is that all built in plugins support | ||||
IDENTIFIED BY ... and none of the external ones currently do. | ||||
*/ | ||||
if ((combo->uses_identified_by_clause || | ||||
combo->uses_identified_by_password_clause) && | ||||
!auth_plugin_is_built_in(old_plugin.str)) | ||||
{ | ||||
const char *new_plugin= (combo->plugin.str && combo->plugin.str[0 | ||||
]) ? | ||||
combo->plugin.str : default_auth_plugin_name.str; | ||||
if (my_strcasecmp(system_charset_info, new_plugin, old_plugin.str | if (my_strcasecmp(system_charset_info, new_plugin, old_plugin.str)) | |||
)) | { | |||
{ | push_warning(thd, Sql_condition::WARN_LEVEL_WARN, | |||
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, | ER_SET_PASSWORD_AUTH_PLUGIN, ER(ER_SET_PASSWORD_AUTH_PLUGIN)); | |||
ER_SET_PASSWORD_AUTH_PLUGIN, ER(ER_SET_PASSWORD_AUTH_PLUGIN)) | } | |||
; | ||||
} | ||||
} | ||||
} | } | |||
combo->plugin= old_plugin; | ||||
} | } | |||
old_plugin.length= 0; | ||||
combo->plugin= old_plugin; | ||||
/* No value for plugin field means default plugin is used */ | /* | |||
if (combo->plugin.str == NULL || combo->plugin.str == '\0') | If the plugin value in user table is found to be null or an empty | |||
{ | string, the following steps are followed: | |||
combo->plugin.str= default_auth_plugin_name.str; | ||||
combo->plugin.length= default_auth_plugin_name.length; | ||||
} | ||||
if (combo->uses_identified_with_clause) | * If GRANT is used with IDENTIFIED BY PASSWORD clause, and the hash | |||
is found to be of mysql_native_password or mysql_old_password | ||||
type, the statement passes without an error and the password field | ||||
is updated accordingly. | ||||
* If GRANT is used with IDENTIFIED BY clause and the password is | ||||
provided as a plain string, hashing of the string is done according | ||||
to the value of old_passwords variable in the following way. | ||||
if old_passwords == 0, mysql_native hashing is used. | ||||
if old_passwords == 1, mysql_old hashing is used. | ||||
if old_passwords == 2, error. | ||||
* An empty password is considered to be of mysql_native type. | ||||
*/ | ||||
if (combo->plugin.str == NULL || combo->plugin.str == '\0') | ||||
{ | { | |||
/* | if (combo->uses_identified_by_password_clause) | |||
Don't allow old plugin fields to change. | ||||
*/ | ||||
char *old_plugin= get_field(thd->mem_root, | ||||
table->field[MYSQL_USER_FIELD_PLUGIN]); | ||||
if (old_plugin != NULL && | ||||
my_strcasecmp(system_charset_info, combo->plugin.str, old_plugin) | ||||
) | ||||
{ | { | |||
error= 1; | if ((combo->password.length == SCRAMBLED_PASSWORD_CHAR_LENGTH) || | |||
my_error(ER_GRANT_PLUGIN_USER_EXISTS, MYF(0), combo->user.length, | (combo->password.length == 0)) | |||
combo->user.str); | { | |||
goto end; | combo->plugin.str= native_password_plugin_name.str; | |||
combo->plugin.length= native_password_plugin_name.length; | ||||
} | ||||
else if (combo->password.length == SCRAMBLED_PASSWORD_CHAR_LENGTH_32 | ||||
3) | ||||
{ | ||||
combo->plugin.str= old_password_plugin_name.str; | ||||
combo->plugin.length= old_password_plugin_name.length; | ||||
} | ||||
else | ||||
{ | ||||
/* | ||||
If hash length doesn't match either with mysql_native hash lengt | ||||
h or | ||||
mysql_old hash length, throw an error. | ||||
*/ | ||||
my_error(ER_PASSWORD_FORMAT, MYF(0)); | ||||
error= 1; | ||||
goto end; | ||||
} | ||||
} | ||||
else | ||||
{ | ||||
/* | ||||
Handling of combo->plugin when IDENTIFIED BY PASSWORD clause is no | ||||
t | ||||
used, i.e. when the password hash is not provided within the GRANT | ||||
query. | ||||
*/ | ||||
if ((thd->variables.old_passwords == 1) && (combo->password.length ! | ||||
= 0)) | ||||
{ | ||||
combo->plugin.str= old_password_plugin_name.str; | ||||
combo->plugin.length= old_password_plugin_name.length; | ||||
} | ||||
else if ((thd->variables.old_passwords == 0) || | ||||
(combo->password.length == 0)) | ||||
{ | ||||
combo->plugin.str= native_password_plugin_name.str; | ||||
combo->plugin.length= native_password_plugin_name.length; | ||||
} | ||||
else | ||||
{ | ||||
/* If old_passwords variable is neither 0 nor 1, throw an error. * | ||||
/ | ||||
my_error(ER_PASSWORD_FORMAT, MYF(0)); | ||||
error= 1; | ||||
goto end; | ||||
} | ||||
} | } | |||
} | } | |||
if (!combo->uses_authentication_string_clause) | if (!combo->uses_authentication_string_clause) | |||
{ | { | |||
combo->auth.str= get_field(thd->mem_root, | combo->auth.str= get_field(thd->mem_root, | |||
table->field[MYSQL_USER_FIELD_AUTHENTICATION_STRING]); | table->field[MYSQL_USER_FIELD_AUTHENTICATION_STRING]); | |||
if (combo->auth.str) | if (combo->auth.str) | |||
combo->auth.length= strlen(combo->auth.str); | combo->auth.length= strlen(combo->auth.str); | |||
else | else | |||
skipping to change at line 3122 | skipping to change at line 3254 | |||
table->field[MYSQL_USER_FIELD_AUTHENTICATION_STRING]->set_notnull() ; | table->field[MYSQL_USER_FIELD_AUTHENTICATION_STRING]->set_notnull() ; | |||
} | } | |||
else | else | |||
{ | { | |||
my_error(ER_BAD_FIELD_ERROR, MYF(0), "plugin", "mysql.user"); | my_error(ER_BAD_FIELD_ERROR, MYF(0), "plugin", "mysql.user"); | |||
goto end; | goto end; | |||
} | } | |||
} | } | |||
/* if we have a password supplied we update the expiration field */ | /* if we have a password supplied we update the expiration field */ | |||
if (table->s->fields >= MYSQL_USER_FIELD_PASSWORD_EXPIRED && | if (table->s->fields > MYSQL_USER_FIELD_PASSWORD_EXPIRED && | |||
password_len > 0) | password_len > 0) | |||
table->field[MYSQL_USER_FIELD_PASSWORD_EXPIRED]->store("N", 1, | table->field[MYSQL_USER_FIELD_PASSWORD_EXPIRED]->store("N", 1, | |||
system_charset _info); | system_charset _info); | |||
} | } | |||
if (old_row_exists) | if (old_row_exists) | |||
{ | { | |||
/* | /* | |||
We should NEVER delete from the user table, as a uses can still | We should NEVER delete from the user table, as a uses can still | |||
use mysqld even if he doesn't have any privileges in the user table! | use mysqld even if he doesn't have any privileges in the user table! | |||
skipping to change at line 7787 | skipping to change at line 7919 | |||
false); | false); | |||
continue; | continue; | |||
} | } | |||
/* update the mysql.user table */ | /* update the mysql.user table */ | |||
enum mysql_user_table_field password_field= MYSQL_USER_FIELD_PASSWORD; | enum mysql_user_table_field password_field= MYSQL_USER_FIELD_PASSWORD; | |||
if (update_user_table(thd, table, | if (update_user_table(thd, table, | |||
acl_user->host.get_host() ? | acl_user->host.get_host() ? | |||
acl_user->host.get_host() : "", | acl_user->host.get_host() : "", | |||
acl_user->user ? acl_user->user : "", | acl_user->user ? acl_user->user : "", | |||
NULL, 0, password_field, true)) | NULL, 0, password_field, true, false)) | |||
{ | { | |||
result= true; | result= true; | |||
append_user(thd, &wrong_users, user_from, wrong_users.length() > 0, | append_user(thd, &wrong_users, user_from, wrong_users.length() > 0, | |||
false); | false); | |||
continue; | continue; | |||
} | } | |||
acl_user->password_expired= true; | acl_user->password_expired= true; | |||
some_passwords_expired= true; | some_passwords_expired= true; | |||
} | } | |||
skipping to change at line 11722 | skipping to change at line 11854 | |||
res= password_strength->get_password_strength(password); | res= password_strength->get_password_strength(password); | |||
plugin_unlock(0, plugin); | plugin_unlock(0, plugin); | |||
} | } | |||
return(res); | return(res); | |||
} | } | |||
/* called when new user is created or exsisting password is changed */ | /* called when new user is created or exsisting password is changed */ | |||
int check_password_policy(String *password) | int check_password_policy(String *password) | |||
{ | { | |||
plugin_ref plugin= my_plugin_lock_by_name(0, &validate_password_plugin_na | plugin_ref plugin; | |||
me, | String empty_string; | |||
MYSQL_VALIDATE_PASSWORD_PLUGIN) | ||||
; | if (!password) | |||
DBUG_ASSERT(password != NULL); | password= &empty_string; | |||
plugin= my_plugin_lock_by_name(0, &validate_password_plugin_name, | ||||
MYSQL_VALIDATE_PASSWORD_PLUGIN); | ||||
if (plugin) | if (plugin) | |||
{ | { | |||
st_mysql_validate_password *password_validate= | st_mysql_validate_password *password_validate= | |||
(st_mysql_validate_password *) plugin_decl(plugin)->i nfo; | (st_mysql_validate_password *) plugin_decl(plugin)->i nfo; | |||
if (!password_validate->validate_password(password)) | if (!password_validate->validate_password(password)) | |||
{ | { | |||
my_error(ER_NOT_VALID_PASSWORD, MYF(0)); | my_error(ER_NOT_VALID_PASSWORD, MYF(0)); | |||
plugin_unlock(0, plugin); | plugin_unlock(0, plugin); | |||
return (1); | return (1); | |||
End of changes. 40 change blocks. | ||||
129 lines changed or deleted | 271 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |