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]

Reply via email to