Reputation: 1
first time caller, long time listener, I have a question centering around an expect script and changing the password on several hosts. I do not have any issue getting the expect script to rotate or change the password, the issue i am having is the expects scripts ability to handle multiple 'expects'. I need to account for 4 things, our environment is borked and dumb - please bear with me.
My script is looping through a list of hosts and logging in, I want it to do one of a few things -- when it logs in, if the account is expired it will expect certain things and change the password, this works. If this does not come up and the script logs in fine with the old password, just execute the passwd command and change password. THe problem I am having right now is getting the two things to work together correctly.
If the host list contains a mix, where the account is expired and in good standing I want to be able to loop through and handle each situation appropriately then log it. Right now, if i put in some test hosts (4 to 5) where the account is expired and fine, the script works if the last hosts are expired. But will not work if the first host is expired then has to move to a new host.
Here is the code below, I have scoured the internet for knowledge and nothing matching this has come up.
I want to be able to say, if the expect value == (current UNIX password) then do this, if the old password is being used go ahead and change to new password...really struggling to get it working together.
#!/usr/bin/expect
set timeout 10
set user userAccount
set password oldPassword
set new_password newPassword
set f [open "input.txt"]
set hosts [read $f]
close $f
## need to say if the expected value is "(current) UNIX password: then do this"
foreach host $hosts {
spawn -noecho /bin/ssh -q -o StrictHostKeychecking=no "$user\@$host"
expect "Password:"
send "$password\r"
expect {
"(current) UNIX password:" {send $password\r; exp_continue}
"New password:" {send $new_password\r; exp_continue}
"Retype new password:" {send $new_password\r; exp_continue}
"~]$" {close}
}
send "echo -e '$password\n$new_password\n$new_password' | passwd\r"
expect "~]$" {close}
}
Upvotes: 0
Views: 4017
Reputation: 4813
I suspect the easiest solution is to make a small change to your first expect command:
expect {
"(current) UNIX password:" {send $password\r; exp_continue}
"New password:" {send $new_password\r; exp_continue}
"Retype new password:" {send $new_password\r}
"~]$" {send "echo -e '$password\n$new_password\n$new_password' | passwd\r"}
}
expect "~]$" {close}
The crucial part is that there's no exp_continue after the second time you send the new password. It will then break out of the first expect command and only match the prompt of the second expect command. If the password hasn't expired, the prompt inside the first expect command will be found. So that's where you can run the passwd command.
With your other wishes added, the loop body could look something like this:
spawn -noecho /bin/ssh -q -o StrictHostKeychecking=no "$user\@$host"
expect "assword: "
send "$password\r"
expect {
-timeout 30
"(current) UNIX password: " {
# Password has expired
send $password\r
expect {
"New password: " {
send $new_password\r
exp_continue
}
"Retype new password: " {
send $new_password\r
exp_continue
}
"all authentication tokens updated successfully." {
# Password has been changed
}
default {
error "Failed to change the password"
}
}
}
"assword: " {
# Old password was not accepted
send $new_password\r
expect {
-timeout 30
-ex "~]$" {
# New password was accepted
}
"assword: " {
# New password was not accepted either
error "None of the passwords was accepted"
}
default {
error "Failed to log in"
}
}
}
"locked" {
# Account is locked
}
-ex "~]$" {
# Logged in with old password
send "echo -e '$password\n$new_password\n$new_password' | passwd\r"
expect {
-ex "~]$" {
# Password successfully updated
}
default {
error "passwd command failed"
}
}
}
default {
error "Log in timed out"
}
}
close
That would be the basic structure. If it doesn't quite work, add an exp_internal 1
command to determine which tweaks would be needed.
Upvotes: 1