Perl IO::Socket::INET permission denied - perl

Have a perl script to connect with a Java service running on localhost, passes encrypted cookie, and returns decrypted data. When I run script from command line, it works fine. Even gave apache user a shell, and ran from command line as that user, which also works fine. If the script is run as CGI from apache, the socket new returns undef and $! is set with "permission denied". ???
Running CentOS 6.3 on this server, and IPtables are disabled.
#!/usr/bin/perl
use strict;
use CGI;
use IO::Socket;
use JSON;
my $cgi = CGI->new();
my $cookie = $cgi->cookie('attESSec') || shift (#ARGV) || undef;
my $data = JSON::false;
if($cookie){
my $socket = IO::Socket::INET->new(
'PeerHost' => '127.0.0.1',
'PeerPort' => '1500',
'Proto' => 'tcp'
);
if($socket){
$socket->send($cookie . "\r\n");
$socket->recv(my $auth,1024);
$socket->close();
chomp($auth);
if($auth){
$data = (split(/\|/,$auth))[5];
}
}
else{
$data = $!;
}
}
print($cgi->header('application/javascript'));
print(JSON->new()->allow_nonref()->utf8()->encode($data));
exit();

I found the answer. The problem was SElinux. By default it doesn't let the httpd process (or anything that spawns from it, such as CGI scripts) establish network sockets. So just had to enable that particular feature with command "setsebool -P httpd_can_network_connect 1". Now it works perfectly.

Related

Perl socket, HP comware router

I'm trying to create a script in Perl that does the following
On a Windows 2008 R2 server, connects to a local OpenWRT router.
Send some commands to the router and save the output (interface brief)on a varaible
Edit the content of the variable (to keep the IP only)
Send the variable again to the router withinin another command
I created a socket but i dont seem to get any luck sending commands to the router. I'm not even sure if I'm logging in.
Here is my code:
use IO::Socket;
use strinct;
use warnings;
$iaddr = gethostbyname("192.168.1.237");
$ssh_port = 22;
$sin = sockaddr_in($ssh_port, $iaddr);
socket(DEV, PF_INET, SOCK_STREAM, getprotobyname('tcp'));
connect(DEV, $sin) || die "Can't connect to EN4000: $!\n";
print DEV "user\n";
print DEV "password\n";
print DEV "echo test >> /etc/config/networkTest \n";
I run it, check the file /etc/config/networkTest but no modification is made
Have a look at Net::SSH::W32Perl
Here's a quick example;
#!/usr/bin/env perl
use strict;
use warnings;
use Net::SSH::W32Perl;
my $host='example.com';
my $user='john';
my $pass="pass";
# Connect
my $ssh = Net::SSH::W32Perl->new($host);
$ssh->login($user, $pass);
# Run command
my $cmd = q(echo test >> /etc/config/networkTest);
my($stdout, $stderr, $exit) = $ssh->cmd($cmd);

Perl Net::SSH doesn't receive prompts

I am writing a script to communicate with a remote server. I understand how to send a basic shell command such as "ls" or "find / |grep foo". But I am executing an interactive application at the other end.
If I call $ssh->shell, I get the prompt from the remote server so I know that SSH is receiving this prompt. But then I can't do anything because the script is blocked in a shell.
I installed two handlers. If I use the script to connect to a basic ssh host, and execute a shell command, the response is delivered to the handlers, so I know they are ok. So I expected the prompt from the application I am executing to be sent to these but it isn't.
#!/usr/bin/perl -w
use strict;
use Net::SSH::Perl;
my $host = 'rt.olsendata.com';
my $user = 'rtdemo';
my $pass = 'rtdemo';
my %params = ('debug' => 1,'protocol' => 2);
my $ssh = Net::SSH::Perl->new($host, %params);
$ssh->register_handler("stderr", sub{
my ($ssh, $packet) = #_;
receiveerrors($packet);
});
$ssh->register_handler("stdout", sub{
my ($ssh, $packet) = #_;
receivedata($packet);
});
my ($output, $errors, $exit) = $ssh->login($user, $pass);
At this point I need to respond to the prompt by sending a "1". But this is interpreted by the remote host as a shell command, not a response to the prompt. It returns the error "h: 1: No such file or directory".
If you want to try it you can use the demo ssh account at the top of the code. It is publicly available.
Edit: I realise that Expect solves this issue, but I could not find any equivalent to register_handler() in Expect. Am I right in this?
I use expect to automate ssh/sftp sessions.
Net::SSH::Perl provides shell() method for "interactive" sessions. Otherwise, this one, like its brethren, assumes that you're executing a single command on a remote server.
The simplest solution by far is Net::SSH::Expect. Below is the code. Immediately upon login I need to send a "1" in response to the prompt ("1" is the choice I want). Then I get another prompt and since I want the default value I just send \n. Then I want to read the input line by line forever. It works like a charm.
my $ssh = Net::SSH::Expect->new (
host => $host,
user => $user,
password=> $pass,
raw_pty => 1
);
my $login_output = $ssh->login();
my $prompt = $ssh->exec("1");
my $line;
$ssh->send("\n");
while ( defined ($line = $ssh->read_line()) ) {
print "$line\n";
}

How to set the shell of remote server through perl telnet

How can I set the remote server shell to bash through the perl telnet?
My code is below:
$telnet = Net::Telnet->new(Timeout=>90,Errmode=>'die');
$telnet->open($ipAddress);
$telnet->login($username,$password);
$telnet->waitfor('/$/');
$telnet->print("exec bash");
print "after bash";
print $telnet->cmd("ls -lrt");
print $telnet->cmd("cd $homePath");
In the above code, after the exec bash statement, none of the commands are getting executed. I need to set the remote shell as bash because some of the processes I need to run after this lines require env settings.
Please let me know how can I do the same.
Your regex to wait for the command prompt is wrong
$telnet->waitfor('/$/');
Try
$telnet->waitfor('/\$ $/');
Even better, see the first example in the Net::Telnet 3.04 doc:
my $host = 'your_destination_host_here';
my $user = 'your_username_here';
my $passwd = 'your_password_here';
my ($t, #output);
## Create a Net::Telnet object.
use Net::Telnet ();
$t = new Net::Telnet (Timeout => 10);
## Connect and login.
$t->open($host);
$t->waitfor('/login: ?$/i');
$t->print($user);
$t->waitfor('/password: ?$/i');
$t->print($passwd);
## Switch to a known shell, using a known prompt.
$t->prompt('/<xPROMPTx> $/');
$t->errmode("return");
$t->cmd("exec /usr/bin/env 'PS1=<xPROMPTx> ' /bin/sh -i")
or die "login failed to remote host $host";
$t->errmode("die");
## Now you can do cmd() to your heart's content.
#output = $t->cmd("uname -a");
print #output;

Display Output In Browser Perl CGI SSH

I'm executing remote commands using Net::OpenSSH using a web frontend. My commands return without failure on the command line, but I get nothing in a web browser. I've done a couple hour research to no avail--any ideas?
Here is some code to give you an example (some removed for obvious reasons).
#!/usr/bin/perl -w
use strict;
use CGI ':standard';
use Net::OpenSSH;
# Here in the code is just the header and standard tags
print "1";
print "2"; # both display
my $ssh = Net::OpenSSH->new($host, user => $uname, key_path => $key); # all works
$ssh- error and die "Can't ssh to host" . $ssh->error;
print "3";
$ssh->system("uname -a") or
die "remote command failed: " . $ssh->error;
my #lsa = $ssh->capture("ls -a");
$ssh->error and
die "remote ls command failed: ". $ssh->error;
print "4";
print "5";
print #lsa; # won't display in browser, just terminal/CLI
Cheers!
I maintain CGI.pm. I recommend these additions to your simple script:
Before you print anything else, print the standard HTTP header: print header();
Add this after the use CGI line: use CGI::Carp qw(fatalsToBrowser); ... that will display any run-time problems in the browser. If you don't get any output after these changes, check that the script compiles with perl -cw script.pl
Below is about the minimum Perl code that worked for me on Debian machine. I suggest you go through it and compare it to your actual code.
However, it did not work out-of-the box on my Debian, I had make some decisions most of which probably aren't very safe, but that's more about specific environment:
make home for user that server runs writable (/var/www)
add host to ~/.ssh/known_hosts beforehand
use the strict_mode => 0 to bypass Net::OpenSSH's security checks instead of finding proper
ctl_dir (Net::OpenSSH requires that the folder and all above folders are 0755 or more strict,
so /tmp I used is normally not good enough)
I believe there are much safer practices than that, but as I said, that's specific to environment.
So the code:
#!/usr/bin/perl
use strict;
use warnings;
use Net::OpenSSH;
use File::Temp qw/ tempdir /;
# necessary minimum for CGI
print "Content-type: text/plain\n\n";
# prepare temp dir
my $temp = tempdir("/tmp/sshme.pl-XXXXXXXX", CLEANUP => 1);
# open SSH session
my %opts = (
user => "user",
password => "password",
ctl_dir => $temp,
strict_mode => 0 ## NOT recommended - see my comments
);
my $ssh = Net::OpenSSH->new("host", %opts);
$ssh->error
and die "Couldn't establish SSH connection: ". $ssh->error;
# perform command and print output
my #lines = $ssh->capture("ls")
or die "remote command failed: " . $ssh->error;
print #lines;
Perhaps your errors get directed to standard error, not standard output. In that case, they'll usually end up in the server log, not the browser window. Perhaps you can use POSIX::dup2 to avoid this:
use POSIX;
# Make sure to send HTTP headers before redirecting streams!
POSIX::close(2); # close original stderr stream. No more output to apache logs!!!
POSIX::dup2(1,2); # redirect error stream to standard output, so errors will appear in browser.
Processes launched by perl, like e.g. some ssh binary, will inherit these streams.

telnet inline with perl?

Is there a way to allow perl to initiate a telnet session and programmatically issue commands to that telnet session?
I initially tried a stupid method:
commands.pl:
sleep(1);
print $command1;
sleep(1);
print $command2;
and then
> perl commands.pl | telnet www.host.com port
This does not work.
There is a Net::Telnet module.
use Net::Telnet ();
$t = new Net::Telnet (Timeout => 10,
Prompt => '/bash\$ $/');
$t->open("sparky");
$t->login($username, $passwd);
#lines = $t->cmd("who");
print #lines;
(Example taken from that page.)
One option would be through Perl's interface to Expect.