Gossamer Forum
Home : General : Perl Programming :

Can a CGI script work within another cgi script?

Quote Reply
Can a CGI script work within another cgi script?
I have installed SiteKeeper scripts on my website to help me manage registered member's access into a hidden and secured directory on my ISP server. What this script does is to get the required files from a hidden directory and push it out into the browser for viewing. For example,

http://www.test.com/cgi-bin/sitekpr/getfile.pl/index.html

will get the index.html file from a hidden directory such as

http://www.test.com/cgi-bin/hidden/index.html

My problem started when I tried to install dbman scripts into that hidden directory

i.e. http://www.test.com/cgi-bin/hidden/dbman/db.cgi

and used SiteKeeper to retrive this db.cgi from that hidden directory. Instead of seeing a log-in screen (as processed by db.cgi), I get instead a screen which has a textual output of the db.cgi instead.

i.e. I see the following:

#!/usr/local/cgi-bin/perl
.
.
.

which is quite dangerous.

Question: Is there a way in which I can get a cgi script to work within another third party cgi script????

Thanks for your help!

David Tan
Quote Reply
Re: Can a CGI script work within another cgi script? In reply to
While it seems to me that site keeper may not keep your site as secure as you might like, there are ways to run another program from within the Site Keeper CGI. The problem with the program as I see it is simply that your Site Keeper is probably reading the file in as a text block and outputting it directly.

Its hard to say exactly how the program outputs data, but basically, what you will want to do is modify the program with a structure similar to this:
Code:
if ($file =~ m/cgi$/) { # if the file ends in "cgi"
# we use a left hand quote to run the file and save output to the variable
$output = `$file`;
} else {
open (FILE, $file);
$output = join ("\n", <FILE> );
close FILE;
}
Since I don't know the specifics of your code, its hard for me to tell you that the variables are those in the program. This is a basic example though. You could also do testing on other file types to restrict delivery in a variety of ways.


------------------
Fred Hirsch
Web Consultant & Programmer
Quote Reply
Re: Can a CGI script work within another cgi script? In reply to
Dear Fred:

Thank you so much for your help! I will have a look at the codes and see whether I can make modifications to it. If you like, I can sent a copy of the script to you for you to look at and experiment. :-)

Just a question. You mentioned that SiteKeeper may not be the mose secure way to manage a membership site. Can you recommend another script which will allow me to do so?

Thanks!

With much appreciation.

David Tan
Quote Reply
Re: Can a CGI script work within another cgi script? In reply to
Fred:

I had a look at my getfile.pl script (which retrives the required files) and have found a subroutine called SendFile which may be relevant for our discussion. Looking at that subroutine, it appears to be a little bit more complicated then I thought. Perhaps you could suggest a way in which I can implement your 'modification' into my script so that I can run cgi scripts within this program? Below is the SendFile subroutine. (I'm still new to programming under Perl :-) )

sub SendFile {
my $userID = shift;
my $path, $full_path, $file, $ext, $content_type;
my $CookiePath = $ENV{'SCRIPT_NAME'};

#set the cookie path to this script's directory.
$CookiePath = substr $CookiePath, 0, ( rindex $CookiePath, "/" );

#if no userID was passed in, use the current user's id.
$userID = ( defined $userID ) ? $userID : &GetClientUserID;

#determine what file is being requested.
$path = ( $ENV{'PATH_INFO'} ) ? $ENV{'PATH_INFO'} : $in{'file'};

#make sure a file has actually been specified.
unless ( $path ) {
&CgiError( "CGI Error", "No file was specified.<br>(Therefore, there is no file to return.)" );
exit;
}

#attempt to read the file.
$full_path = $FILE_ROOT . $path;
unless ( open( FILE, $full_path ) ) {
&CgiError( "CGI Error", "Could not read the requested file: \"$path\"<br>Either the file does not exist or it could not be read." );
exit;
}
binmode FILE; #just in case this is a DOS-based system.
read FILE, $file, -s $full_path;

#determine the content-type for the requested file.
$ext = substr $full_path, ( rindex $full_path, "." ) + 1;
$content_type = ( exists $mime{$ext} ) ? $mime{$ext} : "text/plain";

#send the content-type header for the indicated file.
print "Content-type: $content_type\n";
#make sure the client sets cookies for UserID and ConnKey.
print "Set-Cookie: UserID=$userID; path=". $CookiePath . "\n";
print "Set-Cookie: ConnKey=" . &GetConnectionKey . "; path=" .
$CookiePath . "\n\n";
#finally, send the file itself.
print $file;
exit;
}

Any help with the above section will be most appreciated. Thanks!

REgards
DAvid Tan
Quote Reply
Re: Can a CGI script work within another cgi script? In reply to
David,

I would make an modification of code as follows:
Code:
#attempt to read the file.
$full_path = $FILE_ROOT . $path;
unless ( open( FILE, $full_path ) ) {
&CgiError( "CGI Error", "Could not read the requested file: \"$path\"<br>Either the file does not exist or it could not be read." );
exit;
}
binmode FILE; #just in case this is a DOS-based system.
read FILE, $file, -s $full_path;

#determine the content-type for the requested file.

$ext = substr $full_path, ( rindex $full_path, "." ) + 1;
$content_type = ( exists $mime{$ext} ) ? $mime{$ext} : "text/plain";

#send the content-type header for the indicated file.

print "Content-type: $content_type\n";

#make sure the client sets cookies for UserID and ConnKey.

print "Set-Cookie: UserID=$userID; path=". $CookiePath . "\n";
print "Set-Cookie: ConnKey=" . &GetConnectionKey . "; path=" . $CookiePath . "\n\n";

#finally, send the file itself.
# START OF THE MODIFICATION
if ($full_path =~ m/cgi$/) { # if the file ends in "cgi"
# we use a left hand quote to run the file and save output to the variable
$output = `$full_path`;
$content = "Content-type: text/html";
$output =~ s/$content//g;
print $output;
} else { # END OF MODIFICATION (Remember to close this else below)
print $file;
exit;
}
}
Make sure you remember the extra right bracket at the end "}". There are some possible problems with this. Apparently, this system uses a cookie of some sort to save user data. This data may be lost by the program when it calls the CGI, I have tried to ensure that this gets saved as well, but, this is not a 100% fix. Another problem is the fact that you cannot pass query varaiables to the CGI, because it is essentially being called from the prompt. If you're looking for this type of function, you might be better served by modifying the CGI that you use. This can get a bit complex. It either involves saving the incoming form data into a file and then reading the file in your CGI program, or rerouting that input into STDIN. Its probably easiest to do the first one.

So, what does this do for us, basically, it SHOULD first see if the file exists and open it if it does, then it outputs some header info and slams the cookie into the browser (its not all that painful actually). Then, it checks if the file ends in "cgi". If it does, it will run the program and stash its output in $output. It will then strip out the content header, and print the HTML. This is slightly ineffiecient, because we open and store the actual content of the file's text even though we aren't outputting it (we output the CGI's run output, not the file text itself... confused?) Anyhow, it might be better in the long run for you to check out some more PERL, and either 1) Make two subroutines for each type of file or 2) completely rewrite this subroutine from scratch. Either way, you'll probably have a bit of coding on your hands. My suggestion would be to write/modify something that does what you want it to, and not rely on a middle ground to mesh a solution together.

Hope this helps,


------------------
Fred Hirsch
Web Consultant & Programmer