Hello,
I am trying to get a CGI script to run a system command.....for example
system `/usr/sbin/adduser larry' or die "User was not added" $?;
I have this line in a script and have set Apache to be run as root (don't
worry, all this is being done on a test box...I know the security risks) and
I get an error from adduser that it cannot lock the password file.
Very strange because.....on another box I have the same code working!
The code that is working is below.......
First index.cgi is called
----------INDEX.CGI----------
#!/usr/bin/perl
push (@INC, "/usr/local/interface/server");
require 'cgi-lib.pl';
require 'stub.pl';
exit;
----------END INDEX.CGI---------
Very straight forward so far.....all the action takes place in stub.pl.
---------STUB.PL-------------
# Input Variables:
#
# "zone" -- the zone we're working with.
# "query" -- the kind of query we're making.
# "recordnum" -- the line number of the record to manipulate
# "confirmed" -- confirmed a request we sent
# "host" -- The hostname or IP address to work with
# "record" -- The type of record to work with
# "data" -- Any extra arguments
# Included Functions:
#
# "findroot" -- Find the root named directory.
# From: common.pl
# "findzone" -- Find the zone file of a specified zone
# From: common.pl
# "getlocalip" -- Gets the local IP address.
# From: common.pl
# "getlocalhost" -- Gets the local host.
# From: common.pl
# "excludeblock" -- Excludes a block of text.
# From: blockmanip.pl
# Unique Functions
# "printzone" -- print out a zone
# Uses: &findzone
# Output: Prints out the requested zone.
# Returns: Nothing.
# "delrecord" -- print out a zone, except a specified line
# Uses: &findzone, $recordnum
# Output: Zone file, minus the specified line.
# Returns: Nothing.
# "finddomains" -- Find the domains hosted on the machine
# Uses: $zone
# Output: Domains hosted according to /etc/named.conf.
# Returns: Nothing.
# "delzone" -- Searches /etc/named.conf, and removes a zone from it
# Uses: $zone
# Output: Prints out the zone, minute the specified line.
# Returns: Nothing.
# "addzone" -- Attempts to add a zone.
# Uses: &findzone
# "addrecord" -- Attempts to add a record to a zone.
# "gettimargs" -- Attempts to find the time configuration
# Uses: &findzone
# Returns: Array of time arguments
# "incserial" -- Increments the serial number
# Uses: &gettimeargs
# Returns: Current serial number + 1, or error code
@NEWINC = (
"/usr/local/interface/server/include",
"/usr/local/interface/server/templates",
"/usr/local/interface/server/functions",
);
push(@INC, @NEWINC);
undef @NEWINC;
&ReadParse(*input);
if ((getpwuid($<))[0] ne 'nobody' || ( (getgrgid($())[0] ne 'shadow'
&& (getgrgid($())[0] ne 'nobody' ) )
{
die "I will not function except as child of Apache!\n";
}
unless ($ENV{'REMOTE_USER'} && $ENV{'SERVER_NAME'})
{
die "I will not function outside of a cgi context!\n";
}
require 'config.pl';
require 'getdtpwnam.pl';
sub comment { # insert hidden snide comments for debugging
if ($debug)
{
print "<!--\n\t@_ -->\n";
}
}
# Begin main code.
# Redirect STDERR to STDOUT.
open(STDERR,">&STDOUT");
select STDERR; $| = $1;
# Stard printing out.
print "Content-type: text/html\r\n\r\n",
'<BODY BGCOLOR="white">';
#print "Content-type: text/plain\r\n\r\n";
# Call the queried function.
$< = 0;
$> = 0;
unless ($ENV{'REMOTE_USER'} && $ENV{'SERVER_NAME'})
{
die "I will not function outside of a cgi context!\n";
}
unless (
(
getdtpwnam($ENV{'REMOTE_USER'}))[1] eq $ENV{'SERVER_NAME'}
)
{
&comment("User \($ENV{'REMOTE_USER'}\) and Server Name
\($ENV{'SERVER_NAME'}\) denied!.\n");
print "Error! Incorrect domain name attachment!\n";
die "\tCannot verify secure user; dying...\n";
}
else
{
&comment("User \($ENV{'REMOTE_USER'}\) and Server Name
\($ENV{'SERVER_NAME'}\) accepted.\n");
}
umask 022;
if ($input{'query'} =~ /(\S+)/)
{
$query = $1;
}
unless ($query)
{
die "No query specified, giving up...\n";
}
require "${query}.pl";
&$query;
1;
------------ END STUB.PL------------
Basically what happens is this script receives input from a form (ReadParse
section) and then makes sure that it is a child of Apache and I believe the
lines that do:
$< = 0;
$> = 0;
change the ownership of the process to the root user and group....(BTW on my
system root is 0 in both /etc/passwd and /etc/group). I THINK that is what
this does, but PLEASE correct me if I'm wrong.
That being said, the process (that is, everything the script is doing from
this point) *should* be operating as the root user, correct?
Then the line:
umask 022;
if I understand correctly, makes sure that everything created by the process
from this point on has the permissions 755. (correct me if I'm wrong.)
Then the line
&$query;
executes whatever query the form specified. For example, say the query is
addaccount....the line would look like this:
&addaccount;
Now, once it gets into addaccount.pl...
----------ADDACCOUNT.PL-----------
require 'slurp.pl';
require 'append.pl';
require 'untaint.pl';
require 'encrypt.pl';
require 'checkin.pl';
if ($input{'query'} eq "addaccount")
{
require 'listusers.pl';
require 'listuser-template.pl';
}
sub addaccount {
if ($input{'user'} =~ /\./)
{
&comment("Error: No \".\" allowed in username. It screws up chown.");
print "Error: No \".\" is allowed in usernames.\n";
die;
}
if (getpwnam($input{'user'}))
{
&comment("Error: User already exists... giving up in addaccount!\n");
print "Error: User already exists, giving up...\n";
die;
}
unless ($input{'passwd'})
{
&comment("Error: No password given... giving up in addaccount!\n");
print "Error: No password given, giving up...\n";
die;
}
unless ($input{'shell'})
{
&comment("No shell specified, defaulting to $defaultshell\n");
$input{'shell'} = "$defaultshell";
}
unless ($input{'home'})
{
&comment("No home specified, defaulting to
${defaulthome}${input{'user'}}\n");
$input{'home'} = "$defaulthome" . "$input{'user'}";
}
my($passwd) = &encrypt($input{'passwd'});
$ENV{'PATH'} = "";
$input{'user'} = &untaint($input{'user'});
$input{'home'} = &untaint($input{'home'});
$input{'shell'} = &untaint($input{'shell'});
$passwd = &untaint($passwd);
&comment("Adding Account for
$input{'user'}:\n\tHome:\t\t\t$input{'home'}\n\tShell:\t\t\t$input{'shell'}\n\tEncrypted
Password:\t$passwd\n");
&checkin("/etc/passwd", "added new user with \"$adduserpath $input{'user'}
-d $input{'home'} -m -s $input{'shell'} -p $passwd\"");
system "$adduserpath", "$input{'user'}", "-d", "$input{'home'}", "-m",
"-s", "$input{'shell'}", "-p", "$passwd";
&comment("Changing modes for the user's home directory to mode 711
\(+rwx,go-rw\)...\n");
chmod 0711, $input{'home'};
if ($input{'ftp'} eq "NO")
{
&comment("FTP access disallowed; disabling FTP access.");
&checkin($ftpusers, "Appended \"$input{'user'}\" to $ftpusers");
&appendscalar($ftpusers,"$input{'user'}\n");
}
if ($input{'query'} eq "addaccount")
{
&generate_addaccount_dyn;
&listusers;
}
return 1;
}
1;
---------END ADDACCOUNT.PL----------
Ok, don't worry about all the include files....the part that is giving me
trouble is in this file.
system "$adduserpath", "$input{'user'}", "-d", "$input{'home'}", "-m", "-s",
"$input{'shell'}", "-p", "$passwd";
Back to my orignial question, this line never executes.....probably because
the don't have the proper permissions.....meaning the process is not being
run as root.
The log shows an error message from adduser saying that it can't lock the
file.
*****Keep in mind that the above code works on another server that someone
else setup******* I have done my best to duplicate the environment.
Now, on to how apache is setup.......
First of all the box that is working is running it on Apache SSL and it is
owned as nobody (user) and shadow (group)........tried this on the other
box, but there is no shadow group setup and the shadow file is owned and
grouped to root......so there shouldn't be a problem in my opinion.
I dont' know what other information to include.
If you've made it this far, thanks for taking the time to see if you could
help.
Any and all help is appreciated.
Please let me know if anyone can help.
Thanks,
Kevin
[EMAIL PROTECTED]
_________________________________________________________________
Get your FREE download of MSN Explorer at http://explorer.msn.com/intl.asp
--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]