1

I'm trying to create an expect script to update a user's password non-interactively. New to expect and shell scripting. I want to be able to capture and handle errors encountered. For example, if I'm running passwd normally, and my new password isn't acceptable for some reason, I might see a message like "BAD PASSWORD: The password is too similar to the old one". The problem is that, in the expect script, after send $new_pswd\r with an invalid password, expect "BAD PASSWORD:*" is failing because the next output from passwd is " ". I would like to capture the bad passwords and the message so that I can return those to the calling process. The use case here is to allow individual users who may have multiple accounts to update all their accounts with the same password in one go. This script would be called once for each account.

#!/usr/bin/expect -df

# THIS SCRIPT WON'T WORK
set old_pswd $::env(PSWD1)
set new_pswd $::env(PSWD2)

spawn passwd
expect "*ssword:" { send "$old_pswd\r" }
expect "*ssword:" { send "$new_pswd\r" }
expect {
        "*ssword:" {
                puts "Expected\r"
                send "$new_pswd\r"
                exit 0
        }
        "BAD PASSWORD:*" {
                puts "BAD PASSWORD\r"
                send \x03
                exit 1
        }
        "*" {
                puts "Unexpected\r"
                send \x03
                puts $expect_out(buffer)
                exit 1
                }
        }
Scooter
  • 11
  • 2

1 Answers1

0

UPDATE: I learned a lot about expect since yesterday and wound up solving the problem and a couple others in the script.

The first problem was that I was expecting the password prompt without a space after the colon, so all subsequent expect commands were trying to match against the as-yet-unconsumed space character, which matched against "*", and terminated the script before passwd ever sent its BAD PASSWORD message.

The second problem was trying to match *ssword: before "BAD PASSWORD". The prompt for new password would always match before the BAD PASSWORD message, because passwd was sending "BAD PASSWORD: message message message\r\nNew password: "

Here is a script that now works and is wrapped in an su. Whatever process is calling this script needs to clean up the environment variables afterward. The idea would be to set those securely in advance so that credentials don't have to be passed on command lines. This script is intended to be called from the user's account once for each other account that belonged to them:

#!/usr/bin/expect -f

# THIS SCRIPT WORKS
set old_pswd $::env(PSWD1)
set new_pswd $::env(PSWD2)
set new_user $::env(USER1)

spawn su $new_user
expect "*ssword: " { send "$old_pswd\r" }

expect "$ " { send "passwd\r" }
expect "*ssword: " { send "$old_pswd\r" }
expect "*ssword: " { send "$new_pswd\r" }

expect {
        "BAD PASSWORD: " {
                expect {
                        "dictionary"    { set exit_code 1 }
                        "shorter than"  { set exit_code 2 }
                        "too similar"   { set exit_code 3 }
                        "No password"   { set exit_code 4 }
                        "*"             { set exit_code 99 }
                }
                send \x03
                expect "$ " { send "exit\r" }
                exit $exit_code
        }
        "*ssword: " {
                send "$new_pswd\r"
                expect "$ " { send "exit\r" }
                exit 0
        }
}
Scooter
  • 11
  • 2