$date = `/bin/date`;
You can open up a pipe to a program:
open (SORT, " | /usr/bin/sort | /usr/bin/uniq");You can invoke an external program and wait for it to return with system():
system "/usr/bin/sort < foo.in";or you can invoke an external program and never return with exec():
exec "/usr/bin/sort < foo.in";All of these constructions can be risky if they involve user input that may contain shell metacharacters. For system() and exec(), there's a somewhat obscure syntactical feature that allows you to call external programs directly rather than going through a shell. If you pass the arguments to the external program, not in one long string, but as separate members in a list, then Perl will not go through the shell and shell metacharacters will have no unwanted side effects. For example:
system "/usr/bin/sort","foo.in";You can take advantage of this feature to open up a pipe without going through a shell. By calling open on the magic character sequence
|-
, you fork a copy of Perl and open a pipe to the copy. The child
copy then immediately exec's another program using the argument list
variant of exec().
open (SORT,"|-") || exec "/usr/bin/sort",$uservariable; while $line (@lines) { print SORT $line,"\n"; } close SORT;To read from a pipe without opening up a shell, you can do something similar with the sequence
-|
:
open(GREP,"-|") || exec "/usr/bin/grep",$userpattern,$filename; while (<GREP>) { print "match: $_"; } close GREP;These are the form of open() you should use whenever you would otherwise perform a piped open to a command.
An even more obscure feature allows you to call an external program and lie to it about its name. This is useful for calling programs that behave differently depending on the name by which they were invoked.
The syntax is
system $real_name "fake_name","argument1","argument2"For example:
$shell = "/bin/sh"This invokes the shell using the name "-sh", forcing it to behave interactively. Note that the real name of the program must be stored in a variable, and that there's no comma between the variable holding the real name and the start of the argument list.
system $shell "-sh","-norc"
There's also a more compact syntax for this construction:
system { "/bin/sh" } "-sh","-norc"
You turn on taint checks in version 4 of Perl by using a special version of the interpreter named "taintperl":
#!/usr/local/bin/taintperlIn version 5 of perl, pass the -T flag to the interpreter:
#!/usr/local/bin/perl -TSee below for how to "untaint" a variable.
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';Adjust this as necessary for the list of directories you want searched. It's not a good idea to include the current directory (".") in the path.
$mail_address=~/([\w-.]+\@[\w-.]+)/; $untainted_address = $1;
$foo=~/$user_variable/
is unsafe?foreach (@files) {Now, however, Perl will ignore any changes you make to the user variable, making this sort of loop fail:
m/$user_pattern/o;
}
foreach $user_pattern (@user_patterns) { foreach (@files) { print if m/$user_pattern/o; } }To get around this problem Perl programmers often use this sort of trick:
foreach $user_pattern (@user_patterns) { eval "foreach (\@files) { print if m/$user_pattern/o; }"; }The problem here is that the eval() statement involves a user-supplied variable. Unless this variable is checked carefully, the eval() statement can be tricked into executing arbitrary Perl code. (For example of what can happen, consider what the eval statement does if the user passes in this pattern:
"/; system 'rm *'; /"
The taint checks described above will catch this potential problem. Your alternatives include using the unoptimized form of the pattern matching operation, or carefully untainting user-supplied patterns. In Perl5, a useful trick is to use the escape sequence \Q \E to quote metacharacters so that they won't be interpreted:
print if m/\Q$user_pattern\E/o;
You can make a script run with the privileges of its owner by setting its "s" bit:
chmod u+s foo.plYou can make it run with the privileges of its owner's group by setting the s bit in the group field:
chmod g+s foo.plHowever, many Unix systems contain a hole that allows suid scripts to be subverted. This hole affects only scripts, not compiled programs. On such systems, an attempt to execute a Perl script with the suid bits set will result in a nasty error message from Perl itself.
You have two options on such systems:
ftp://rtfm.mit.edu/pub/usenet-by-group/comp.lang.perl/
#include <unistd.h> void main () { execl("/usr/local/bin/perl","foo.pl","/local/web/cgi-bin/foo.pl",NULL); }After compiling this program, make it suid. It will run under its owner's permission, launching a Perl interpreter and executing the statements in the file "foo.pl".
Another option is to run the server itself as a user that has sufficient privileges to do whatever the scripts need to do. If you're using the CERN server, you can even run as a different user for each script. See the CERN documentation for details.