mirror of
https://github.com/webmin/webmin.git
synced 2026-10-28 22:21:12 +00:00
This patch completes the ACL added in [17ba87cbc](https://github.com/webmin/webmin/commit/17ba87cbc).
That change protected only the edit and save pages.
Users without environment-variable access could still change variables through delete, bulk actions, and moves.
This applies the permission everywhere and hides blocked controls.
It also applies create and delete permissions to variables and prevents job and variable endpoints from being mixed.
357 lines
10 KiB
Perl
Executable File
357 lines
10 KiB
Perl
Executable File
#!/usr/local/bin/perl
|
|
# index.cgi
|
|
# Display a list of all cron jobs, with the username and command for each one
|
|
|
|
require './cron-lib.pl';
|
|
&ReadParse();
|
|
&ui_print_header(undef, $text{'index_title'}, "", undef, 1, 1);
|
|
$max_jobs = $userconfig{'max_jobs'} || $config{'max_jobs'};
|
|
|
|
# Make sure cron is installed (very likely!)
|
|
$err = &check_cron_config();
|
|
if ($err) {
|
|
print $err,"<p>\n";
|
|
&ui_print_footer("/", $text{'index'});
|
|
exit;
|
|
}
|
|
|
|
# Work out which users can be viewed
|
|
map { $ucan{$_}++ } split(/\s+/, $access{'users'});
|
|
@jobs = &list_cron_jobs();
|
|
@ulist = &unique(map { $_->{'user'} } @jobs);
|
|
if ($access{'mode'} == 1) {
|
|
@ulist = grep { $ucan{$_} } @ulist;
|
|
}
|
|
elsif ($access{'mode'} == 2) {
|
|
@ulist = grep { !$ucan{$_} } @ulist;
|
|
}
|
|
elsif ($access{'mode'} == 3) {
|
|
@ulist = ( $remote_user );
|
|
}
|
|
elsif ($access{'mode'} == 4) {
|
|
@ulist = grep { local @u = getpwnam($_);
|
|
(!$access{'uidmin'} || $u[2] >= $access{'uidmin'}) &&
|
|
(!$access{'uidmax'} || $u[2] <= $access{'uidmax'}) }
|
|
@ulist;
|
|
}
|
|
elsif ($access{'mode'} == 5) {
|
|
@ulist = grep { local @u = getpwnam($_);
|
|
$u[3] == $access{'users'} } @ulist;
|
|
}
|
|
|
|
if ($config{'show_run'}) {
|
|
&foreign_require("proc", "proc-lib.pl");
|
|
@procs = &proc::list_processes();
|
|
}
|
|
|
|
# Work out creation links
|
|
@crlinks = ( );
|
|
if ($access{'create'}) {
|
|
push(@crlinks, &ui_link("edit_cron.cgi?new=1&search=".
|
|
&urlize($in{'search'}),
|
|
$text{'index_create'}) );
|
|
push(@crlinks, &ui_link("edit_env.cgi?new=1&search=".
|
|
&urlize($in{'search'}),
|
|
$text{'index_ecreate'}) )
|
|
if ($env_support && $access{'env'});
|
|
}
|
|
if ($config{cron_allow_file} && $config{cron_deny_file} && $access{'allow'}) {
|
|
push(@crlinks, &ui_link("edit_allow.cgi", $text{'index_allow'}) );
|
|
}
|
|
my @files = &list_cron_files();
|
|
if ($access{'mode'} == 0 && @files) {
|
|
push(@crlinks, &ui_link("edit_manual.cgi", $text{'index_manual'}));
|
|
}
|
|
|
|
# Build a list of cron job rows to show
|
|
$single_user = !&supports_users() || (@ulist == 1 && $access{'mode'});
|
|
@links = ( &select_all_link("d", 1),
|
|
&select_invert_link("d", 1),
|
|
@crlinks );
|
|
@rows = ( );
|
|
foreach $u (@ulist) {
|
|
if (!$config{'single_file'}) {
|
|
# Get the Unix user's real name
|
|
if ((@uinfo = getpwnam($u)) && $uinfo[5] =~ /\S/) {
|
|
$uname = "$u ($uinfo[5])";
|
|
}
|
|
else { $uname = $u; }
|
|
}
|
|
|
|
@jlist = grep { $_->{'user'} eq $u } @jobs;
|
|
@plist = ();
|
|
for($i=0; $i<@jlist; $i++) {
|
|
local $rpd = &is_run_parts($jlist[$i]->{'command'});
|
|
local @exp = $rpd ? &expand_run_parts($rpd) : ();
|
|
if (!$rpd || @exp) {
|
|
push(@plist, [ $jlist[$i], \@exp ]);
|
|
}
|
|
}
|
|
for($i=0; $i<@plist; $i++) {
|
|
local $job = $plist[$i]->[0];
|
|
&convert_range($job);
|
|
&convert_comment($job);
|
|
local @exp = @{$plist[$i]->[1]};
|
|
local $idx = $job->{'index'};
|
|
local @cols;
|
|
push(@cols, $idx);
|
|
$useridx = 0;
|
|
$cmdidx = 0;
|
|
if (!$single_user) {
|
|
$useridx = scalar(@cols);
|
|
push(@cols, &html_escape($uname));
|
|
}
|
|
push(@cols, $job->{'active'} ? $text{'yes'} :
|
|
"<font color=#ff0000>$text{'no'}</font>");
|
|
$donelink = 0;
|
|
if ($job->{'name'}) {
|
|
# An environment variable - show the name only
|
|
$cmdidx = scalar(@cols);
|
|
local $envdesc = "<i>$text{'index_env'}</i> ".
|
|
"<tt>@{[&html_escape($job->{'name'})]} = @{[&html_escape($job->{'value'})]}</tt>";
|
|
push(@cols, $access{'env'} ?
|
|
&ui_link("edit_env.cgi?idx=".$idx, $envdesc) :
|
|
$envdesc);
|
|
$donelink = 1;
|
|
}
|
|
elsif (@exp && $access{'command'}) {
|
|
# A multi-part command
|
|
$cmdidx = scalar(@cols);
|
|
@exp = map { &html_escape($_) } @exp;
|
|
push(@cols, &ui_link("edit_cron.cgi?idx=".$idx.
|
|
"&search=".&urlize($in{'search'}),
|
|
join("<br>",@exp)) );
|
|
$donelink = 1;
|
|
}
|
|
elsif ($access{'command'}) {
|
|
# A simple command
|
|
$cmdidx = scalar(@cols);
|
|
local $max = $config{'max_len'} || 10000;
|
|
local ($cmd, $input) =
|
|
&extract_input($job->{'command'});
|
|
$cmd =~ s/\\%/%/g;
|
|
$input =~ s/\\%/%/g;
|
|
$cmd = length($cmd) > $max ?
|
|
&html_escape(substr($cmd, 0, $max))." ..." :
|
|
$cmd !~ /\S/ ? "BLANK" : &html_escape($cmd);
|
|
push(@cols, &ui_link("edit_cron.cgi?idx=".$idx.
|
|
"&search=".&urlize($in{'search'}),
|
|
$cmd) );
|
|
$donelink = 1;
|
|
}
|
|
|
|
# Show cron time
|
|
if (!$access{'command'} || $config{'show_time'} || $userconfig{'show_time'}) {
|
|
$when = &when_text($job, 1);
|
|
if ($job->{'name'}) {
|
|
push(@cols, "");
|
|
}
|
|
elsif ($donelink) {
|
|
push(@cols, $when);
|
|
}
|
|
else {
|
|
push(@cols, &ui_link(
|
|
"edit_cron.cgi?idx=".$idx.
|
|
"&search=".&urlize($in{'search'}),
|
|
$when) );
|
|
}
|
|
}
|
|
|
|
# Show comment
|
|
if ($config{'show_comment'} || $userconfig{'show_comment'}) {
|
|
push(@cols, &html_escape($job->{'comment'}));
|
|
}
|
|
|
|
# Show next run time
|
|
if ($config{'show_next'} || $userconfig{'show_next'}) {
|
|
my $n = &next_run($job);
|
|
push(@cols, $n ? &make_date($n)
|
|
: "<i>$text{'index_nunknown'}</i>");
|
|
}
|
|
|
|
# Show running indicator
|
|
if ($config{'show_run'}) {
|
|
if ($job->{'name'}) {
|
|
# An environment variable
|
|
push(@cols, "");
|
|
}
|
|
else {
|
|
# Try to find the process
|
|
local $proc = &find_cron_process($job, \@procs);
|
|
$txt = $proc ?
|
|
"<font color=#00aa00>$text{'yes'}</font>" :
|
|
$text{'no'};
|
|
if ($config{'show_run'} == 2 &&
|
|
($access{'kill'} || !$proc)) {
|
|
$lnk = $proc ? "kill_cron.cgi?idx=$idx" : "exec_cron.cgi?idx=$idx&bg=1";
|
|
push(@cols, &ui_link($lnk, $txt) );
|
|
}
|
|
else {
|
|
push(@cols, $txt);
|
|
}
|
|
}
|
|
}
|
|
|
|
# Show mover buttons
|
|
if ($access{'move'}) {
|
|
# Hide moves that would cross a protected variable
|
|
local $upswap = &get_cron_move_target(\@jobs, $idx, "up");
|
|
local $downswap = &get_cron_move_target(\@jobs, $idx, "down");
|
|
local $topswap = &get_cron_move_target(\@jobs, $idx, "top");
|
|
local $bottomswap = &get_cron_move_target(\@jobs, $idx, "bottom");
|
|
local $movable = $job->{'name'} ||
|
|
$job->{'type'} == 0 ||
|
|
$job->{'type'} == 3;
|
|
local $canup = $upswap && $movable &&
|
|
$upswap->{'index'} != $idx &&
|
|
$upswap->{'file'} eq $job->{'file'} &&
|
|
($upswap->{'name'} || $upswap->{'type'} == 0 ||
|
|
$upswap->{'type'} == 3) &&
|
|
($access{'env'} ||
|
|
!&cron_move_affects_env(\@jobs, $job, $upswap));
|
|
local $candown = $downswap && $movable &&
|
|
$downswap->{'index'} != $idx &&
|
|
$downswap->{'file'} eq $job->{'file'} &&
|
|
($downswap->{'name'} || $downswap->{'type'} == 0 ||
|
|
$downswap->{'type'} == 3) &&
|
|
($access{'env'} ||
|
|
!&cron_move_affects_env(\@jobs, $job, $downswap));
|
|
local $cantop = $topswap && $movable &&
|
|
$topswap->{'index'} != $idx &&
|
|
$topswap->{'file'} eq $job->{'file'} &&
|
|
($topswap->{'name'} || $topswap->{'type'} == 0 ||
|
|
$topswap->{'type'} == 3) &&
|
|
($access{'env'} ||
|
|
!&cron_move_affects_env(\@jobs, $job, $topswap));
|
|
local $canbottom = $bottomswap && $movable &&
|
|
$bottomswap->{'index'} != $idx &&
|
|
$bottomswap->{'file'} eq $job->{'file'} &&
|
|
($bottomswap->{'name'} ||
|
|
$bottomswap->{'type'} == 0 ||
|
|
$bottomswap->{'type'} == 3) &&
|
|
($access{'env'} ||
|
|
!&cron_move_affects_env(\@jobs, $job, $bottomswap));
|
|
local $mover = "move.cgi?search=".
|
|
&urlize($in{'search'})."&idx=$idx";
|
|
push(@cols, &ui_up_down_arrows(
|
|
"$mover&up=1",
|
|
"$mover&down=1",
|
|
$canup, $candown,
|
|
)." ".
|
|
&ui_up_down_arrows(
|
|
"$mover&top=1",
|
|
"$mover&bottom=1",
|
|
$cantop, $canbottom,
|
|
"images/top.gif",
|
|
"images/bottom.gif",
|
|
));
|
|
}
|
|
|
|
# Add search colume
|
|
push(@cols, $job->{'command'}.' '.$job->{'name'}.' '.
|
|
$job->{'comment'});
|
|
push(@rows, \@cols);
|
|
$noenv{$idx}++ if ($job->{'name'} && !$access{'env'});
|
|
}
|
|
}
|
|
|
|
# Limit to search
|
|
if ($in{'search'}) {
|
|
@rows = grep { $_->[@$_-1] =~ /\Q$in{'search'}\E/i ||
|
|
$_->[1] =~ /\Q$in{'search'}\E/i } @rows;
|
|
}
|
|
|
|
# Show search form
|
|
print &ui_form_start("index.cgi");
|
|
print "$text{'index_search'} \n";
|
|
print &ui_textbox("search", $in{'search'}, 20);
|
|
print &ui_submit($text{'ui_searchok'});
|
|
print &ui_form_end();
|
|
|
|
# Check if we are over the display limit
|
|
if ($max_jobs && @rows > $max_jobs && !$in{'search'}) {
|
|
print "$text{'index_toomany2'}<p>\n";
|
|
print &ui_links_row(\@crlinks);
|
|
}
|
|
elsif (@rows) {
|
|
# Show jobs
|
|
if ($in{'search'}) {
|
|
print &text('index_searchres',
|
|
"<i>".&html_escape($in{'search'})."</i>"),"<p>\n";
|
|
push(@links, &ui_link("index.cgi", $text{'index_reset'}) );
|
|
}
|
|
print &ui_form_start("delete_jobs.cgi", "post");
|
|
print &ui_links_row(\@links);
|
|
@tds = ( "width=5" );
|
|
print &ui_columns_start([
|
|
"",
|
|
$single_user ? ( ) : ( $text{'index_user'} ),
|
|
$text{'index_active'},
|
|
$access{'command'} ? ( $text{'index_command'} ) : ( ),
|
|
!$access{'command'} || $config{'show_time'} ||
|
|
$userconfig{'show_time'} ? ( $text{'index_when'} ) : ( ),
|
|
$config{'show_comment'} || $userconfig{'show_comment'} ?
|
|
( $text{'index_comment'} ) : ( ),
|
|
$config{'show_next'} ? ( $text{'index_next'} ) : ( ),
|
|
$config{'show_run'} ? ( $text{'index_run'} ) : ( ),
|
|
$access{'move'} ? ( $text{'index_move'} ) : ( ),
|
|
], 100, 0, \@tds);
|
|
foreach my $r (@rows) {
|
|
# Variables cannot be selected without permission to edit them
|
|
print &ui_checked_columns_row([ @$r[1..(@$r-2)] ],
|
|
\@tds, "d", $r->[0], 0,
|
|
$noenv{$r->[0]});
|
|
}
|
|
print &ui_columns_end();
|
|
print &ui_links_row(\@links);
|
|
print &ui_form_end([ [ "delete", $text{'index_delete'} ],
|
|
[ "disable", $text{'index_disable'} ],
|
|
[ "enable", $text{'index_enable'} ] ]);
|
|
}
|
|
else {
|
|
# Show message
|
|
if ($in{'search'}) {
|
|
push(@crlinks, &ui_link("index.cgi", $text{'index_reset'}) );
|
|
}
|
|
print $in{'search'} ? &text('index_esearch',
|
|
"<i>".&html_escape($in{'search'})."</i>")."<p>" :
|
|
$module_info{'usermin'} ? "$text{'index_none3'} <p>\n" :
|
|
$access{'mode'} ? "$text{'index_none2'} <p>\n"
|
|
: "$text{'index_none'} <p>\n";
|
|
print &ui_links_row(\@crlinks);
|
|
}
|
|
|
|
# If there is an init script that runs crond, show status
|
|
if (&foreign_available("init")) {
|
|
&foreign_require("init");
|
|
my $init = $config{'init_name'};
|
|
my $atboot;
|
|
if ($access{'stop'} && $init && ($atboot = &init::action_status($init))) {
|
|
print &ui_hr();
|
|
print &ui_buttons_start();
|
|
|
|
# Running now?
|
|
my $r = &init::status_action($init);
|
|
if ($r == 1) {
|
|
print &ui_buttons_row("stop.cgi", $text{'index_stop'},
|
|
$text{'index_stopdesc'});
|
|
}
|
|
elsif ($r == 0) {
|
|
print &ui_buttons_row("start.cgi", $text{'index_start'},
|
|
$text{'index_startdesc'});
|
|
}
|
|
|
|
# Start at boot?
|
|
print &ui_buttons_row("bootup.cgi", $text{'index_boot'},
|
|
$text{'index_bootdesc'}, undef,
|
|
&ui_radio("boot", $atboot == 2 ? 1 : 0,
|
|
[ [ 1, $text{'yes'} ],
|
|
[ 0, $text{'no'} ] ]));
|
|
|
|
print &ui_buttons_end();
|
|
}
|
|
}
|
|
|
|
&ui_print_footer("/", $text{'index'});
|
|
|