Skip to content

Commit c8cf0a8

Browse files
author
Nirbhay Choubey
committed
Bug #14698309: 'MYSQLADMIN PASSWORD' IS INCOMPATIBLE WITH
THE "PASSWORD EXPIRED" FLAG mysqladmin ... password ... was expecting that it can always execute commands other than SET PASSWORD against the server. And it was using this opportunity to try to be smart and detect if "old" pre-4.1 passwords are being used by this server. If any of these commands failed it was just giving up. This is obviously incompatible with password expiration, as the only accepted command in this state would be SET PASSWORD. And this renders mysqldump .. password .. unusable as an option to update the password for such accounts. Fixed mysqldump to detect this particular error code sent by the password expiration check and react by skipping the auto-adjustment (and logging an warning about it if run with --verbose) and trying its best according to the parameters supplied to it. Added a testcase.
1 parent 2646d60 commit c8cf0a8

1 file changed

Lines changed: 67 additions & 22 deletions

File tree

client/mysqladmin.cc

Lines changed: 67 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <mysql.h>
2626
#include <sql_common.h>
2727
#include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
28+
#include <mysqld_error.h> /* to check server error codes */
2829

2930
#define ADMIN_VERSION "8.42"
3031
#define MAX_MYSQL_VAR 512
@@ -625,7 +626,8 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
625626

626627
for (; argc > 0 ; argv++,argc--)
627628
{
628-
switch (find_type(argv[0],&command_typelib, FIND_TYPE_BASIC)) {
629+
int option;
630+
switch (option= find_type(argv[0], &command_typelib, FIND_TYPE_BASIC)) {
629631
case ADMIN_CREATE:
630632
{
631633
char buff[FN_REFLEN+20];
@@ -939,6 +941,11 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
939941
char buff[128],crypted_pw[64];
940942
time_t start_time;
941943
char *typed_password= NULL, *verified= NULL;
944+
bool log_off= true, err= false;
945+
int retry_count= 0; /* Attempts to SET PASSWORD */
946+
947+
bool old= (option == ADMIN_OLD_PASSWORD);
948+
942949
/* Do initialization the same way as we do in mysqld */
943950
start_time=time((time_t*) 0);
944951
randominit(&rand_st,(ulong) start_time,(ulong) start_time/2);
@@ -956,16 +963,15 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
956963
if (strcmp(typed_password, verified) != 0)
957964
{
958965
my_printf_error(0,"Passwords don't match",MYF(ME_BELL));
959-
return -1;
966+
err= true;
967+
goto error;
960968
}
961969
}
962970
else
963971
typed_password= argv[1];
964972

965973
if (typed_password[0])
966974
{
967-
bool old= (find_type(argv[0], &command_typelib, FIND_TYPE_BASIC) ==
968-
ADMIN_OLD_PASSWORD);
969975
#ifdef __WIN__
970976
size_t pw_len= strlen(typed_password);
971977
if (pw_len > 1 && typed_password[0] == '\'' &&
@@ -974,16 +980,23 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
974980
" your command\nline client, as you might have expected.\n");
975981
#endif
976982
/*
977-
If we don't already know to use an old-style password, see what
978-
the server is using
983+
If we don't already know to use an old-style password, see
984+
(if possible) what the server is using.
979985
*/
980986
if (!old)
981987
{
982988
if (mysql_query(mysql, "SHOW VARIABLES LIKE 'old_passwords'"))
983989
{
984-
my_printf_error(0, "Could not determine old_passwords setting from server; error: '%s'",
985-
error_flags, mysql_error(mysql));
986-
return -1;
990+
bool fatal= (mysql_errno(mysql) != ER_MUST_CHANGE_PASSWORD);
991+
if (fatal || opt_verbose)
992+
my_printf_error(0, "Could not determine old_passwords setting "
993+
"from server; error: '%s'.", error_flags,
994+
mysql_error(mysql));
995+
if (fatal)
996+
{
997+
err= true;
998+
goto error;
999+
}
9871000
}
9881001
else
9891002
{
@@ -992,42 +1005,64 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
9921005
{
9931006
my_printf_error(0,
9941007
"Could not get old_passwords setting from "
995-
"server; error: '%s'",
996-
error_flags, mysql_error(mysql));
997-
return -1;
1008+
"server; error: '%s'.",
1009+
error_flags, mysql_error(mysql));
1010+
err= true;
1011+
goto error;
9981012
}
9991013
if (!mysql_num_rows(res))
10001014
old= 1;
10011015
else
10021016
{
10031017
MYSQL_ROW row= mysql_fetch_row(res);
1004-
old= !strncmp(row[1], "ON", 2);
1018+
old= (!strncmp(row[1], "ON", 2) || !strncmp(row[1], "1", 1));
10051019
}
10061020
mysql_free_result(res);
10071021
}
10081022
}
1023+
/* turn logging off if we can */
1024+
if (mysql_query(mysql,"set sql_log_off=1"))
1025+
{
1026+
if (opt_verbose)
1027+
fprintf(stderr, "Note: Can't turn off logging; '%s'", mysql_error(mysql));
1028+
log_off= false;
1029+
}
1030+
1031+
retry:
1032+
/*
1033+
In case the password_expired flag is set ('Y'), then there is no way
1034+
to determine the password format. So, we first try to set the
1035+
password using native format. If it fails with ER_PASSWORD_LENGTH,
1036+
we will give one more try with old format.
1037+
*/
10091038
if (old)
10101039
make_scrambled_password_323(crypted_pw, typed_password);
10111040
else
10121041
make_scrambled_password(crypted_pw, typed_password);
10131042
}
10141043
else
10151044
crypted_pw[0]=0; /* No password */
1016-
sprintf(buff,"set password='%s',sql_log_off=0",crypted_pw);
10171045

1018-
if (mysql_query(mysql,"set sql_log_off=1"))
1019-
{
1020-
my_printf_error(0, "Can't turn off logging; error: '%s'",
1021-
error_flags, mysql_error(mysql));
1022-
return -1;
1023-
}
1046+
sprintf(buff, "set password='%s'", crypted_pw);
1047+
10241048
if (mysql_query(mysql,buff))
10251049
{
1050+
if ((mysql_errno(mysql) == ER_PASSWD_LENGTH) &&
1051+
!(option == ADMIN_OLD_PASSWORD) && !retry_count)
1052+
{
1053+
/* Try to set the password using old format. */
1054+
memset(crypted_pw, 0, 64);
1055+
old= 0;
1056+
retry_count ++;
1057+
goto retry;
1058+
}
1059+
10261060
if (mysql_errno(mysql)!=1290)
10271061
{
10281062
my_printf_error(0,"unable to change password; error: '%s'",
10291063
error_flags, mysql_error(mysql));
1030-
return -1;
1064+
err= true;
1065+
goto error;
10311066
}
10321067
else
10331068
{
@@ -1041,15 +1076,25 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
10411076
" --skip-grant-tables).\n"
10421077
"Use: \"mysqladmin flush-privileges password '*'\""
10431078
" instead", error_flags);
1044-
return -1;
1079+
err= true;
1080+
goto error;
10451081
}
10461082
}
1083+
if (log_off && mysql_query(mysql, "set sql_log_off=0"))
1084+
{
1085+
if (opt_verbose)
1086+
fprintf(stderr, "Note: Can't turn on logging; '%s'", mysql_error(mysql));
1087+
}
1088+
error:
10471089
/* free up memory from prompted password */
10481090
if (typed_password != argv[1])
10491091
{
10501092
my_free(typed_password);
10511093
my_free(verified);
10521094
}
1095+
if (err)
1096+
return -1;
1097+
10531098
argc--; argv++;
10541099
break;
10551100
}

0 commit comments

Comments
 (0)