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