mirror of
https://github.com/webmin/webmin.git
synced 2026-10-26 05:00:51 +00:00
Fix non-root MySQL backup hooks
This patch addresses non-root MySQL backup hooks remaining unreachable after original patch https://github.com/webmin/webmin/commit/6873c65. Now it makes before and after commands available when backups run as a configured non-root Unix user. Root hook execution remains limited to cron-eligible Webmin users, and Usermin remains excluded from backup hooks.
This commit is contained in:
@@ -53,14 +53,17 @@ if (!$in{'save'} || $in{'sched'}) {
|
||||
push(@compat, split(/\0/, $in{'options'}));
|
||||
$cron = !$module_info{'usermin'} && $access{'buser'} eq 'root' &&
|
||||
!$access{'user'} && &foreign_installed("cron");
|
||||
$commands = &can_run_backup_commands($cron);
|
||||
$cmode = 0;
|
||||
if ($cron) {
|
||||
if ($commands) {
|
||||
$config{'backup_before_'.$in{'db'}} = $in{'before'};
|
||||
$config{'backup_after_'.$in{'db'}} = $in{'after'};
|
||||
if ($in{'all'}) {
|
||||
$config{'backup_cmode_'.$in{'db'}} = $in{'cmode'};
|
||||
$cmode = $in{'cmode'};
|
||||
}
|
||||
}
|
||||
if ($cron) {
|
||||
$config{'backup_email_'.$in{'db'}} = $in{'email'};
|
||||
$config{'backup_notify_'.$in{'db'}} = $in{'notify'};
|
||||
|
||||
@@ -193,7 +196,7 @@ if (!$in{'save'}) {
|
||||
&html_escape($file)),"<p>\n";
|
||||
next;
|
||||
}
|
||||
if ($cron && $cmode == 0) {
|
||||
if ($commands && $cmode == 0) {
|
||||
# Run and check before-backup command (for one DB)
|
||||
$bok = &execute_before($db, STDOUT, 1, $file,
|
||||
$in{'all'} ? undef : $db,
|
||||
@@ -220,7 +223,7 @@ if (!$in{'save'}) {
|
||||
}
|
||||
&execute_after($db, STDOUT, 1, $file, $in{'all'} ? undef : $db,
|
||||
$access{'buser'})
|
||||
if ($cron && $cmode == 0);
|
||||
if ($commands && $cmode == 0);
|
||||
|
||||
if ($in{'dest'}) {
|
||||
# Sent to browser
|
||||
|
||||
@@ -28,6 +28,7 @@ if (!-x $cmd) {
|
||||
|
||||
$cron = !$module_info{'usermin'} && $access{'buser'} eq 'root' &&
|
||||
!$access{'user'} && &foreign_installed("cron");
|
||||
$commands = &can_run_backup_commands($cron);
|
||||
if ($in{'all'}) {
|
||||
print "$text{'backup_desc3'}\n";
|
||||
}
|
||||
@@ -156,7 +157,7 @@ $b = $c{'backup_parameters_'.$in{'db'}};
|
||||
print &ui_table_row($text{'backup_parameters'},
|
||||
&ui_textbox("parameters", $b, 60));
|
||||
|
||||
if ($cron) {
|
||||
if ($commands) {
|
||||
# Show before/after commands
|
||||
$b = $c{'backup_before_'.$in{'db'}};
|
||||
print &ui_table_row($text{'backup_before'},
|
||||
@@ -175,7 +176,10 @@ if ($cron) {
|
||||
[ 1, $text{'backup_cmode1'} ] ]));
|
||||
}
|
||||
|
||||
print &ui_hidden_table_end("opts");
|
||||
}
|
||||
print &ui_hidden_table_end("opts");
|
||||
|
||||
if ($cron) {
|
||||
print &ui_hidden_table_start($text{'backup_header3'}, "width=100%", 2,
|
||||
"sched", 1, [ "width=30%" ]);
|
||||
|
||||
@@ -211,9 +215,6 @@ if ($cron) {
|
||||
|
||||
print &ui_hidden_table_end("sched");
|
||||
}
|
||||
else {
|
||||
print &ui_hidden_table_end("opts");
|
||||
}
|
||||
|
||||
if ($cron) {
|
||||
print &ui_form_end([ [ "backup", $text{'backup_ok'} ],
|
||||
|
||||
@@ -1023,6 +1023,17 @@ if ($config{'webmin_subs'}) {
|
||||
return $rv;
|
||||
}
|
||||
|
||||
# can_run_backup_commands(cron)
|
||||
# Returns true if this request can configure and run backup commands. Cron
|
||||
# access already permits root commands, while other Webmin users are limited
|
||||
# to commands run as their configured non-root backup user.
|
||||
sub can_run_backup_commands
|
||||
{
|
||||
my ($cron) = @_;
|
||||
return !$module_info{'usermin'} &&
|
||||
($cron || $access{'buser'} && $access{'buser'} ne 'root');
|
||||
}
|
||||
|
||||
# execute_before(db, handle, escape, path, db-for-config, [&as-user])
|
||||
# Executes the before-backup command for some DB, and sends output to the
|
||||
# given file handle. Returns 1 if the command succeeds, or 0 on failure
|
||||
|
||||
@@ -136,6 +136,51 @@ subtest 'sandboxed SQL files use direct input' => sub {
|
||||
'the sandboxed command does not use source');
|
||||
};
|
||||
|
||||
subtest 'backup commands honor the backup user privilege boundary' => sub {
|
||||
local %main::module_info;
|
||||
local %main::access = ( 'buser' => 'root' );
|
||||
ok(!main::can_run_backup_commands(0),
|
||||
'root commands require existing cron eligibility');
|
||||
ok(main::can_run_backup_commands(1),
|
||||
'cron-eligible users can run root commands');
|
||||
|
||||
$main::access{'buser'} = 'backupuser';
|
||||
ok(main::can_run_backup_commands(0),
|
||||
'Webmin backups can run commands as a non-root backup user');
|
||||
$main::module_info{'usermin'} = 1;
|
||||
ok(!main::can_run_backup_commands(1),
|
||||
'Usermin cannot gain backup command access');
|
||||
};
|
||||
|
||||
subtest 'backup commands run as the non-root backup user' => sub {
|
||||
no warnings 'redefine';
|
||||
local $main::config{'backup_before_testdb'} = 'before-command';
|
||||
local $main::config{'backup_after_testdb'} = 'after-command';
|
||||
my @commands;
|
||||
local *main::command_as_user = sub {
|
||||
my ($user, $background, $command) = @_;
|
||||
is($background, 0, 'backup command remains synchronous');
|
||||
return "as-$user $command";
|
||||
};
|
||||
local *main::execute_command = sub {
|
||||
push(@commands, $_[0]);
|
||||
return 0;
|
||||
};
|
||||
|
||||
ok(main::execute_before('testdb', undef, 0, '/tmp/test.sql',
|
||||
'testdb', 'backupuser'),
|
||||
'before command succeeds');
|
||||
ok(main::execute_after('testdb', undef, 0, '/tmp/test.sql',
|
||||
'testdb', 'backupuser'),
|
||||
'after command succeeds');
|
||||
is_deeply(\@commands,
|
||||
[ 'as-backupuser before-command',
|
||||
'as-backupuser after-command' ],
|
||||
'both commands are wrapped for the backup user');
|
||||
is($ENV{'BACKUP_FILE'}, '/tmp/test.sql',
|
||||
'backup commands receive the destination path');
|
||||
};
|
||||
|
||||
subtest 'binary log retention display round-trips exactly' => sub {
|
||||
# The page shows seconds as days, and saving converts the shown days
|
||||
# back with int(days * 86400 + 0.5), which must reproduce the exact
|
||||
|
||||
Reference in New Issue
Block a user