Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SSH login through Perl

Tags:

ssh

rsa

cygwin

perl

I am using Net:Appliance::Session to login to a remote Unix server, but am not able to connect. Below is my code and the debug output:

my $s = Net::Appliance::Session->new({
     personality => 'Bash',
     transport => 'SSH',
     host => $host,
});
$s->set_global_log_at('debug');
try {
     print "Trying to connect\n";
     $s->connect({ username => $user, password => $pass });
     print "Executing command\n";
     print $s->cmd($cmd);   
}
catch {
     warn "failed to execute command: $_";
}
finally {
     $s->close;
};

And the output is:

Trying to connect
[   0.019420] pr finding prompt
[   0.028553] tr creating Net::Telnet wrapper for ssh
[   0.031377] tr connecting with:  ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o CheckHostIP=no -l user ...
[   3.151205] du   SEEN:
Warning: Permanently added '...' (RSA) to the list of known hosts.
[   3.183935] pr failed: [Can't call method "isa" on an undefined value at /usr/lib/perl5/site_perl/5.14/Net/CLI/Interact/Phrasebook.pm line 247.
], sending WAKE_UP and trying again
[   3.184943] pr finding prompt
[   4.898408] du   SEEN:
Warning: Permanently added '...' (RSA) to the list of known hosts.
Password:
[   4.920447] pr failed to find prompt! wrong phrasebook?
failed to execute command: Warning: Permanently added '...' (RSA) to the list of known hosts.
Password:
        ...propagated at /usr/lib/perl5/site_perl/5.14/Net/CLI/Interact/Role/Prompt.pm line 127.

When I login through Putty, I get the following response and can login successfully:

login as: user
Using keyboard-interactive authentication.
Password:

I cannot figure out what I am doing wrong. Any help is appreciated.

EDIT: I think I should mention that I am using Cygwin for this. I have manually logged in to the remote server and the keys in my .ssh/known_hosts file are also set, but still get the RSA error when running this program in Cygwin. I saw this question in SO: "Warning: Permanently added to the list of known hosts” message from Git and added the line UserKnownHostsFile ~/.ssh/known_hosts to my config file, but the error refuses to go away.

EDIT2: When I use the -vvv option in the above program, I get the following output:

Trying to connect
[   0.020327] pr finding prompt
[   0.062541] tr creating Net::Telnet wrapper for ssh
[   0.063709] tr connecting with:  ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o CheckHostIP=no -vvv -l user 1.1.1.1
[   0.731041] du   SEEN:
OpenSSH_6.2p2
[   0.851829] pr failed: [Can't call method "isa" on an undefined value at /usr/lib/perl5/site_perl/5.14/Net/CLI/Interact/Phrasebook.pm line 247.
], sending WAKE_UP and trying again
[   0.852459] pr finding prompt
[   0.852748] du   SEEN:
OpenSSH_6.2p2, OpenSSL 1.0.1e 11 Feb 2013
[   0.863739] pr failed to find prompt! wrong phrasebook?
failed to execute command: OpenSSH_6.2p2, OpenSSL 1.0.1e 11 Feb 2013
        ...propagated at /usr/lib/perl5/site_perl/5.14/Net/CLI/Interact/Role/Prompt.pm line 127.
like image 539
user828647 Avatar asked May 23 '26 12:05

user828647


2 Answers

The Net::Appliance::Session module is using is set of matching patterns called "Phrasebook" to guess password query output, command ending prompt, ...

In your case, there are 2 major issue and one minor/cosmetic one:

  1. Net::Appliance::Session rely on connection profile. The correct one is named "bash" and not "Bash"
  2. The bash default phrasebook (located in "~site_perl/Net/CLI/Interact/phrasebook/unix/bash/pb") is targeting ssh/bash based appliance and is not matching your everyday unix server behavior:

    prompt user  
        match /[Uu]sername: $/  
    
    prompt pass
        match /password(?: for \w+)?: $/
    
    prompt generic
        match /\w+@.+\$ $/
    
    prompt privileged
        match /^root@.+# $/
    
    macro begin_privileged
        send sudo su -
        match pass or privileged
    
    macro end_privileged
        send exit  
        match generic  
    
    macro disconnect  
        send logout  
    

    As you can see, both "generic" and "pass" prompt does not match your usual linux password and prompt. You will need to adjust it to your needs:

    • create a library structure by creating some nested directory: "mylib\mybash\"
    • make a copy of the "bash" phrasebook to that nested directory and edit it to match your unix server behaviour.
  3. There is also the ssh warning output:

Warning: Permanently added '...' (RSA) to the list of known hosts.

You just need to set ssh warnings to off using either the "-q" or "-o LogLevel=quiet" options to the ssh calling options.

So, in the end, your code would look like that:

my $s = Net::Appliance::Session->new
  ({ add_library     => 'mylib',
     personality     => 'mybash',
     transport       => 'SSH',
     host            => $host,
     connect_options => { opts => [ '-q', ], },
   });
$s->set_global_log_at('debug');
try {
    print "Trying to connect\n";
    $s->connect({ username => $user, password => $pass });
    print "Executing command\n";
    print $s->cmd($cmd);
}
catch {
    warn "failed to execute command: $_";
}
finally {
    $s->close;
};

With a phrasebook like this one (quickly tuned to my freebsd server):

prompt user
    match /[Uu]sername: $/

prompt pass
    match /[Pp]assword:\s*$/

prompt generic
    match /\w+@.+[\$>] $/

prompt privileged
    match /^root@.+# $/

macro begin_privileged
    send sudo su -
    match pass or privileged

macro end_privileged
    send exit
    match generic

macro disconnect
    send logout

macro paging
    send terminal length %s

NOTE:
About "Net::Appliance::Session" vs "Net::OpenSSH":

  • both modules are handling ssh connectionx fine
  • "Net::Appliance::Session" is more "cisco/whatever-appliance" oriented, but should permit easily to connect to a server, execute 1 command, get its result, then go root and execute another command (very handy if you don't have direct root access from ssh)
  • "Net::OpenSSH" is handling command execution though ssh on 1 command only basis, that is it execute a command, get its result and exit. No direct way to set an environment, go root and execute the command (you need to use a wrapper like Net::Telnet on it to do that)
  • "Net::OpenSSH" requires a fairly recent version of openssh client and does not work on Windows, not even under Cygwin (see "Net::OpenSSH" manual).
like image 141
Ouki Avatar answered May 25 '26 03:05

Ouki


Try using Net::OpenSSH instead. It would be easier to use and more reliable when talking to a Unix server.

like image 38
salva Avatar answered May 25 '26 04:05

salva