Hi!
On Wed, Jul 25, 2001 at 11:53:30PM +0200, you wrote:
> Besides, I realised that I can't pass a command line to the popen'ed
> program. That's useless.
Sorry? From popen()'s manpage:
-- snip --
The command argument is a pointer to a null-terminated
string containing a shell command line. This command is
passed to /bin/sh using the -c flag; interpretation, if
any, is performed by the shell. The mode argument is a
pointer to a null-terminated string which must be either
`r' for reading or `w' for writing.
-- snap --
So, calling
popen("ls -lF", "r")
will return a FILE pointer to a pipe connected with the command "ls
-lF", thus reading from it will return a directory listing.
This also is one of the dangerous features of popen() (and system() as
well), as it will pass the command to sh -c. That means you must never
use it to call popen() with (unfiltered) user supplied data (at least
not in suid-binaries or other stuff where the user supplying the data is
not the same as the user running the program, e.g. in CGIs).
For example, a common mistake in CGIs using popen() to sendmail to send
an email is doing the following:
snprintf(buffer, sizeof(buffer), "/usr/lib/sendmail -oi %s", email);
sendmail = popen(buffer, "w");
[...]
If email contains unfiltered input the user can supply via a form field,
one could enter "bogus@email.address; rm -rf /". This would lead to
popen() calling
sh -c /usr/lib/sendmail -oi bogus@email.address; rm -rf /
and that will not start sendmail, but also remove all files in
directories the httpd-user has write access to. That's because the ";"
is a command separator for the shell.
One method to prevent that for any command is to replace every ' in the
user-supplied data with '\'' (note that you have to double the backslash
when adding that to C code) and enclose the resulting string in '. This
way, the above command would become
sh -c /usr/lib/sendmail -oi 'bogus@email.address; rm -rf /'
This isn't dangerous anymore, as the ; is now part of the third
parameter to sendmail and thus is no longer special to the shell.
And even if someone entered "bogus@email.address'; rm -rf /" the first
step would neutralize the ', resulting in
sh -c /usr/lib/sendmail -oi 'bogus@email.address'\''; rm -rf /'
I know this is far beyond the scope of the original question, but it's
important to know when using popen() nonetheless. Also don't forget that
the same applies to system() as well, which internally uses sh -c, too!
Ciao
Thomas
--
Thomas Binder (Gryf @ IRCNet) gryf@hrzpub.tu-darmstadt.de
PGP-key available on request!
Vote against SPAM: http://www.politik-digital.de/spam/
Attachment:
pgpekjBQ7B26m.pgp
Description: PGP signature