Add ability to force reset lost admin password for MySQL

This commit is contained in:
Ilia Rostovtsev
2020-11-29 18:07:39 +03:00
parent a79a09a60d
commit d10b1578ae
4 changed files with 117 additions and 2 deletions

View File

@@ -96,7 +96,7 @@ if ($r == 0) {
elsif ($r == -1) {
# Running, but webmin doesn't know the root (or user's) password!
&main_header();
print "<b>$text{'index_nopass'}</b> <p>\n";
print "$text{'index_nopass'} <p>\n";
print &ui_form_start("login.cgi", "post");
print &ui_table_start($text{'index_ltitle'}, undef, 2);
@@ -105,7 +105,8 @@ elsif ($r == -1) {
&ui_textbox("login", $access{'user'} || $config{'login'}, 40));
print &ui_table_row($text{'index_pass'},
&ui_password("pass", undef, 40));
&ui_password("pass", undef, 40) . "<br>" .
&ui_checkbox("force", 1, $text{'mysqlpass_echange_forcepass'}));
print &ui_table_end();
print &ui_form_end([ [ undef, $text{'save'} ] ]);

View File

@@ -858,4 +858,13 @@ root_epass1=No new password entered
root_epass2=Passwords do not match
root_none=No password!
root_auto=Automatic (typically <tt>root</tt>)
mysqlpass_err=MySQL safe mode
mysqlpass_esafecmd=The command $1 needed to start MySQL with authentication disabled was not found
mysqlpass_eshutdown=Shutdown failed : $1
mysqlpass_esafe=Startup in safe mode failed : $1
mysqlpass_estartup=Startup failed : $1
mysqlpass_echange=Password change failed : $1
mysqlpass_echange_forcepass=Force override the given password, if lost or forgotten
__norefs=1

View File

@@ -9,6 +9,7 @@ $access{'user'} || !$access{'noconfig'} || &error($text{'login_ecannot'});
$in{'login'} || &error($text{'login_elogin'});
$mysql_login = $config{'login'} = $in{'login'};
$mysql_pass = $config{'pass'} = $in{'pass'};
$in{'force'} && force_set_mysql_admin_pass($mysql_login, $mysql_pass);
$authstr = &make_authstr();
if (&is_mysql_running() == -1) {
&error($text{'login_epass'});

View File

@@ -1764,5 +1764,109 @@ if (defined($c->{'pass'})) {
&start_mysql();
}
# force_set_mysql_admin_pass(user, pass)
# Forcibly change MySQL admin password, if lost or forgotten
sub force_set_mysql_admin_pass
{
my ($user, $pass) = @_;
&error_setup($text{'mysqlpass_err'});
&foreign_require("proc");
# Find the mysqld_safe command
my $safe = &has_command("mysqld_safe");
if (!$safe) {
&error(&text('mysqlpass_esafecmd', "<tt>mysqld_safe</tt>"));
}
# Shut down server if running
if (&is_mysql_running()) {
my $err = &stop_mysql();
if ($err) {
&error(&text('mysqlpass_esafecmdeshutdown', $err));
}
}
# Start up with skip-grants flag
my $cmd = $safe." --skip-grant-tables";
# Running with `mysqld_safe` - when called, command doesn't create "mysqld" directory under
# "/var/run" eventually resulting in DBI connect failed error on all MySQL versions
my $ver = &get_mysql_version();
if ($ver !~ /mariadb/i) {
my $mysockdir = '/var/run/mysqld';
my $myusergrp = 'mysql';
my $myconf = &get_mysql_config();
if ($myconf) {
my ($mysqld) = grep { $_->{'name'} eq 'mysqld' } @$myconf;
if ($mysqld) {
my $members = $mysqld->{'members'};
# Look for user
my $myusergrp_ = &find_value("user", $members);
if ($myusergrp_) {
$myusergrp = $myusergrp_;
}
# Look for socket
my $mysockdir_ = &find_value("socket", $members);
if ($mysockdir_) {
$mysockdir = $mysockdir_;
$mysockdir =~ s/^(.+)\/([^\/]+)$/$1/;
}
}
}
$cmd = "mkdir -p $mysockdir && chown $myusergrp:$myusergrp $mysockdir && $cmd";
}
my ($pty, $pid) = &proc::pty_process_exec($cmd, 0, 0);
sleep(5);
if (!$pid || !kill(0, $pid)) {
my $err = <$pty>;
&error(&text('mysqlpass_esafe', $err));
}
# Update password by running command directly
my $cmd = $config{'mysql'} || 'mysql';
my $sql = &get_change_pass_sql($pass, $user, 'localhost');
my $out = &backquote_command("$cmd -D $master_db -e ".
quotemeta("flush privileges; $sql")." 2>&1 </dev/null");
if ($?) {
$out =~ s/\n/ /gm;
&error(&text('mysqlpass_echange', "$out"));
}
else {
# Update root password now for other
# hosts, using regular database connection
my $d = &execute_sql_safe($master_db,
"select host from user where user = ?", $user);
@hosts = map { $_->[0] ne 'localhost' } @{$d->{'data'}};
foreach my $host (@hosts) {
$sql = get_change_pass_sql($pass, $user, $host);
eval {
local $main::error_must_die = 1;
&execute_sql_logged($master_db, 'flush privileges');
&execute_sql_logged($master_db, $sql);
&execute_sql_logged($master_db, 'flush privileges');
sleep 1;
};
}
}
# Shut down again, with the mysqladmin command
my $mysql_shutdown = $config{'mysqladmin'} || 'mysqladmin';
my $out = &backquote_logged("$mysql_shutdown shutdown 2>&1 </dev/null");
if ($?) {
$out =~ s/\n/ /gm;
&error(&text('mysqlpass_eshutdown', $out));
}
# Finally, re-start in normal mode
my $err = &start_mysql();
if ($err) {
&error(&text('mysqlpass_estartup', $err));
}
&error_setup($text{'login_err'});
}
1;