Replace host key automatically on linux - perl

I have a script that connects to an SFTP server with the following code:
use Net::SFTP::Foreign;
my %cfg = (
user => "$user",
password => "$password",
port => 22,
more => [-o => 'StrictHostKeyChecking no']
);
my $sftp = Net::SFTP::Foreign->new("$host",%cfg);
I am using StrictHostKeyChecking to make sure the script automatically accepts the ssh key.
The issue begins when the server replaces the host key with new one. I get the error: WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
So I have to manually remove the key by running ssh-keygen -R testserver.com
After that the script works fine again.
I am trying to find a way to autmatically replace the key if it changes.
Technically I can run ssh-keygen -R testserver.com every time the script runs, but I do not like that solution.
So far I am not able to a good automated way to replace the key.

Add another option that points UserKnownHostsFile to /dev/null should do the trick, not that it's recommend from security perspective ;-)
use Net::SFTP::Foreign;
my %cfg = (
user => "$user",
password => "$password",
port => 22,
more => [-o => 'StrictHostKeyChecking=no',
-o => 'UserKnownHostsFile=/dev/null']
);
my $sftp = Net::SFTP::Foreign->new("$host",%cfg);

Related

Not able to use 'copy_perm' option in Net::SFTP::Foreign module

I want to copy the file from remote host to the local host with the preservation of file permission, hence i tried to use the 'copy_perm' option as per the documentation of Net::SFTP::Foreign as mentioned below -
my $sftp = Net::SFTP::Foreign->new(
host => $host,
key_path => $ssh_key_path,
copy_perm => 1,
more => [ -o => 'Compression yes' ]
);
But I am getting the below error -
Invalid option 'copy_perm' or bad combination of options at test.pl at line 101.
The line 101 is the Net::SFTP::Foreign object creation as mentioned above.
Did i miss anything or anyone has faced same issue before?
That's because copy_perm isn't an option for the new method. You use it in get and put.

can't ssh:unable to establish master SSH connection: bad password or master process exited unexpectedly

I have problem with perl modules, i 'm trying to connect to the remote server using the OpenSSH module from CPAN and i have given the username and password correctly but when i run my CGI from browser i see the following error message "
can't ssh:unable to establish master SSH connection: bad password or
master process exited unexpectedly
in need of immediate reply's and awaiting,
Thanks in Advance.
Here is my code
#!/usr/bin/perl -w
use CGI;
use Data::Dumper;
use strict;
use CGI::Carp qw(fatalsToBrowser);
use Net::OpenSSH;
my $query = CGI->new();
#my $mach_name=$query->param('mach_name');
my $mach_name= '****.cce.***.com';
my $user='root';
my $passwd='*******';
my $ssh = Net::OpenSSH->new("$mach_name",user => "$user" , passwd => "$passwd
", master_opts => [-o => "strictHostKeyChecking=no"]);
$ssh->error and die "can't ssh:" . $ssh->error;
my $mem_info =$ssh->capture("ioscan -m lun");
print "$mem_info";
print "Content-type: text/html\n\n";
print "<html><head><title>test page</title></head>\n";
print "<body><p>Dicovering Machine Please wait....</p>\n";
print "<p>$mach_name</p>";
print "<p><b>Swap Memory :$mem_info </b> </p>";
print "</body></html>";
The same program if i run through the command line it is getting the o/p but through the browser i'm seeing the above error i have given the passwd and username correctly
My problem was solved when I've increased the timeout from 10 seconds to 15 seconds, because the device is using an older SSH daemon version, but my linux server that made the client connection is upgraded and of course it probes first the newer ciphers.
my $ssh = Net::OpenSSH->new(
$host,
port => $port,
user => $user,
password => $pass,
timeout => 15, # <= this was 10 and now is 15
kill_ssh_on_timeout => 1,
strict_mode => 0,
master_opts => [-o => "StrictHostKeyChecking=no", '-vvv'], #<= -vvv helped much
ctl_dir =>'/tmp/libnet-openssh-perl',
Looks like some permissions issue. Run ssh in verbose mode:
my $ssh = Net::OpenSSH->new("$mach_name",
user => "$user",
passwd => "$passwd",
master_opts => '-vvv',
master_stderr_fh => \*LOG);
If that doesn't give you enough information about the cause of the problem, then, you can use truss to see what's happening at the OS level.
Also check .ssh/known_hosts, make sure .ssh directory is writeable by Apache. .libnet-openssh-perl directory should be writeable by Apache.
For example, my Apache user is apache with a home directory of /var/www
I have /var/www/.ssh owned by apache, and /var/www/.libnet-openssh-perl owned by apache. I ssh to devices using my own account, then copy my known_hosts file to /var/www/.ssh/known_hosts

SSH login through 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.
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:
Net::Appliance::Session rely on connection profile. The correct one is named "bash" and not "Bash"
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.
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).
Try using Net::OpenSSH instead. It would be easier to use and more reliable when talking to a Unix server.

Cannot reload Cisco device using perl Net::Appliance::Session library

I am trying to reboot a Cisco device using net::appliance::session library. But even the code doesn't give en error the device doesn't reboot. This is the two lines I am using:
$session->cmd(String => 'Reload',Match => ['/Proceed/'], );
$session->cmd(String => "\n", Match => ['//'],);
In the Cisco shell a reload command is given like this:
test#reload
Proceed with reload? [confirm]
Connection closed by foreign host.
This thread in the cpan forum also tells me to do this way. I think there is a problem with carriage returns and confirm dialogs. Because when I try to create a directory it works fine:
$session->cmd(String => 'mkdir',Match => ['/Create dire.*/'] );
$session->cmd(String => 'test',Match => ['//'] );
The equivelant of this in Cisco shell:
test#mkdir
Create directory filename []? test
Created dir flash:test
But when I try to delete this directory which needs a carriage return as confirmation the scripts fails again.
$session->cmd(String => 'rmdir asd',Match => ['/Remove directory.*/'] );
$session->cmd(String => '\n' ,Match => ['/Delete flash.*/'] );
$session->cmd(String => '\n');
The equivelant in Cisco is this:
test#rmdir test
Remove directory filename [test]?
Delete flash:test? [confirm]
Removed dir flash:test
So I think the problem isn't with reload command. But the problem is sending carriage returns as confirmation. I have tried \n \r \n\r \r\n and empty string but they didn't work.
Any ideas?
Maybe the Cisco device is case sensitive? In the example you used 'reload' and 'Reload' in the Perl code.
Maybe you could try this:
$session->say('reload');
$session->gather();
$session->say('confirm');
$session->gather();

Perl SCP ERROR(Asking to Continue?)

Here's is what I am doing
my $username = "user";
my $password= "pass";
my $host="xxx.xxx.xxx.xxx";
my $scpe = Net::SCP::Expect->new(user => $username,
password => $password,
preserve => 1,
recursive => 1,
verbose=>1,
auto_yes=>1);
$scpe->scp("$file","$host:./drop/drop.txt");
When I run this code there is no error I am using unix box, $file is in my directory and have full permissions, also I have changed the directory to temp in unix box but when somebody else runs this code they get
Problem performing scp: Are you sure
you want to continue connecting
(yes/no)? at scp.pl line 242
I am very confused why is it happening, as this error is not received by me
Short answer:
Raise the timeout_auto value:
my $scpe = Net::SCP::Expect->new(user => $username,
password => $password,
preserve => 1,
recursive => 1,
verbose=>1,
timeout_auto=>10, #For example - 5 should probably be plenty
auto_yes=>1);
Long answer.
The
problem performing scp
is what Net::SCP::Expect prepends to the literal error message it gets from SCP itself, so in this case
Are you sure you want to continue
connecting (yes/no)?
This usually happens because the host SCP is connecting to is not yet known.
You should set auto_yes to 1 if you want to avoid this error as the CPAN Documentation for NET::SCP::Expect explains, but I see you're already doing that.
If that doesn't help, consider raising the timeout_auto value. It defaults to 1 second, but if it takes longer for SCP to pose the 'are you sure' question (because for example the DNS looking of the host takes longer), it might not be enough.