Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Changing passwords using Expect.pm through ssh on a large number (75) of systems

by linebacker (Scribe)
on Jul 11, 2002 at 18:43 UTC ( #181105=perlquestion: print w/replies, xml ) Need Help??

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

Following the example on the Expect.pm POD, I thought I was on the right track. However, when this script gets to line 46, the command passwd seems to be printed several times over and over and over again on the target machine. Ideas?
1 #!/usr/bin/perl -w 2 use strict; 3 use Expect; 4 5 my $timeout = '5'; 6 my $username = 'luser'; 7 my $newpass = '0ldp@sswd!'; 8 my $oldpass = 'n4p@sswd!'; 9 10 open(HOSTS,"hosts.txt") 11 or die "Error while opening file:$!\n"; 12 chomp( my @hosts = <HOSTS> ); 13 close(HOSTS) 14 or die "Error while closing file:$!\n"; 15 foreach my $newhost (@hosts) { 16 my $exp = Expect->spawn("ssh -l $username $newhost") 17 or die "Cannot spawn ssh: $!\n";; 18 my $spawn_ok; 19 # $exp->exp_internal(1); 20 $exp->expect($timeout, 21 [ 22 'password: $', 23 sub { 24 my $fh = shift; 25 print $fh "$oldpass\n"; 26 exp_continue; 27 } 28 ], 29 [ 30 "$username\]", 31 sub { 32 my $fh = shift; 33 print $fh "passwd\n"; 34 exp_continue; 35 } 36 ], 37 [ 38 'password:', 39 sub { 40 my $fh = shift; 41 print $fh "$oldpass\n"; 42 $timeout, 43 exp_continue; 44 } 45 ], 46 [ 47 'password:', 48 sub { 49 my $fh = shift; 50 print $fh "$newpass\n"; 51 exp_continue; 52 } 53 ], 54 [ 55 'password:', 56 sub { 57 my $fh = shift; 58 print $fh "$newpass\n"; 59 exp_continue; 60 } 61 ], 62 [ 63 eof => 64 sub { 65 if ($spawn_ok) { 66 die "ERROR: premature EOF in login.\n"; 67 } else { 68 die "ERROR: could not spawn ssh.\n"; 69 } 70 } 71 ], 72 [ 73 timeout => 74 sub { 75 die "Timeout.\n"; 76 } 77 ], 78 '-re', qr'[#>:] $', #' wait for shell prompt, t +hen exit expect 79 ); 80 }
  • Comment on Changing passwords using Expect.pm through ssh on a large number (75) of systems
  • Download Code

Replies are listed 'Best First'.
Re: Changing passwords using Expect.pm through ssh on a large number (75) of systems
by ferrency (Deacon) on Jul 11, 2002 at 18:55 UTC
    This doesn't answer your question, but it might solve your problem:

    You might want to see if your system has a chpass or pw command. chpass lets you change an account's password by specifying an encrypted password on the command line, which would alleviate your need for passwd completely.

    However, because the encrypted password is specified on the command line, be aware that it may show up on your system's process list. It may not be a good idea to do this on a system with untrusted users, if those users are allowed to get info about processes they don't own. In this case, your method would be better, but unfortunately I don't have enough experience with the Expect module to help you very much :)

    Alan

Re: Changing passwords using Expect.pm through ssh on a large number (75) of systems
by sschneid (Deacon) on Jul 11, 2002 at 19:24 UTC
    I would suggest performing multiple expects, as opposed to doing multi-pattern matching. Consider:
    my $exp; foreach (@hosts) { $exp = Expect->spawn("ssh -l $username $_") or die "Cannot spawn ssh: $!\n"; do_exp ($timeout, 'password $', $oldpass); do_exp ($timeout, "$username\]", 'passwd'); do_exp ($timeout, 'password:', $oldpass); do_exp ($timeout, 'password:', $newpass); do_exp ($timeout, 'password:', $newpass); } sub do_exp { my ($_timeout, $_lookfor, $_send) = @_; if ($exp->expect($_timeout, $_lookfor)) { $exp->send($_send); } else { die "Timeout waiting for $_lookfor.\n"; } }
    This way your script will look for the patterns in order as opposed to getting confused as to when to send what (especially since three of the patterns you're trying to match are exactly the same). If you want to change the pattern matching from string to regex, you only need to change the following in the do_exp sub:
    if ($exp->expect($_timeout, $_lookfor)) {
    to:
    if ($exp->expect($_timeout,'-re',$_lookfor)) {


    One final suggestion: I'd try to match "Old password:" and "New password:" instead of just "password:".

    Hope it helps,
    scott.
      I modified per your recommendation:
      #!/usr/bin/perl -w use strict; use Expect; my $timeout = '5'; my $username = 'luser'; my $newpass = 'luser'; my $oldpass = 'n3wp@ss!'; open(HOSTS,"hosts.txt") or die "Error while opening file:$!\n"; chomp( my @hosts = <HOSTS> ); close(HOSTS) or die "Error while closing file:$!\n"; my $exp; foreach (@hosts) { $exp = Expect->spawn("ssh -l $username $_") or die "Cannot spawn ssh: $!\n";; my $spawn_ok; #$exp->exp_internal(1); do_exp ($timeout, 'password', $oldpass); do_exp ($timeout, "$username\n", "passwd"); do_exp ($timeout, 'password:', $oldpass); do_exp ($timeout, 'password:', $newpass); do_exp ($timeout, 'password:', $newpass); } sub do_exp { my ($_timeout, $_lookfor, $_send) = @_; if ($exp->expect($_timeout,'-re',$_lookfor)) { $exp->send($_send); } else { die "Timeout waiting for $_lookfor.\n"; } }

      but am still having problems.
      I show the output with verbose debugging turned on below:
      Starting EXPECT pattern matching... Expect::expect('Expect=GLOB(0x835f7e0)', 5, '-re', 'password') cal +led at ./example.pl line 30 main::do_exp(5, 'password', 'n3wp@ss!') called at ./example.pl lin +e 21 spawn id(3): list of patterns: #1: -re `password' spawn id(3): Does `' match: pattern #1: -re `password'? No. luser@10.10.10.39's password: spawn id(3): Does `luser@10.10.10.39\'s password: ' match: pattern #1: -re `password'? YES!! Before match string: `luser@10.10.10.39\'s ' Match string: `password' After match string: `: ' Matchlist: () Sending 'n3wp@ss!' to spawn id(3) Expect::print('Expect=GLOB(0x835f7e0)', 'n3wp@ss!') called at ./ex +ample.pl line 30 main::do_exp(5, 'password', 'n3wp@ss!') called at ./example.pl lin +e 21 Starting EXPECT pattern matching... Expect::expect('Expect=GLOB(0x835f7e0)', 5, '-re', 'luser^J') call +ed at ./example.pl line 30 main::do_exp(5, 'luser^J', 'passwd') called at ./example.pl line 2 +2 spawn id(3): list of patterns: #1: -re `luser\n' spawn id(3): Does `: ' match: pattern #1: -re `luser\n'? No. n3wp@ss! spawn id(3): Does `: n3wp@ss!' match: pattern #1: -re `luser\n'? No. Timeout waiting for luser

      Without verbose debugging:
      luser@10.10.10.39's password: n3wp@ss!Timeout waiting for luser .
      Thanks again for the assist!
        Sorry, overlooked:
        $exp->send("$_send\n");
        If it's not sent explicitly, Expect doesn't add a return onto the end of the string you're sending. Also, are you sure you want to be matching $username\n? I'm guessing the \n is a typo, somehow...

        I took out the pattern-match statement looking for the ssh password (I'm using keys) and tried the script, and it works for me. Let me know if you're still having trouble...

        scott.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://181105]
Approved by ferrency
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (6)
As of 2019-10-23 23:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Notices?