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/