#!/usr/bin/perl # expect_pw_changer.pl # Meryll Larkin # November 3, 2021 use strict; # for name of outfile use POSIX qw(strftime); use Net::SSH::Expect; # for hidden password use Term::ReadKey; # for "copy" for .ssh/authorized_keys use File::Copy; # flush buffer to output so all is not lost if # you need to cancel script before it finishes $| = 1; my $pid = $$; my $today = strftime "%Y%m%d",localtime; # my $timeout1 = '10'; my $timeout1 = '5'; # my $timeout2 = '5'; my $timeout2 = '3'; my @commands; my $response; print "\n Welcome to Expect Password Changer!\n"; print qq| Use this program to login to remote computers and change your user password|; print "\n"; print qq| You will be asked to provide: 1. your login password on the command line, 2. a file with a list of remote computers (hosts) for password change. |; chomp(my $ssh_keyfile = $ENV{"HOME"}); # if ssh_keyfile ends in a slash, remove final slash $ssh_keyfile =~ s/\/$//; $ssh_keyfile .= '/.ssh/authorized_keys'; my $restore_authorized_keys = 0; my $ssh_keyfile_save = ${ssh_keyfile} . "_save_" . $today . '_' . $pid; # If an authorized_keys file exists in the .ssh folder ask user if he/she # wants to move it. if ( -e $ssh_keyfile ) { print "\n Move ssh authorized_keys? Expect requires use of passwords. (Y/n) "; chomp ($response = ); if ($response !~ /^\s*n/i ) { $restore_authorized_keys = 1; move($ssh_keyfile, $ssh_keyfile_save); if ( -e $ssh_keyfile_save ) { print " $ssh_keyfile moved to $ssh_keyfile_save\n"; print " It will be restored at end of script\n\n"; } else { print " ERROR while trying to move $ssh_keyfile\n"; } } } my @junk; my $user; my $pwd; my $newpwd; my $unique_pwd_boo = 0; ($user, $pwd) = &get_login("current",$user,$pwd); my $command = "passwd"; print "Will you use the same NEW password for each host or will there be unique passwords? [SAME/unique] "; chomp ($response = ); if ($response =~ /^\s*u/i) { $unique_pwd_boo = 1; &display_file_example; } else { ($user, $newpwd) = &get_login("new",$user,$pwd); } my $infile = &get_filename("input - host list", $unique_pwd_boo); chomp $infile; my $outfile = "expect_pw_${today}_${pid}" . '.log'; open (INPUT, $infile) || die "Unable to open $infile " . $! . "\n"; open (OUTPUT, ">>$outfile") || die "Unable to open $outfile " . $! . "\n"; my $who = ' whoami '; while () { chomp (my $line = $_); # ignore lines that begin with comment character next if ($line =~ /^\s*#/); # ignore empty lines next if ($line !~ /\w/); my $hozt; if ( $unique_pwd_boo ) { ($hozt, $newpwd, @junk) = split('\s+',$line); } else { ($hozt, @junk) = split('\s+',$line); } print "\n************************************"; print "\n************************************\n\n"; print " Working on $hozt\n"; print "\n-------------------------------\n\n"; print OUTPUT "\n\n*************\n$hozt\n-----------\n"; my $login_output; my $ssh = Net::SSH::Expect->new ( host => $hozt, password => $pwd, user => $user, raw_pty => 1, timeout => $timeout1 ); eval { $login_output = $ssh->login($timeout2); } or do { print OUTPUT "login failed\n\n"; print " login failed on $hozt\n\n"; next; }; $ssh->exec("stty raw -echo"); # https://metacpan.org/dist/Net-SSH-Expect/view/lib/Net/SSH/Expect.pod $ssh->send( $command); $ssh->waitfor('password:\s*\z', 3) or die "prompt 'password' not found after 1 second"; $ssh->send($pwd); $ssh->waitfor(':\s*\z', 3) or die "prompt 'New password:' not found"; $ssh->send($newpwd); $ssh->waitfor(':\s*\z', 3) or die "prompt 'Confirm new password:' not found"; $ssh->send($newpwd); print "Result of command \'$command\'\n"; print OUTPUT "$command\n"; my $line; # returns the next line, removing it from the input stream: while ( defined ($line = $ssh->read_line()) ) { print $line . "\n"; print OUTPUT $line . "\n"; } $ssh->close(); } close INPUT; if ($unique_pwd_boo) { print "Do you want to delete $infile, which contains passwords? [Y|n] "; chomp ($response = ); if ($response !~ /^\s*n/i ) { unlink $infile; print " Input file $infile deleted\n"; } } close OUTPUT; if ($restore_authorized_keys) { move($ssh_keyfile_save, $ssh_keyfile); if ( -e $ssh_keyfile ) { print " $ssh_keyfile file restored.\n\n"; } else { print " ERROR while trying to restore $ssh_keyfile\n"; } } print "\n Also see results in $outfile\n\n"; exit (0); # ********************************* sub get_filename { my ($filetype, $unique_pwd_boo) = @_; if ($unique_pwd_boo) { print " What is the (path and) filename for the $filetype file with unique password key-value pairs? "; } else { print " What is the (path and) filename for the $filetype file? "; } my $filename = ; return $filename; } # ********************************* sub get_login { my ($type,$user,$pwd1) = @_; if ($user eq "NULL") { print " Username for $type: "; chomp ($user = ); } print " Hidden $type password: "; ReadMode('noecho'); # don't echo chomp (my $pwd = ); ReadMode(0); # back to normal if ($pwd !~ /\w/) { $pwd = $pwd1; } print "\n"; return ($user,$pwd); } # ********************************* sub display_file_example { print "\n"; print qq| * For unique NEW passwords, you will need to create a file with key-value pairs. The first word will be the host name or ip address. Then a space. The second word will be your new password. # host_name_or_ip new_password localhost thisIsMyPWD 127.0.0.1 thisIsMy936 |; print "\n"; } # *********************************