touriste75 has asked for the wisdom of the Perl Monks concerning the following question:

Hi all Working with a linux virtual machine without the possibility to install any module, my goal is to connect in SSH to several material and without the result in STDOUT, pass in console some command. I tried without success

use strict; use warnings; use Data::Dumper; use feature 'say'; no warnings 'uninitialized'; my @fail; my @CLI; my $pass; my $mire; my @ip; my $ssh_cli = 'ssh -o StrictHostKeyChecking=no -o ConnectTimeout=3 -l' +; print 'Login: '; chomp (my $login = <>); print 'Password: '; chomp (my $password = <>); print 'Fichier IP: '; chomp (my $SOURCE = <>); print 'Fichier ligne de commandes:'; chomp (my $commande = <>); open (my $source, "<", $SOURCE) or die "Can't open: $!"; while (my $line = <$source>) { $line =~ s/[\r\n]+//; push @ip, $line; } open (my $cli, "<", $commande) or die "Can't open: $!"; while (my $line = <$cli>) { $line =~ s/[\r\n]+//; push @CLI, $line; } foreach my $ip (@ip) { my $SSH = system "$ssh_cli $login $ip"; if ($SSH =~ /username/i) { my $pass = print "$login\n"; } else { say "Connexion SSH $ip echec"; push @fail, $ip; say '-' x 20; next; } if ($SSH =~ /password/i) { my $mire = print "$password\n"; } else { say "Connexion SSH $ip echec"; push @fail, $ip; say '-' x 20; next } if ($SSH =~ /[>]$/) { foreach (@CLI) { say "$_"; my $resultat = print "$_\n"; print "$resultat"; } } else { say "Commande show version KO"; push @fail, $ip; next; } } say; say '### Connexion SSH KO ###'; foreach (@fail) { say "$_"; }

RESULT:

ZZZ@YYY:~$ perl SSH.pl

Login: TOTO

Password: TATA

Fichier IP: SSH.txt

Fichier ligne de commandes:SSH-commandes.txt

User Access Verification

Username:

I made another trie simpler with the module IPC::Open3 in the core to read and write the process but no more success.

use strict; use warnings; use Data::Dumper; use feature 'say'; no warnings 'uninitialized'; use IPC::Open3; print 'Login: '; chomp (my $login = <>); print 'Password: '; chomp (my $password = <>); print 'Fichier IP: '; chomp (my $SOURCE = <>); print 'Fichier ligne de commandes:'; chomp (my $commande = <>); my $cmd = 'ssh -o StrictHostKeyChecking=no -o ConnectTimeout=3 -l'; my $pid = open3(\*WRITER, \*READER, \*ERROR, $cmd); #if \*ERROR is 0, stderr goes to stdout while( my $output = <READER> ) { print "output->$output"; if ($output =~ /username/i) { print WRITER "nsoc-iec\n"; } }

RESULT:

ZZZ@YYY:~$ perl SSH.pl

Login: TOTO

Password: TATA

Fichier IP: SSH.txt

Fichier ligne de commandes:SSH-commandes.txt

ZZZ@YYY ~/SCRIPT

$

Someone have a lead ?

Thanks

Replies are listed 'Best First'.
Re: SSH and expect without module
by haukex (Archbishop) on Mar 15, 2017 at 15:46 UTC
    my $SSH = system "$ssh_cli $login $ip"; if ($SSH =~ /username/i) {

    Sorry, this will not do what you expect. system waits until the command finishes, does not capture the command's output and does not allow interactive communication with the subprocess.

    I would instead recommend the module Net::OpenSSH. Its documentation shows you how to integrate it with other modules such as Expect. Since you seem to want to connect to multiple remote machines to execute commands there, you might also take a look at Net::OpenSSH::Parallel (I haven't used it myself yet but I've heard good things).

    without the possibility to install any module

    I recommend you have a look at Yes, even you can use CPAN. If you really, really can't install any modules, you could have a look at my writeup on interacting with external commands here and you'd have to study perlipc, but I would strongly recommend you follow the above advice to use something like Net::OpenSSH instead. There was even a thread two days ago asking a question similar to yours, in which salva mentioned you can install it simply by copying over its lib directory.

      Hi,

      I think I am going to make test with th ling to perlipc. the main idea was to make one script to configure several builders according the builders (maybe more in the futur) following by the IP adress

      Cisco 172.22.99.254 ... Extreme Networks 172.29.24.239 ... HP 172.28.127.245 ... Symbol Technologies, Inc. 10.150.238.1

      for each, check if the symbole is > or # at the prompt and send lines for specifics builders.

        I think I am going to make test with th ling to perlipc.

        IPC can be tricky, especially interactive communication with processes on remote machines, as you seem to want to do. Let me put my advice a different way: I suspect the time you spend on getting the appropriate modules installed will be less than the time necessary to re-invent the IPC wheel.

Re: SSH and expect without module
by thanos1983 (Parson) on Mar 15, 2017 at 15:56 UTC

    Hello touriste75,

    I would start with (How To Configure SSH Key-Based Authentication on a Linux Server).

    Update: Forgot to say, by using SSH-keys you don't need to enter a password to connect to your remote host. Really you should do this even if you can use Perl modules.

    As a second step a few days ago another Monk asked similar question, and he post a piece of code that seems to be working according to him (untested by me). Find more about it here (SSH and qx).

    From the similar question (SSH and qx) as salva the author of Net::OpenSSH suggested: Net::OpenSSH is a pure Perl module. You just have to copy everything in the lib directory from the module distribution into some directory in the machine and add that directory into @INC to get it working..

    Update2: In the past I had similar problems I tested any possible way of ssh, telnet modules that I could find. Take a look with working codes examples Best module to execute administrator commands on external operating systems (Linux).

    Recently also another monk was asking for something similar (been able to SSH to multiple nodes). I created a working example for him with Net::OpenSSH::Parallel and the example is multiple machines disk space alert.

    Similarly if you want to execute also SUDO commands, including example with working code Net::OpenSSH::Parallel with sudo commands.

    Hope this helps, maybe to have another approach to your problem.

    Seeking for Perl wisdom...on the process of learning...not there...yet!

      The Monks here were kind enough to help me get Net::OpenSSH installed on an older system where updates were, uh, problematic. But I was further stymied by the age of the underlying ssh client, which was incompatible. So I offer the following:

      sub ops_do_ssh_qx { my ($cmd) = @_; $cmd->{ssh_cmd} = 'ssh ' . $cmd->{user} . '\@' . $cmd->{host} . ' +\'' . $cmd->{command} . '\'' . ' 2>/dev/null'; $cmd->{output} = qx($cmd->{ssh_cmd}); if ( defined $cmd->{output} ) { $cmd->{cmd_ret_code} = $?; chomp $cmd->{output}; } else { ($cmd->{ssh_ret_code}, $cmd->{ssh_ret_msg}) = (0 + $!, '' . $!); } return $cmd; }

      It does rely on ssh keys being setup properly.

      I hope you find it useful.

      Thanks,
      cbeckley

Re: SSH and expect without module
by shmem (Chancellor) on Mar 15, 2017 at 17:51 UTC
    my goal is to connect in SSH to several material and without the result in STDOUT, pass in console some command.

    It is even more simple than what you tried. Sample transcript:

    qwurx [shmem] ~> perl -e 'open my $fh,"|-","ssh localhost"; while(<STD +IN>){print $fh $_}' Pseudo-terminal will not be allocated because stdin is not a terminal. The programs included with the Debian GNU/Linux system are free softwa +re; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. You have new mail. touch blorflydick <--- input at terminal touch gobbledygook <--- input at terminal ^D <--- input at terminal (Ctrl-D or eof) qwurx [shmem] ~> ls -lrt | tail -2 <--- after perl terminated -rw-r--r-- 1 shmem shmem 0 Mar 15 18:30 blorflydick -rw-r--r-- 1 shmem shmem 0 Mar 15 18:30 gobbledygook

    No modules required. If you just want to pass some commands and don't care about STDOUT/STDERR, all you have to do is a plain piped open. If you want to multiplex the commands to several hosts, store the filehandles in an array and print your input to the remote shells in a loop (untested):

    my @fh; for my $ip (@ips) { open my $fh,"|-","ssh $ip" or die "Can't ssh to $ip: $!\n"; push @fh, $fh; } while (<STDIN>) { for my $fh (@fh) { print $fh $_; } }

    You might, since you are not interested in STDOUT/STDERR, redirect all output within the piped open to avoid funny blocking errors and/or spamming your terminal:

    open my $fh,"|-","ssh $ip >/dev/null 2>&1" or die "Can't ssh to $i +p: $!\n";

    and/or set $|=1 (see perlvar) and/or call $fh->autoflush on every handle created. Finding out the difference between these measures is left as an excercise to the reader.

    update: the ssh connection in this example was established using ssh keys and a running ssh-agent. If you have to enter (different) credentials you want to set $fh->autoflush and use sshpass to pass the passwords (for each connection).

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: SSH and expect without module
by salva (Canon) on Mar 15, 2017 at 18:48 UTC
    If you want to do password authentication, then you need Expect or the lower level IO::Pty installed, or some helper command as sshpass or a SSH client as plink which accepts the password as a command line argument.

    The issue is that ssh doesn't read the password from STDIN but directly from the tty and Perl doesn't offer a way to manipulate ttys/ptys without using some non core module.