I'm currently writing a CGI script in Perl that is supposed to read in a crontab (works), allows for easy manipulation in a web browser (TODO) and should finally set the crontab when editing it is done (fails). To preemtively answer any questions on security: The script is reachable only within a VPN tunnel and so is invisible on the 'Net...
Anyway, here's the code in question:
if($p_action eq 'set')
{
my $l_i = 1;
my $l_param;
if(!open(CRON, "| /usr/bin/sudo /usr/bin/crontab"))
{
print CRON "CRON_TZ=$l_param\n" if(defined ($l_param = $cgi->param("cron_tz")));
print CRON "MAILTO=$l_param\n" if(defined ($l_param = $cgi->param("mailto")));
print CRON "SHELL=$l_param\n" if(($l_param = $cgi->param("shell")) ne 'unset');
print CRON "\n" if(defined $cgi->param("cron_tz") || defined $cgi->param("mailto") || $cgi->param('shell') ne 'unset');
while(defined $cgi->param("line$l_i-min"))
{
my $l_min = $cgi->param("line$l_i-min");
my $l_hour = $cgi->param("line$l_i-hour");
my $l_day = $cgi->param("line$l_i-day");
my $l_month = $cgi->param("line$l_i-month");
my $l_wday = $cgi->param("line$l_i-wday");
my $l_cmd = $cgi->param("line$l_i-cmd");
print CRON "- " if($cgi->param("line$l_i-nolog") eq 'Nolog');
print CRON $l_min.' ';
print CRON $l_hour.' ';
print CRON $l_day.' ';
print CRON $l_month.' ';
print CRON $l_wday.' ';
print CRON $l_cmd."\n";
$l_i++;
}
close(CRON);
}
}
I already have permitted both /usr/bin/crontab -l and /usr/bin/crontab in the sudoers file for execution by wwwrun.
Although crontab is actually executed when opening the pipe, nothing, however, is passed to crontab and so resulting in an empty crontab. It appears that I'm missing something crucial here, but I don't possibly see what it could be. Any clues on how to get this thing unstuck?
P.S.: I want to confine root privileges to as few lines of code as possible so running the script as root is not an option.