lostperls has asked for the wisdom of the Perl Monks concerning the following question:

Hi all

I have this command if (!system("adduser $username -g 100 -s /bin/false -d /home/$username -p $encrypted_pass -e $expiry_date -c $realname")) { But because $realname can contain spaces it needs to be passed to adduser as -c "my real name is bob", rather than -c my real name is bob.

I cant put " " round the $realname as this doesn't work. Any ideas how to rewrite this?

Cheers

Replies are listed 'Best First'.
Re: Running System Commans With ""
by fruiture (Curate) on Sep 11, 2002 at 19:37 UTC

    Again, TIMTOWTDI. I could tell you about using the qq// operator or simply 'single quotes' or \backslashes or the concatenation.operator, but the _best_ way is certainly the list-method of system():

    unless( system('adduser' => $username, -g => 100, -s => '/bin/false', -d => "/home/$username", -p => $encrypted_pass, -e => $expiry_date, -c => $realname, )){

    See `perldoc -f system`

    UPDATE: I've just read Don't try this at home: that's the reason why passing a list to system() is the best way :)

    --
    http://fruiture.de
      What does that do on an OS where a new process gets a single string? If it just concatenates the list together, you're back where you started.

        I don't even know any OS that does so. But still it's more secure, because still no shell is started and no shell-tricks can be used. But an OS without 'char *argv[]' probably also doesn't know a shell, .. ? :)

        --
        http://fruiture.de
Re: Running System Commans With ""
by jkahn (Friar) on Sep 11, 2002 at 19:42 UTC
    As ferrency suggested in the crisis he describes in "Don't try this at home", composing all the bits of a system command into one line is dangerous, because one of those variables might contain a malicious command.

    Instead, consider using the system LIST syntax, e.g.:

    # # add double-quote characters to either end of realname # # $realname = '"' . $realname . '"'; # commented out above line after fruiture pointed out that # system LIST format makes it unnecessary -- and even # wrong, since realname would then be stored with '"' # on either side! # run system command, but pass args directly to the # adduser program, rather than booting a shell if (!system("adduser", $username, '-g', '100', '-s', '/bin/false', '-d', "/home/$username", '-p', $encrypted_pass, '-e' $expiry_date, '-c' $realname ) ) { die "trouble adding user: returned non-zero\n"; }

    This will:

    1. Solve your problem with quotes, since you've added them $realname is passed as a single argument.
    2. Protect you from malicious examples like ferrency pointed out before.

    See perldoc -f system.

    update: fruiture pointed out that quotes were not needed in system LIST syntax.

      The list argument form of system is also FASTER than the scalar form, isnt' it? I believe I read somewhere that the scalar form invokes another shell and hands off the processing to it, whereas the list form is more... er, direct? Faster and more secure. Mmmmmmm...

      I can't explain how but I know I read it somewhere. Could someone elaborate for me about what the list form actually does?

      --
      perl: code of the samurai

        Yes, it's faster because there's no need for an intermediate sh process to get loaded, parse the arguments, redirect input and output where they should be sent to, and pass the arguments to the program invoked.

        If you do want shell-style redirection, though, you'll have to use a system EXPR syntax. It's not all bad; a number of Perl Cookbook recipes use it for good reason (mostly for shell redirection).