#!/usr/bin/expect -f # # change_pass - Log into posix-like network # devices like Cyclades or NetApp filers and # update the root passwords in batch. Password # is accepted from STDIN for security reasons # # USAGE: # change_pass host1 user@host2 otheruser@host3 ... # # Working: # - Cyclades # - Sun ILOMS # - NetApp Filers (needs more testing) # Future: # - RSA Cards # - Ingrians # Broken: # - IBM Blade Chasis set the max pass length to # 8 and min pass to 3. Don't use this on them! # #$Id: change_pass 11233 2007-02-01 00:43:37Z jschroeder $ set old_pass "" set prompt "(# \$|\w+\d+\>|->)" proc get_password {} { global old_pass # Disable password echoing and wait for input fconfigure stdin -blocking 1 stty -echo # Only used when key based auth doesn't work puts -nonewline stdout "Old Password: " flush stdout set old_pass [gets stdin] puts "\r" set pass 0 set passvrfy 1 while {"$pass" != "$passvrfy"} { puts -nonewline stdout "New Password: " flush stdout set pass [gets stdin] puts "\r" puts -nonewline stdout "Re-type Password: " flush stdout set passvrfy [gets stdin] puts "\r" if {"$pass" != "$passvrfy"} { puts stderr "ERROR: Passwords do not match\n" } if {"$pass" == "" || "$pass" == "ticketmaster"} { puts stderr "ERROR: No cookie! NOT YOURS! Try again\n" set pass 0 set passvrfy 1 } } fconfigure stdin -blocking 0 stty echo return $pass } proc change_password {passwd hostname} { global status {} global prompt set pass_changed 0 send "passwd\r" # Initial password change prompt expect { # Anything Linux including Cyclades -reg "\[Nn]ew (UNIX |)password:" {} # NetApp Filers -reg "Login:" { send "root\r" expect "New password:" } # Sun ILOM root account -reg "->" { send "set /SP/users/root password\r" expect "Enter new password:" } } send "$passwd\r" # Secondary password change prompt expect { -reg "new (UNIX |)password(:| again:)" {} } send "$passwd\r" # Password change success prompt expect { # Cyclade -reg "Password changed" { set status($hostname) ok } # Redhat and Debian have different pam success messages -reg "passwd:.*successfully" { set status($hostname) ok } # NetApp Filers -reg "passwd for user 'root' changed." { set status($hostname) ok } # Sun ILOM root account -reg "New password was successfully set for user /SP/users/root" { set status($hostname) ok } } expect -reg "$prompt" send "exit\r" } proc show_final_status {} { global status {} puts "\r--------------------------------------------------------------------------------\r" foreach machine [array names status] { switch "$status($machine)" { ok { puts "$machine password changed successfully.\r" } manual { puts stderr "WARNING: $machine password was manually changed, this might be incorrect!\r" } invalid { puts stderr "ERROR: could not connect to $machine!\r" } denied { puts stderr "ERROR: permission denied to $machine!\r" } default { puts stderr "WARNING: $machine password not changed!\r" } } } puts "\r--------------------------------------------------------------------------------\r" } # Main program starts here global argv global old_pass global status {} # Open ssh connections in parallel for super mega ultra speed foreach host $argv { set timeout 20 set user root # Set the correct username if user@host is specified if [string match {*@*} $host] { regexp {(\w+)@(.*)} $host arg user host unset arg } spawn -noecho ssh -l $user $host set hosts($host) $spawn_id } set new_pass [get_password] foreach session [array names hosts] { set spawn_id $hosts($session) expect { -reg "Name or service not known" { set status($session) invalid } -reg "No route to host" { set status($session) invalid } -reg "Permission denied\[^\n]*\n" { puts stderr "$expect_out(buffer)\n" set status($session) denied } -reg "Connection closed by foreign host.\[^\n]*\n" { puts stderr "$expect_out(buffer)\n" set status($session) invalid } -reg "The authenticity of host \[^\n]+\n" { exp_continue } -reg "Are you sure you want to continue connecting \[^\n]+" { send "yes\r" exp_continue } -reg "\[pP]assword: " { # Use the old password if key based authentication doesn't work. # If the old password is wrong, switch to interactive mode. # 1.) Login # 2.) Manually change the password # 3.) Logout and control will be returned to this script set status($session) manual send "$old_pass\r" expect { -reg "$prompt" { change_password $new_pass $session } -reg "\[pP]assword: " { interact } } } # Authentication successful! -reg "$prompt" { change_password $new_pass $session } timeout { set status($session) invalid } eof { # also used for lines starting with a "@@@@@@@@@" lines like # @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ # @ YOUR SYSTEM HAS BEEN HAXORED RUN WHILE YOU STILL CAN! @ puts stderr "\rERROR: EOF found <$expect_out(buffer)>" exit 1 } } } show_final_status