How to pass password via Perl script - perl

I have a situation where in I am calling the below Perl script
if (param("lremail") && param("lot")) {
my $address=param("lremailaddress");
my $lot=param("lot");
print a({-href=>"$dir/new.pl"},"Back to Top"),br;
print "Request submitted for $address.",br;
print "Lot $lot",br;
print "You will receive an e-mail with a link to the data when the request is complete.";
print end_html;
system ("ssh SERVERNAME /test/abc.csh $lot $$ $address &");
exit(1);
The above script does not run because when I execute the system is prompted for a password. Then I looked it up and found the below command..
expect -c 'spawn ssh SERVERNAME /test/abc.csh J213520 06 abc#gmail.com "ls -lh file"; expect "Password:"; send "PASSWORD\r"; interact'
The above command is executed successfully without any issue but from the command line only. When I incorporate the same(by replacing the system call) within the Perl script, it fails. How can I incorporate within the first script?

Reiterating and adding to comments:
Consider using a key-based authentication either with passphrase-less keys or with ssh-agent (e.g., using ssh-keygen generated/managed identities);
Consider using sshpass or another expect-like external;
Consider using the Perl Expect or an equivalent CPAN module; and/or,
Consider using the Perl Net::SSH or an equivalent CPAN module.
Also, system can easily introduce remote code execution vulnerabilities, especially when using its system LIST syntax.

Related

Using expect from Perl

I have a situation where in I am calling the below Perl script
if (param("lremail") && param("lot")) {
my $address=param("lremailaddress");
my $lot=param("lot");
print a({-href=>"$dir/new.pl"},"Back to Top"),br;
print "Request submitted for $address.",br;
print "Lot $lot",br;
print "You will receive an e-mail with a link to the data when the request is complete.";
print end_html;
system ("ssh SERVERNAME /test/abc.csh $lot $$ $address &");
exit(1);
The above script does not run because when I execute the system is prompted for a password. Then I looked it up and found the below command..
> expect -c 'spawn ssh SERVERNAME /test/abc.csh J213520 06 abc#gmail.com "ls -lh file"; expect "Password:"; send "PASSWORD\r"; interact'
The above command is executed successfully without any issue but from the command line only. When I incorporate the same(by replacing the system call) within the Perl script, it fails.
How can I incorporate within the first script?
There's an Expect module for Perl.
However, I tend to write straight expect scripts and call them from Perl. That way I can use the expect scripts on their own. But then, I used to do a lot of Tcl too.

Running a program that requires a password on the command line from a Perl script

I have written a Perl wrapper around a shell script. I am using IPC::Run::Simple to execute system commands. As an example:
run ("mkdir ~$usr/12.2.0_cp/faiz_cpv/$pdate") or die "Error $ERR";
run ("cp ~$usr/12.2.0_cp/faiz_cpv/MPlist.lst ~$usr/12.2.0_cp/faiz_cpv/$pdate") || die "Error: $ERR";
run ("cd ~$usr/12.2.0_cp/faiz_cpv/$pdate; sh /opsutils/mfg_top/rel/CPV/bin/list_generation.sh . MPlist.lst mfg_relall_us\#oracle.com") or die "error $ERR";
.
.
One of these shell scripts requires the user of the script to enter their password. That is, a message is printed on stdout and the password is accepted via the shell. A number of calls are made to this shell script during the entire process which means a user must reenter his password a number of times.
Is there a way by which I can request user for the password at the command line itself, and pass that password implicitly instead of prompting user for the password again and again?
Perl has mkdir and chdir built in and File::Copy provides a copy routine. Its generally safer and faster to use them than shelling out. Though it will not translate ~ for you. File::chdir makes changing a directory and running a command a little safer.
For the rest, use the full IPC::Run to control interacting with your program and Term::ReadLine::Gnu to read the password without displaying it. Sorry this is just a sketch and not a full answer.

Missing output when running system command in perl/cgi file

I need to write a CGI program and it will display the output of a system command:
script.sh
echo "++++++"
VAR=$(expect -c " spawn ssh -o StrictHostKeyChecking=no $USER#$HOST $CMD match_max
100000 expect \"*?assword:*\" send -- \"$PASS\r\" send -- \"\r\" expect eof ")
echo $VAR
echo "++++++"
In CGI file:
my $command= "ksh ../cgi-bin/script.sh";
my #output= `$command`;
print #output;
Finally, when I run the CGI file in unix, the $VAR is a very long string including \n and some delimiters. However, when I run on web server, the output is
++++++
++++++
So $VAR is missing when passing in the web interface/browser.
I know maybe the problem is $VAR is very long string.
But anyway, is there anyway to solve this problem except writing the output to a file then retrieve it from browser?
Thanks if you are interested in my question.
script.sh uses several environment variables: $USER, $HOST, $CMD and $PASS. The CGI environment will have different environment variables set than a login shell. You may need to set these variables from your CGI script before calling script.sh.
Try finding where commands like expect and ssh that you are calling are on your system and adding their directory paths to the PATH used by your script.
I.e.
which expect
returns /usr/bin/expect then add the line:
PATH=$PATH:/usr/bin && export PATH
near the beginning of the ksh script. During debug you may also want to redirect stderr to a file by appending 2>/tmp/errors.txt to the end of your command since stderr is not shown in the browser.
my $command= "ksh ../cgi-bin/script.sh 2>/tmp/errors.txt";

How can I send POST and GET data to a Perl CGI script via the command line?

I am trying to send a get or a post through a command-line argument. That is test the script in the command line before I test through a browser (the server has issues). I tried searching online, and I suppose I was probably using incorrect terminology because I got nothing. I know this is possible because I saw someone do it. I just don't remember how it was done.
Thanks! :)
To test a CGI program from the command line, you fake the environment that the server creates for the program. CGI.pm has a special offline mode, but often I find it easier not to use because of the extra setup I need to do for everything else my programs typically expect.
Depending on the implementation of your script, this involves setting many environment variables, which you can do from a wrapper script that pretends to be the server:
#!/bin/bash
export HTTP_COOKIE=...
export HTTP_HOST=test.example.com
export HTTP_REFERER=...
export HTTP_USER_AGENT=...
export PATH_INFO=
export QUERY_STRING=$(cat query_string);
export REQUEST_METHOD=GET
perl program.cgi
If you're doing this for a POST request, the environment is slightly different and you need to supply the POST data on standard input:
#!/bin/bash
export CONTENT_LENGTH=$(perl -e "print -s q/post_data/");
export HTTP_COOKIE=...
export HTTP_HOST=test.example.com
export HTTP_REFERER=...
export HTTP_USER_AGENT=...
export PATH_INFO=...
export QUERY_STRING=$(cat query_string);
export REQUEST_METHOD=POST
perl program.cgi < post_data
You can make this as fancy as you need and each time you want to test the program, you change up the data in the query_string or post_data files. If you don't want to do this in a shell script, it's just as easy to make a wrapper Perl script.
Are you using the standard CGI module?
For example, with the following program (notice -debug in the arguments to use CGI)
#! /usr/bin/perl
use warnings;
use strict;
use CGI qw/ :standard -debug /;
print "Content-type: text/plain\n\n",
map { $_ . " => " . param($_) . "\n" }
param;
you feed it parameters on the command line:
$ ./prog.cgi foo=bar baz=quux
Content-type: text/plain
foo => bar
baz => quux
You can also do so via the standard input:
$ ./prog.cgi
(offline mode: enter name=value pairs on standard input; press ^D or ^Z when done)
foo=bar
baz=quux
^D
Content-type: text/plain
foo => bar
baz => quux
Old discussion, but I was looking for the same answers - so for those who follow - this is what I found out
RTFM! from the CGI man page ( and there is more )
DEBUGGING
If you are running the script from the command line or in the perl
debugger, you can pass the script a list of keywords or parameter=value
pairs on the command line or from standard input (you don't have to
worry about tricking your script into reading from environment
variables). You can pass keywords like this:
your_script.pl keyword1 keyword2 keyword3
or this:
your_script.pl keyword1+keyword2+keyword3
or this:
your_script.pl name1=value1 name2=value2
or this:
your_script.pl name1=value1&name2=value2
To turn off this feature, use the -no_debug pragma.
If you don't want to alter the perl script, you can call it with at least two environment variables set, as others mentioned already. To simulate a GET request:
shell$ QUERY_STRING=limit=20 REQUEST_METHOD=GET ./events_html.pl
That's the console shortcut for www.myserver.org/events_html.pl?limit=20
Yes, it's possible to do this from the command line, bypassing your server. This page explains all: Perl CGI debugging (sitewizard.com) (Especially item 6 on that page). Here I quote the most important part:
To test the script offline using the
GET method, simply set the
QUERY_STRING environment variable
accordingly. If you are using Windows,
you might use the following command
line in a DOS window prior to running
the script in the same window:
set QUERY_STRING=recipient=John#Doe.com&Fullname=M+Name
To test the script offline using the
POST method, put the line below into a
text file named, say, testinput.txt.
recipient=John#Doe.com&Fullname=M+Name
Then redirect that file as an input to
the script. On Unix systems as well as
under Windows' MSDOS prompt, you can
do it this way:
perl -w scriptname.pl < testinput.txt
Your script will then receive that
input as though it was sent it by a
form on the website. Check the error
messages that perl spouts, if any, to
help you track the problem in the
script.
To give a cgi script post data:
$ echo -n 'a=b;c=d' | REQUEST_METHOD=POST CONTENT_LENGTH=999 perl index.cgi
To give a cgi script get data:
$ perl index.cgi 'a=b;c=d'
LWP comes with ready made scripts that can be used from the command-line. Check for GET and POST scripts in your system.
In Windows, you can use VBScript to write a command line util that calls into the MS XML library:
Dim XMLHttp : Set XMLHttp = CreateObject("Microsoft.XMLHTTP")
On Error Resume Next
strIPAddress = WScript.Arguments(0)
strMACAddress = WScript.Arguments(1)
strSubnetMask = WScript.Arguments(2)
On Error Goto 0
WScript.Echo "Attempting to wake host " & strIPAddress & " on NIC " & strMACAddress &
"using netmask " & strSubnetMask
strGetUrl = http://wolService/WolService/WolService.asmx/WakeBroadcast?hostIP=" &
strIPAddress & "&macAddress=" & strMACAddress & "&subnetMask=" & strSubnetMask
XMLHttp.Open "GET", strGetUrl, False
XMLHttp.Send ""
WScript.Echo XMLHttp.ResponseText
Edit: This script sends HTTP requests and can be used from the command line. I got confused by the question 'How can I send POST and GET data to a Perl CGI script via the command line' and thought this was about sending POST and GET data to a Perl CGI script via the command line from an unspecified client OS.

How can I get the command-line output of a DOS tool using Perl?

I want to meassure the throughput of a link using Windows build-in FTP tool inside a Perl script. Therefore the script creates the following command script:
open <ip>
<username>
<password>
hash
get 500k.txt
quit
Afterwards I run the command script using the following Perl code:
system(#args);
#args = ("ftp", "-s:c:\\ftp_dl.txt");
system(#args);
If I run the command inside a DOS-box the output looks like this:
ftp> open <ip>
Connected to <ip>
220 "Welcome to the fast and fabulous DUFTP005 ftp-server :-) "
User (<ip>:(none)):
331 Please specify the password.
230 Login successful.
ftp> hash
Hash mark printing On ftp: (2048 bytes/hash mark) .
ftp> get 500k.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for 500k.txt (14336 bytes).
#######
226 File send OK.
ftp: 14336 bytes received in 0.00Seconds 14336000.00Kbytes/sec.
ftp> quit
221 Goodbye.
To be able to get the throughput I need the extract that line:
ftp: 14336 bytes received in 0.00Seconds 14336000.00Kbytes/sec.
I'm not very familiar with Perl. Does anybody have an idea how to get that line?
Use either open in pipe mode:
open($filehandle, "$command|") or die "did not work: $! $?";
while(<$filehandle>)
{
#do something with $_
}
or use backticks:
my #programoutput=`$command`
You can't get the output with system().
Instead use bactkicks:
my $throughput = 0;
my $output = `ftp -s:c:\\ftp_dl.txt`;
if (($? == 0) && ($output =~ /([\d+\.]+)\s*K?bytes\/sec/m)) {
$throughput = $1;
}
$output will contain all the lines from the execution of the ftp command (but not any error message sent to STDERR).
Then we check if ftp returned success (0) and if we got a throughput somewhere in the output.
If so, we set $throughput to it.
This being Perl, there are many ways to do this:
You could also use the Net::FTP module that supports Windows to deal with the file transfer and use a timing module like Time::HiRes to time it and calculate your throughput.
This way you won't depend on the ftp program (your script would not work on localised version of Windows for instance without much re-work, and you need to rely on the ftp program to be installed and in the same location).
See perlfaq8, which has several answers that deal with this topic. The ones you probably need for this question are:
Why can't I get the output of a command with system()?
How can I capture STDERR from an external command?
Also, you might be interested in some of the IPC (Interprocess Communication) Perl modules that come in the standard library:
IPC::Open2
IPC::Open3
Some of the Perl documentation might also help:
perlipc - Perl interprocess communication
perlopentut - Perl open tutorial
If you're not familiar with the Perl documentation, you might check out my Perl documentation documentation.
Good luck,
You should try and use libcurl which is more suited for the task.
There is an easy to use API