in reply to Re: Using doublequotes in a system call
in thread Using doublequotes in a system call

The open() is in the error message. The only code I displayed from my script was the system(), and I call an error routine if it fails, I just didn't display that.
system() and &error;
I tried passing the quotes and the name through a scalar, and that didn't work. What format are you suggesting on the array? The entire input or just the quotes and name? Can you provide a quick example. I'm not following.

I didn't have strict or warnings on. I'll add them and see what happens.

Thanks so far,
Rick Guyer
DualTech Services, Inc.

Replies are listed 'Best First'.
Re^3: Using doublequotes in a system call
by particle (Vicar) on May 19, 2002 at 02:08 UTC
    sure, i can give you an example. but the best examples are in perlsec. you're running AS ROOT, and not checking your variables for taintedness. if i can get you to your web page, i can do VERY EVIL THINGS to your system. of course, i'd never do that ;-)

    use -T as well as strict and warnings. don't use the PATH environment, unless you've cleaned it. when you execute a system call, use the full path to the executable, and pass an array, so the shell is bypassed. these and many other good practices can be learned by reading the perlsec documentation. i highly recommend reading Ovid's "Web Programming Using Perl" Course as well. it's helped me tremendously.

    here's some code...

    #!/usr/bin/perl -wT use strict; use CGI; # clean your environment BEGIN { $ENV{PATH} = '/usr/bin:/usr/local/bin'; } my $useradd = '/full/path/to/useradd'; my( $site_count, $username ); # and so on... # get input, which will be tainted... # my $username = $CGI->param('username'); # untaint input # for instance, username is 1 to 12 word characters if( $username =~ /^(\w{1,12})$/ ) { $username = $1 } # and so on... # now call system, with list of arguments to bypass shell system( $useradd, qq|-c "fullname"|, qq|-d /home/sites/site$site_count/users/$username|, qq|-g site$site_count|, qq|and so on...|, ) and error( "oh, i didn't expect that! $!" );

    ~Particle *accelerates*

      This is the right idea, but your system() call isn't quite correct. When you run something like:
      system("$useradd -c \"$fullname\" ...");
      then system() runs the command by way of the a shell. The shell splits the command string up into words--removing the quotes in the process--and ends up passing the '-c' and the $fullname to useradd as two separate arguments.

      However, when you call:

      system( $useradd, qq|-c "fullname"|, ...
      then the shell doesn't get involved, and useradd receives the exact argument list you passed to system(). In this case you've constructed a single string
      -c "value-of-$fullname"
      which useradd will percieve as a single argument, quotes and all. This probably isn't what useradd is expecting.

      If you're going to use the list form of system, you really have to pass each argument as a separate list element, eg:

      system ($useradd, '-c', $fullname, '-d', "/home/sites/site$site_count/users/$username", '-g', "site$site_count", '-G', "site-adm$site_count", '-p', $password, '-s', '/bin/false', '-u', $uid, $username);
      This way, the shell isn't involved, because you're using the list form of system(). But useradd receives each command-line argument as a separate element (with no extraneous quotes) just like it expects.

      If you have trouble understanding the difference, then try running each of the following:

      system('cat -n /etc/group'); system('cat', '-n /etc/group'); system('cat', '-n', '/etc/group');
      Use the q{} or qq{} quote form if you like; it shouldn't matter. The first and third lines should work; the second should give you an error of some sort.
        you are, of course, correct. my 'in-head-interpreter' still doesn't parse perfectly, so my on-the-fly example was flawed.

        your clear and detailed response will now be the place i point anyone who wants to understand using system.

        ~Particle *accelerates*