Skip to content

Commit

Permalink
validate SET PASSWORD
Browse files Browse the repository at this point in the history
  • Loading branch information
vuvova committed Dec 4, 2014
1 parent dccd85e commit b814046
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 106 deletions.
11 changes: 11 additions & 0 deletions mysql-test/suite/plugins/r/simple_password_check.result
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ create user foo1 identified by '123:qwe:4SD!';
ERROR HY000: Your password does not satisfy the current policy requirements
create user foo1 identified by '123:qwe:ASD4';
ERROR HY000: Your password does not satisfy the current policy requirements
create user foo1 identified by '123:qwe:ASD!';
set password for foo1 = password('qwe:-23:ASD!');
ERROR HY000: Your password does not satisfy the current policy requirements
set password for foo1 = old_password('4we:123:ASD!');
ERROR HY000: Your password does not satisfy the current policy requirements
set password for foo1 = password('qwe:123:4SD!');
ERROR HY000: Your password does not satisfy the current policy requirements
set password for foo1 = old_password('qwe:123:ASD4');
ERROR HY000: Your password does not satisfy the current policy requirements
set password for foo1 = password('qwe:123:ASD!');
drop user foo1;
uninstall plugin simple_password_check;
create user foo1 identified by 'pwd';
drop user foo1;
12 changes: 12 additions & 0 deletions mysql-test/suite/plugins/t/simple_password_check.test
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ create user foo1 identified by '123:qwe:4SD!';
--error ER_NOT_VALID_PASSWORD
create user foo1 identified by '123:qwe:ASD4';

create user foo1 identified by '123:qwe:ASD!';
--error ER_NOT_VALID_PASSWORD
set password for foo1 = password('qwe:-23:ASD!');
--error ER_NOT_VALID_PASSWORD
set password for foo1 = old_password('4we:123:ASD!');
--error ER_NOT_VALID_PASSWORD
set password for foo1 = password('qwe:123:4SD!');
--error ER_NOT_VALID_PASSWORD
set password for foo1 = old_password('qwe:123:ASD4');
set password for foo1 = password('qwe:123:ASD!');
drop user foo1;

uninstall plugin simple_password_check;

create user foo1 identified by 'pwd';
Expand Down
9 changes: 2 additions & 7 deletions sql/set_var.cc
Original file line number Diff line number Diff line change
Expand Up @@ -851,10 +851,7 @@ int set_var_user::update(THD *thd)
int set_var_password::check(THD *thd)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
user= get_current_user(thd, user);
/* Returns 1 as the function sends error to client */
return check_change_password(thd, user->host.str, user->user.str,
password, strlen(password)) ? 1 : 0;
return check_change_password(thd, user);
#else
return 0;
#endif
Expand All @@ -863,9 +860,7 @@ int set_var_password::check(THD *thd)
int set_var_password::update(THD *thd)
{
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Returns 1 as the function sends error to client */
return change_password(thd, user->host.str, user->user.str, password) ?
1 : 0;
return change_password(thd, user);
#else
return 0;
#endif
Expand Down
4 changes: 1 addition & 3 deletions sql/set_var.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,10 +321,8 @@ class set_var_user: public set_var_base
class set_var_password: public set_var_base
{
LEX_USER *user;
char *password;
public:
set_var_password(LEX_USER *user_arg,char *password_arg)
:user(user_arg), password(password_arg)
set_var_password(LEX_USER *user_arg) :user(user_arg)
{}
int check(THD *thd);
int update(THD *thd);
Expand Down
99 changes: 54 additions & 45 deletions sql/sql_acl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ ulong role_global_merges= 0, role_db_merges= 0, role_table_merges= 0,
#endif

#ifndef NO_EMBEDDED_ACCESS_CHECKS
static bool fix_and_copy_user(LEX_USER *to, LEX_USER *from, THD *thd);
static void update_hostname(acl_host_and_ip *host, const char *hostname);
static ulong get_sort(uint count,...);
static bool show_proxy_grants (THD *, const char *, const char *,
Expand Down Expand Up @@ -965,10 +966,25 @@ static bool fix_user_plugin_ptr(ACL_USER *user)


/*
transform equivalent LEX_USER values to one:
username IDENTIFIED BY PASSWORD xxx
username IDENTIFIED VIA mysql_native_password USING xxx
etc
Validates the password, calculates password hash, transforms
equivalent LEX_USER representations.
Upon entering this function:
- if user->plugin is specified, user->auth is the plugin auth data.
- if user->plugin is mysql_native_password or mysql_old_password,
user->auth if the password hash, and LEX_USER is transformed
to match the next case (that is, user->plugin is cleared).
- if user->plugin is NOT specified, built-in auth is assumed, that is
mysql_native_password or mysql_old_password. In that case,
user->auth is the password hash. And user->password is the original
plain-text password. Either one can be set or even both.
Upon exiting this function:
- user->password is the password hash, as the mysql.user.password column
- user->plugin is the plugin name, as the mysql.user.plugin column
- user->auth is the plugin auth data, as the mysql.user.authentication_string column
*/
static bool fix_lex_user(THD *thd, LEX_USER *user)
{
Expand Down Expand Up @@ -1005,7 +1021,7 @@ static bool fix_lex_user(THD *thd, LEX_USER *user)
}
}

if (user->password.length)
if (user->password.length && !user->auth.length)
{
size_t scramble_length;
void (*make_scramble)(char *, const char *, size_t);
Expand Down Expand Up @@ -2691,72 +2707,57 @@ static int check_alter_user(THD *thd, const char *host, const char *user)
Check if the user is allowed to change password
@param thd THD
@param host Hostname for the user
@param user User name
@param new_password New password
@param new_password_len The length of the new password
new_password cannot be NULL
@param user User, hostname, new password or password hash
@return Error status
@retval 0 OK
@retval 1 ERROR; In this case the error is sent to the client.
*/

int check_change_password(THD *thd, const char *host, const char *user,
char *new_password, uint new_password_len)
bool check_change_password(THD *thd, LEX_USER *user)
{
if (check_alter_user(thd, host, user))
return 1;
LEX_USER *real_user= get_current_user(thd, user);

size_t len= strlen(new_password);
if (len && len != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
{
my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
return 1;
}
return 0;
if (fix_and_copy_user(real_user, user, thd))
return true;

*user= *real_user;

return check_alter_user(thd, user->host.str, user->user.str);
}


/**
Change a password for a user.
@param thd THD
@param host Hostname
@param user User name
@param new_password New password hash for host@user
@param user User, hostname, new password hash
@return Error code
@retval 0 ok
@retval 1 ERROR; In this case the error is sent to the client.
*/
bool change_password(THD *thd, const char *host, const char *user,
char *new_password)
bool change_password(THD *thd, LEX_USER *user)
{
TABLE_LIST tables[TABLES_MAX];
/* Buffer should be extended when password length is extended. */
char buff[512];
ulong query_length= 0;
enum_binlog_format save_binlog_format;
uint new_password_len= (uint) strlen(new_password);
int result=0;
const CSET_STRING query_save __attribute__((unused)) = thd->query_string;

DBUG_ENTER("change_password");
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
host,user,new_password));
DBUG_ASSERT(host != 0); // Ensured by parent

if (check_change_password(thd, host, user, new_password, new_password_len))
DBUG_RETURN(1);
user->host.str, user->user.str, user->password.str));
DBUG_ASSERT(user->host.str != 0); // Ensured by parent

if (mysql_bin_log.is_open() ||
(WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0)))
{
query_length= sprintf(buff, "SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'",
safe_str(user), safe_str(host), new_password);
safe_str(user->user.str), safe_str(user->host.str),
safe_str(user->password.str));
}

if (WSREP(thd) && !IF_WSREP(thd->wsrep_applier, 0))
Expand All @@ -2781,7 +2782,7 @@ bool change_password(THD *thd, const char *host, const char *user,

mysql_mutex_lock(&acl_cache->lock);
ACL_USER *acl_user;
if (!(acl_user= find_user_exact(host, user)))
if (!(acl_user= find_user_exact(user->host.str, user->user.str)))
{
mysql_mutex_unlock(&acl_cache->lock);
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
Expand All @@ -2792,10 +2793,10 @@ bool change_password(THD *thd, const char *host, const char *user,
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(&acl_memroot, 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);
acl_user->auth_string.str= strmake_root(&acl_memroot, user->password.str, user->password.length);
acl_user->auth_string.length= user->password.length;
set_user_salt(acl_user, user->password.str, user->password.length);
set_user_plugin(acl_user, user->password.length);
}
else
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE,
Expand All @@ -2804,7 +2805,7 @@ bool change_password(THD *thd, const char *host, const char *user,
if (update_user_table(thd, tables[USER_TABLE].table,
safe_str(acl_user->host.hostname),
safe_str(acl_user->user.str),
new_password, new_password_len))
user->password.str, user->password.length))
{
mysql_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */
goto end;
Expand Down Expand Up @@ -5660,11 +5661,8 @@ static bool has_auth(LEX_USER *user, LEX *lex)
lex->mqh.specified_limits;
}

static bool copy_and_check_auth(LEX_USER *to, LEX_USER *from, THD *thd)
static bool fix_and_copy_user(LEX_USER *to, LEX_USER *from, THD *thd)
{
if (fix_lex_user(thd, from))
return true;

if (to != from)
{
/* preserve authentication information, if LEX_USER was reallocated */
Expand All @@ -5673,6 +5671,17 @@ static bool copy_and_check_auth(LEX_USER *to, LEX_USER *from, THD *thd)
to->auth= from->auth;
}

if (fix_lex_user(thd, to))
return true;

return false;
}

static bool copy_and_check_auth(LEX_USER *to, LEX_USER *from, THD *thd)
{
if (fix_and_copy_user(to, from, thd))
return true;

// if changing auth for an existing user
if (has_auth(to, thd->lex) && find_user_exact(to->host.str, to->user.str))
{
Expand Down
6 changes: 2 additions & 4 deletions sql/sql_acl.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,8 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len);
bool acl_getroot(Security_context *sctx, char *user, char *host,
char *ip, char *db);
bool acl_check_host(const char *host, const char *ip);
int check_change_password(THD *thd, const char *host, const char *user,
char *password, uint password_len);
bool change_password(THD *thd, const char *host, const char *user,
char *password);
bool check_change_password(THD *thd, LEX_USER *user);
bool change_password(THD *thd, LEX_USER *user);

bool mysql_grant_role(THD *thd, List<LEX_USER> &user_list, bool revoke);
bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
Expand Down
Loading

0 comments on commit b814046

Please sign in to comment.