Subject: | ssh(1) does not require a username |
Date: | Mon, 04 Jul 2016 15:03:38 +0300 |
To: | bug-Net-SSH-Expect [...] rt.cpan.org, bnegrao [...] cpan.org |
From: | chohag [...] jtan.com |
ssh has its own default username, or obtains it from ~/.ssh/config,
which process Net::SSH::Expect overrides. The attached patch allows the
ssh calculation to still take place if a user is not provided and
hopefully handles correctly the case where a username is prompted for.
diff -ur perl5-Net::SSH::Expect.orig/lib/Net/SSH/Expect.pm perl5-Net::SSH::Expect/lib/Net/SSH/Expect.pm
--- perl5-Net::SSH::Expect.orig/lib/Net/SSH/Expect.pm Wed Apr 23 05:18:13 2008
+++ perl5-Net::SSH::Expect/lib/Net/SSH/Expect.pm Mon Jul 4 13:19:49 2016
@@ -28,8 +28,8 @@
my Net::SSH::Expect $self = fields::new(ref $type || $type);
# Options used to configure the SSH command
- $self->{host} = $args{host}|| undef;
- $self->{user} = $args{user} || $ENV{'USER'};
+ $self->{host} = $args{host} || undef;
+ $self->{user} = $args{user} || undef;
$self->{password} = $args{password} || undef;
$self->{port} = $args{port} || undef; # ssh -p
$self->{no_terminal} = $args{no_terminal} || 0; # ssh -T
@@ -73,14 +73,14 @@
# 2) Define the ssh command line using the defaults and user-defined settings
# 3) Fork the ssh process using the spawn() method of the Expect instance we created.
# The SSH connection is established on this step using the user account set in the 'user'
-# constructor attribute. No password is sent here, that happens only in the login() method.
+# constructor attribute or relying on ssh(1)'s default. No password is sent here, that
+# happens only in the login() method.
#
# This method is run internally by the login() method so you don't need to run it yourself
# in most of the cases. You'll run this method alone if you had set up public-key authentication
# between the ssh client and the ssh server. In this case you only need to call this method
# to have an authenticated ssh connection, you won't call login(). Note that when you
-# use public-key authentication you won't need to set the 'password' constructor attribute
-# but you still need to define the 'user' attribute.
+# use public-key authentication you won't need to set the 'password' constructor attribute.
# If you don't know how to setup public-key authentication there's a good guide at
# http://sial.org/howto/openssh/publickey-auth/
#
@@ -93,7 +93,6 @@
my $host = $self->{host};
croak(ILLEGAL_STATE . " field 'host' is not set.") unless $host;
- croak(ILLEGAL_STATE . " field 'user' is not set.") unless $user;
my $log_file = $self->{log_file};
my $log_stdout = $self->{log_stdout};
@@ -114,7 +113,9 @@
$flags .= $ssh_option if $ssh_option;
# this sets the ssh command line
- my $ssh_string = $self->{binary} . " $flags $user\@$host";
+ my $ssh_string = $self->{binary} . " $flags ";
+ $ssh_string .= "$user\@" if $user;
+ $ssh_string .= $host;
# creating the Expect object
my $exp = new Expect();
@@ -165,7 +166,7 @@
# welcome message and/or the remote prompt. You could use this string to do your verification
# that the login was successful. The content returned is removed from the input stream.
# dies:
-# IllegalState: if any of 'host' or 'user' or 'password' fields are unset.
+# IllegalState: if 'host' or 'password' fields are unset.
# SSHProccessError: if run_ssh() failed to spawn the ssh process
# SSHConnectionError: if the connection failed for some reason, like invalid 'host' address or network problems.
sub login {
@@ -188,7 +189,6 @@
my $timeout = $self->{timeout};
my $t = $self->{terminator};
- croak(ILLEGAL_STATE . " field 'user' is not set.") unless $user;
croak(ILLEGAL_STATE . " field 'password' is not set.") unless $password;
# spawns the ssh process if this wasn't done yet
@@ -202,7 +202,17 @@
$self->_sec_expect($timeout,
[ qr/\(yes\/no\)\?\s*$/ => sub { $exp->send("yes$t"); exp_continue; } ],
[ $password_prompt => sub { $exp->send("$password$t"); } ],
- [ $login_prompt => sub { $exp->send("$user$t"); exp_continue; } ],
+ [ $login_prompt => sub {
+ if (not $user) {
+ $user = $self->user($ENV{'USER'});
+ if ($user) {
+ warn "Login prompt detected and 'user' field is not set; using $user from \$USER.";
+ } else {
+ die "Login prompt detected and 'user' field is not set";
+ }
+ }
+ $exp->send("$user$t"); exp_continue;
+ } ],
[ qr/REMOTE HOST IDEN/ => sub { print "FIX: .ssh/known_hosts\n"; exp_continue; } ],
[ timeout => sub
{
diff -ur perl5-Net::SSH::Expect.orig/lib/Net/SSH/Expect.pod perl5-Net::SSH::Expect/lib/Net/SSH/Expect.pod
--- perl5-Net::SSH::Expect.orig/lib/Net/SSH/Expect.pod Wed Apr 23 05:18:17 2008
+++ perl5-Net::SSH::Expect/lib/Net/SSH/Expect.pod Mon Jul 4 13:22:37 2016
@@ -103,7 +103,8 @@
This module is a wrapper to the I<ssh> executable that is available in your system's I<$PATH>.
Use this module to execute commands on the remote SSH server.
It authenticates with the user and password you passed in the constructor's attributes
-C<user> and C<password>.
+C<user> and C<password>. If C<user> is not supplied it relies on ssh providing the default unless
+it detects a login prompt, in which case it falls back to the $USER environment variable.
Once an ssh connection was started using the C<connect()> method it will remain open
until you call the C<close()> method. This allows you execute as many commands as you want
@@ -298,14 +299,14 @@
# 2) Define the ssh command line using the defaults and user-defined settings
# 3) Fork the ssh process using the spawn() method of the Expect instance we created.
# The SSH connection is established on this step using the user account set in the 'user'
- # constructor attribute. No password is sent here, that happens only in the login() method.
+ # constructor attribute or relying on ssh(1)'s default. No password is sent here, that
+ # happens only in the login() method.
#
# This method is run internally by the login() method so you don't need to run it yourself
# in most of the cases. You'll run this method alone if you had set up public-key authentication
# between the ssh client and the ssh server. In this case you only need to call this method
# to have an authenticated ssh connection, you won't call login(). Note that when you
- # use public-key authentication you won't need to set the 'password' constructor attribute
- # but you still need to define the 'user' attribute.
+ # use public-key authentication you won't need to set the 'password' constructor attribute.
# If you don't know how to setup public-key authentication there's a good guide at
# http://sial.org/howto/openssh/publickey-auth/
#
@@ -346,7 +347,7 @@
# welcome message and/or the remote prompt. You could use this string to do your verification
# that the login was successful. The content returned is removed from the input stream.
# dies:
- # IllegalState: if any of 'host' or 'user' or 'password' fields are unset.
+ # IllegalState: if 'host' or 'password' fields are unset.
# SSHProccessError: if run_ssh() failed to spawn the ssh process
# SSHConnectionError: if the connection failed for some reason, like invalid 'host' address or network problems.