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

Greetings, Brothers!

I have no doubt my lack of Linux knowledge is seriously hampering me in my attempts to automate checking for sudo access on remote machines--any help would be greatly appreciated!

Basically, the idea is that if I have the current user password, that is success, and if not I want to drop into interactive mode to set it correctly (I won't bore you with the grisly why's and wherefores)

I have a simple method that attempts to do this:

sub checksudo { my ($ssh, $ip, $pass) = @_; #$ssh is the successfully created openssh +object, $pass is the user's sudo password my $system = $ssh->system ('sudo -K') or return "failed to sudo -K: $! +\n"; #ensure we are prompted for a password my ( $pty, $pid ) = $ssh->open2pty( "sudo -p 'configtest:' bash 2>&1") or return "failed to attempt sudo bash: $!\n"; my $expect = Expect->init($pty); #sleep 1; #$expect->send ($pass . "\n"); $expect->expect(2, [ qr/configtest:/ => sub { my $expect =shift; $expect->send($p +ass . "\n"); exp_continue;} ], [ qr/Sorry/ => sub { my $expect=shift; print "Failed\n"; e +xp_continue; } ], ); #$expect->interact(); return; }
The above code gives me:
tcsetattr: Input/output error
If I comment out the first array ref in the $expect->expect() statement, I get:
tcsetattr: Input/output error channel 0: chan_read_failed for istate 1
However, if I remove the $expect->expect() statement entirely and uncomment the $expect->send() statement which just sends the password, I get successful sudo's on the remote machine. Likewise if I only have the $expect->interact() statement in place, that works just fine, too.

I have to think I'm fundamentally misunderstanding something--any input would be greatly appreciated!

updateEven when things seem to go fine, it seems that I still get the I/O errors when I try to execute another remote ssh command. The command succeeds but when that error at the top. I can't seem in the docs for Net::OpenSSH how to kill a particular child connection, which I'm guessing is what I need to do?

Replies are listed 'Best First'.
Re: Losing my mind with Net::OpenSSH and Expect
by salva (Canon) on Feb 28, 2011 at 08:55 UTC
    The following script works for me:
    #!/usr/bin/perl use strict; use warnings; use Net::OpenSSH; use Expect; my $host = $ARGV[0]; my $pass1 = $ARGV[1]; my $pass2 = $ARGV[2]; my $ssh = Net::OpenSSH->new($host, passwd => $pass1); $ssh->error and die "unable to connect to remote host: " . $ssh->error +; my ( $pty, $pid ) = $ssh->open2pty("sudo -kp 'configtest:' bash 2>&1") or return "failed to attempt sudo bash: $!\n"; my $expect = Expect->init($pty); $expect->expect(2, [ qr/configtest:/ => sub { my $expect =shift; $expect->send($p +ass2 . "\n"); exp_continue;} ], [ qr/Sorry/ => sub { my $expect=shift; print "Failed\n"; e +xp_continue; } ], ); $expect->interact();
    Can you try it?

    Which OpenSSH version and OS are you using?

      Hi Salva,

      Thanks for the response. When I did it just as you said, I got:

      fcntl returned undef during exp_init of Expect=GLOB(0x97b1760), Bad fi +le descriptor
      I had had issues trying to include the -k in the sudo command, so I made it a separate $ssh->system() call, and it does seem to work except that I have to hit Enter for it to go into interactive mode. Sounds trivial, I know, but I'm hitting rather a lot of machines.

      If I get rid of exp_continue after sending the password, it goes straightaway. Unfortunately, if it fails it doesn't catch the "Sorry", and just prompts me for a password. So it's a catch-22.

      I'll be darned if I can detect a substantive difference between your code and mine, too, beyond what I've mentioned!

      I'm on Ubuntu 10 and OpenSSH:
      OpenSSH_5.5p1 Debian-4ubuntu5, OpenSSL 0.9.8o 01 Jun 2010

        For clarity, when I moved the -k out of the open2pty call, I got rid of the new error message. So it's interesting that you didn't have that issue.