Skip to main content.
home | support | download

Back to List Archive

Re: configuring and debugging swish.cgi with IIS

From: Nathan Vonnahme <nathan.vonnahme(at)>
Date: Thu Jun 12 2003 - 01:21:32 GMT
Ahah!  I think I have confirmed that IPC::Open2 does not use the shell.  And my original post to the list specifying the quotes around "Program Files" appears to not really be necessary after all...   I don't know what my problem was the other day, and I'm sorry if I've caused anybody grief or alarm!

The gory details follow.

This test script:  

	use IPC::Open2;

	# using the shell, chokes on space
	$pid = open2($rdrfh, $wtrfh, 'C:\Program Files\SWISH-E\swish-e.exe -w foo');
	print scalar <$rdrfh>, '-'x50, "\n";
	# using the shell, properly escaped
	$pid = open2($rdrfh, $wtrfh, 'C:\"Program Files"\SWISH-E\swish-e.exe -w foo');
	print scalar <$rdrfh>, '-'x50, "\n";
	# without using the shell
	$pid = open2($rdrfh, $wtrfh, 'C:\Program Files\SWISH-E\swish-e.exe', "-w", "foo");
	print scalar <$rdrfh>, '-'x50, "\n";

produces this output:
	'C:\Program' is not recognized as an internal or external command,
	operable program or batch file.
	# SWISH format: 2.2.3
	# SWISH format: 2.2.3

So, swish.cgi using open2 should be avoiding the shell.  I must have had some other problem the other day, and I finally got the swish binary to run by hand from DOS by quoting "Program Files" so I tried that in the swish.cgi config and it worked.

At least, system(1, @array) is supposed to not use the shell according to perldoc perlfunc and perlport, and therefore open2($rfh, $wfh, @array) is supposed to not use it too, and this example shows that it doesn't choke on the space like it would if it was using the shell.

SO:  a pretty good solution for all the other system calls would be something like this subroutine (with code I used to test it):

#print safer_backticks('C:\Program Files\SWISH-E\swish-e.exe -w foo');  # see if the erroneous usage thing works
#print "\n", '-'x50, "\n";
print safer_backticks('C:\Program Files\SWISH-E\swish-e.exe', '-w', 'foo>junk'); 
print "\n", '-'x50, "\n";
print safer_backticks('C:\Program Files\SWISH-E\swish-e.exe', '-w', 'foo'); 
print "\n", '-'x50, "\n";
print safer_backticks('catdoc', "-a", 'N:\IT\Procedures\testdoc.doc') ; 

# safer_backticks('catdoc', 'blah', 'blah')
# a safer alternative to `catdoc blah blah`
sub safer_backticks {
	die "this won't be safe unless you pass the args as an array, smarty!" if $#_ == 0 && $_[0] =~ /[ ;]/;
	warn "oop, now now you're not trying none of that fancy pipe/file redirection shell business are you?" if join(' ',@_) =~ /[\|\>\<]/;
	use IPC::Open2;

    my ( $rdrfh, $wtrfh );
    my $pid = IPC::Open2::open2($rdrfh, $wtrfh, @_ );

	return <$rdrfh>;

It's not as good as the forking you're doing in case swish runs for a long time, but it's better than backticks and about as easy to use.


>>> <> 06/10/03 09:20PM >>>
On Tue, Jun 10, 2003 at 05:24:01PM -0700, Nathan Vonnahme wrote:

> > Well, without fork/exec on Windows it's hard.  I'm sure there's some 
> > Win32 specific functions to do that, but I have never looked into it.  I 
> > spent a *year* posting to Win32 CGI lists asking how to securely run an 
> > external program (like swish-e) from a CGI script and never got any 
> > response.
> I was thinking that that's what you're doing with IPC::Open2, right?
> At least, its documentation claims:
>     $pid = open2(\*RDRFH, \*WTRFH, 'some cmd and args');
>       # or without using the shell
>     $pid = open2(\*RDRFH, \*WTRFH, 'some', 'cmd', 'and', 'args');
> so
> since you're passing an array it shouldn't use the shell (and as far
> as I can tell from reading IPC::Open* and IO::Pipe, it doesn't), but
> apparently on Windows it still barfs on that unescaped space, so it
> must be interacting with DOS somehow.  I guess if you use
> system(@array) it's not supposed to use the shell, but if the first
> arg has a space it probably thinks you do need to use the shell, or
> something like that?

Most of that documentation was written before porting Perl to Windows. 

Anyway, that's what I hoped when I switched form a piped open to
IPC::Open.  Someone recommended it to me at one point as a solution to
the shell problem.  I had Windows at the time and I do remember a few
choice words I had after switching to IPC and seeing that the shell was 
still used.  At least that's what I remember happening.

> The escaping and quoting method above should be find for everything,
> but I think it would be possible to just write a backtick() type
> subroutine that uses IPC::Open2 or 3, then I think you would be
> forever free from shell metacharacter exploits, though you'd still
> need to do the escaping/quoting thing on Windows at least.  It might
> not be worth it though... just escaping and quoting should be pretty
> foolproof.

IPC::Open2 uses IPC::Open3, and when running under windows I think it
finally uses a system().  Let me look. (tap..tap...tap...)  yes, open3
calls _open3 which checks $do_spawn which is true on Win32 and then
calls spawn_with_handles() which does the system call:

         $pid = eval { system 1, @_ };  # 1 == P_NOWAIT

I'm not very clear on that style of system() call, but it is described 
somewhere in perldoc perlport.  IIRC, that call does a spawn() on 
Windows -- not that I know what that does.

That's all just a quick look, though.

I don't have Windows, but it would be really interesting if you could
try IPC::Open3 and throw in some metachars and see it it croaks.  Maybe
mess with COMSPEC or whatever Windows uses to define the shell.  It
would be interesting to see if I was mistaken about IPC::Open* running
through the shell.  But, the requirement to place the swish-e binary
path in quotes makes me think it does, though.

On other systems fork/exec is the way to go.  On Windows maybe 
Win32::Process would be the way to go.  Someone else will need to go 
down that road.


Bill Moseley
Received on Thu Jun 12 01:21:34 2003