diff --git a/mysql/index.cgi b/mysql/index.cgi index 75f7cb5da..e0889150a 100755 --- a/mysql/index.cgi +++ b/mysql/index.cgi @@ -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 "$text{'index_nopass'}

\n"; + print "$text{'index_nopass'}

\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) . "
" . + &ui_checkbox("force", 1, $text{'mysqlpass_echange_forcepass'})); print &ui_table_end(); print &ui_form_end([ [ undef, $text{'save'} ] ]); diff --git a/mysql/lang/en b/mysql/lang/en index b452a233b..3d98d0044 100644 --- a/mysql/lang/en +++ b/mysql/lang/en @@ -858,4 +858,13 @@ root_epass1=No new password entered root_epass2=Passwords do not match root_none=No password! root_auto=Automatic (typically root) + +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 diff --git a/mysql/login.cgi b/mysql/login.cgi index 7532acc03..43ad6f47a 100755 --- a/mysql/login.cgi +++ b/mysql/login.cgi @@ -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'}); diff --git a/mysql/mysql-lib.pl b/mysql/mysql-lib.pl index 82a836780..0df563e0a 100755 --- a/mysql/mysql-lib.pl +++ b/mysql/mysql-lib.pl @@ -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', "mysqld_safe")); + } + +# 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 [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