Looks like no one’s replied in a while. To start the conversation again, simply ask a new question.

Shell Script to set a user password from variables

I have a very unique situation where I need a password set by a shell script. (I am open to other options.) We are currently looking to use a certain encryption software that requires "Power On Authentication". This requires a separate "encryption user account" for the encryption. I will be setting the local user account in OS X to auto login. I have a script to change BOTH passwords, that will run some applescript commands to prompt the user for there old password, then their new password twice, and it verifies the passwords match. It then verifies the old password is valid against the encryption by running a command and checking for a successful exit status, if it is valid it proceeds to change the encryption password based on the variables given in the apple script. I am looking for a way to verify and set the user account password in the process. I have a basic script but I am looking for a little error checking, in that if the passwords are not already the same (the encryption and local account), or at least if the user account password fails to set, that it is echoed.
I can certainly provide the scripts I have if necessary.

A few side notes - I am well aware of the security implications of coding a password into a shell script. That is not what I am doing, I am passing variables from applescript.

This is for doctors who...god forbid...cannot be burdened with having to keep track of separate accounts. (It is kind of a pain in the rear.)

Help is greatly appreciated.

MacBookPro7,1, Mac OS X (10.6.5), Lots of other computers

Posted on Nov 27, 2010 9:07 PM

Reply
23 replies

Nov 28, 2010 11:18 PM in response to BobHarris

BobHarris wrote:
As far as my Expect script...It does seem to run most of the time
as I am running the script as the logged in user and changing the
password for the logged in user. But my biggest concern is that
I get no notice of any kind if the expect script does not change
the password. It just runs like it completed. I am looking for
some way of "error checking" I guess.

You could try using the 'su' command to validate that the password
has been changed as desired:

su $USER -c "exit 0"
if [ $? != 0 ]; then
echo oops
fi

You of course put that into an 'expect' script. The 'su' command will
prompt for the password to $USER. You would provide the new password.

If 'su' works, then $? will be 0. If 'su' fails because the password
was wrong, then $? will be 1.


I get what you mean now, it took me all day, (I guess I got side tracked) but I think I get what you mean. Sorry for the delay, had a few other things going on, and it just wasn't clicking. By using the expect script to su using the provided $OLDPSWRD variable passed through I can continue on from there. If the SU fails then I provide the error, if it succeeds then I move on with the script. I think I would still like to try and get the exit status of the actual passwd command, but that might be asking to much, and maybe not needed.

Thanks again, you have been a great help. Now lets see if I can get it going. I was having some trouble doing anything else in the expect script. Probably something to do with the header maybe? More to come.

Nov 29, 2010 12:01 AM in response to iDam81

I think I have it. I found the following script which will run su against the username and password provided returning an exit code of 0 or 1.

#!/bin/bash
#
# login.sh $USERNAME $PASSWORD
#this script doesn't work if it is run as root, since then we don't have to specify a pw for 'su'
if [ $(id -u) -eq 0 ]; then
echo "This script can't be run as root." 1>&2
exit 1
fi
if [ ! $# -eq 2 ]; then
echo "Wrong Number of Arguments (expected 2, got $#)" 1>&2
exit 1
fi
USERNAME=$1
PASSWORD=$2
#since we use expect inside a bash-script, we have to escape tcl-$.
expect << EOF
spawn su $USERNAME -c "exit"
expect "Password:"
send "$PASSWORD "
#expect eof
set wait_result [wait]
# check if it is an OS error or a return code from our command
# index 2 should be -1 for OS erro, 0 for command return code
if {[lindex $wait_result 2] == 0} {
exit [lindex $wait_result 3]
}
else {
exit 1
}
EOF


I can call this in my first script using the variables provided by the user to verify the username and password are correct. If they are correct, and do in fact match the credentials used to change the SafeGuard account, I can move on to change the OS X account. If they do not match I can provide a detailed error message. I can even go as far as verifying them both before I set either one. Exactly the error checking I was looking for.

I also changed all of my inputs to accept the special characters and that seems to be working great.
Thank you very much.

Nov 29, 2010 7:58 AM in response to iDam81

I'd expect that a solution based on FileVault or pgp would satisfy the auditing requirements.

Also, I am not a security officer. I am a desktop engineer tasked with verifying the encryption that our CTO has defined meets our needs. Full disk encryption and logging.


What might be a statement of the obvious (and without intending any offense), please reflect on whether you want to be left holding the bag if (or when?) this password stuff might go wrong. Your CTO has delegated some of that responsibility to you.

Programming encryption and security in general has a subtle distinction from more mundane programming tasks in that (some) folks are actively trying to breach it; bugs have a different (and sometimes far higher) cost. And some of the attackers are quite clever.

Best to hand this decision and the review to the HIPAA auditors and to the folks that write this security and encryption stuff for a living, and back to your CTO and to the vendor.

If you do deploy with this AppleScript solution, make certain the code here gets reviewed. Just as with medicine itself, the consequences can be nasty: right medicine, right date, right dose, right route, right patient, etc. if you can use a preloaded vendor-provided solution, then you don't have to deal with drawing up the med.

Nov 29, 2010 2:55 PM in response to MrHoffman

First and foremost, my script works. And thank you Bob Harris for assisting me with the actual script.

To those others who offered there opinions and suggestions, I certainly DID take them into account. To the extent that I will not be utilizing the change password script. We are still using Sophos encryption as it meets our needs that I mentioned above. (And the key...we OWN it.) I really do understand and appreciate the posts, but must say I was a bit annoyed when it turned into a battle about standards when the post was about a shell script. Again...I re-iterate, I understand, appreciate, and even took into account some of the information provided...but it was not the topic of my post. I needed help with a shell script.

Maybe it was my fault for using the statement:

{quote}>Also, I am welcome to a whole new solution if anyone can think of something that might work better.
{quote}

I meant a technical/scripting solution, or a simple "you probably shouldn't do that...". I was not asking about evaluating new software. Again that might have been my fault in my wording, so I apologize.

Again, I thank everyone who took their time to even think twice about my post. Everyone seems very talented and helpful. Keep up the good work.

Nov 29, 2010 3:37 PM in response to iDam81

Here is some expect code you can put directly into your main script,
which will tell you if your 'passwd' command worked or failed.

/usr/bin/expect -c "
spawn /usr/bin/passwd
expect word:
sleep 1
send $OLDPSWD0
expect word:
sleep 1
send $PSWD0
expect word:
sleep 1
send $PSWD0
expect {
failure {exit 1}
success {exp_continue}
}
"
if [ $? != 0 ]; then
echo "Oops! passwd failed"
fi

This code snippit has several advantages:

a) no need for a 2nd script.
You can keep everything in one script.
Easier to maintain.

b) no need for EOD stuff.
While <<EOD can be useful, I find it a pain in general.

c) this code fragment actually detects that 'passwd' returned 'failure'
and causes expect to return 1 which you can test in $?

d) the expect { ... } can be expanded to look for dozen's of possible error
messages that can come out of 'passwd'. You might want to use the the command

strings /usr/bin/passwd | less

which should give you an idea of all the different error messages passwd can issue.

By the way. While debugging this little expect code snippit, I used:

/usr/bin/expect -d -c "
...
"

where the -d option displayed a lot of useful debugging/tracing information
that helped me figure out what was going on.

I also looked for examples in "man expect", which is where I found the
expect { ... } syntax. A little experimentation along with the -d option
and I had an expect command where $? returned 0 on success, and 1 on failure.

NOTE: I make no claims on whether your approach is good or bad from a
security standpoint. I'll let MrHoffman and etresoft address that.

Nov 29, 2010 9:42 PM in response to BobHarris

Here is the finished script.


#!/usr/bin/env bash
#Display notification
/usr/bin/osascript <<-EOF
tell application "System Events"
activate
display dialog "This utility will set both your Apple system password and your Sophos SafeGuard Encryption password. This will fail if your Apple and Sophos accounts and passwords are not already in sync. They are in sync when deployed." buttons {"OK"} default button "OK"
end tell
EOF
#Prompting User for Password
read OLDPSWD0 < <(/usr/bin/osascript -e '
tell application "System Events"
activate
display dialog "Please enter your old Password:" default answer "" with hidden answer buttons {"OK"} default button "OK"
set the PSWD0 to text returned of the result
end tell
')
printf -v OLDPSWD0 "%q" "$OLDPSWD0"
passWdNtSt="true"
while [ $passWdNtSt == true ];
do
read PSWD0 < <(/usr/bin/osascript -e '
tell application "System Events"
activate
display dialog "Please enter a new password:" default answer "" with hidden answer buttons {"OK"} default button "OK"
set the PSWD0 to text returned of the result
end tell
')
printf -v PSWD0 "%q" "$PSWD0"
read PSWD1 < <(/usr/bin/osascript -e '
tell application "System Events"
activate
display dialog "Please verify your new password:" default answer "" with hidden answer buttons {"OK"} default button "OK"
set the PSWD1 to text returned of the result
end tell
')
printf -v PSWD1 "%q" "$PSWD1"
if [ "$PSWD0" == "$PSWD1" ]; then
passWdNtSt="false"
else
/usr/bin/osascript <<-EOF
tell application "System Events"
activate
display dialog "Your Passwords do not match, please try again!" buttons {"OK"} default button "OK"
end tell
EOF
fi
done
#Setting OSX account password
/usr/bin/expect -c "
spawn /usr/bin/passwd
expect word:
sleep 1
send $OLDPSWD0
expect word:
sleep 1
send $PSWD0
expect word:
sleep 1
send $PSWD0
expect {
failure {exit 1}
success {exp_continue}
}
"
if [ $? != 0 ]; then
/usr/bin/osascript <<-EOF
tell application "System Events"
activate
display dialog "The OS X account password you typed is incorrect. Please try again." buttons {"OK"} default button "OK"
end tell
EOF
exit
else
#Setting SafeGuard User Password
/usr/bin/sgadmin --list-users --authenticate-user $USER --authenticate-password $OLDPSWD0
if [ "$?" != "0" ]; then
/usr/bin/osascript <<-EOF
tell application "System Events"
activate
display dialog "The SafeGuard Encryption password you typed is incorrect. Please try again." buttons {"OK"} default button "OK"
end tell
EOF
exit
else
/usr/bin/sgadmin --change-password --user $USER --old-password $OLDPSWD0 --new-password $PSWD0 --confirm-password $PSWD1
/usr/bin/osascript <<-EOF
tell application "System Events"
activate
display dialog "Your password has been set." buttons {"OK"} default button "OK"
end tell
EOF
fi
fi



Thank you very much BobHarris, the code you posted worked perfect. It is sad but true that this is most likely not a secure script to use and I will not implement it based on earlier posts, but frankly it was fun and I learned a lot. I really appreciate you taking the time to break down, and explain your findings as well. I will admit I looked at the man pages for "Expect" and couldn't make heads or tails out of most of it. I found a few sites explaining error checking in Expect, but I could not figure out where to add my brackets and the syntax to use.

The -d in expect I will be playing with to learn more about the command. I have been dabbling in shell scripts for a few years and have never come across it. I am familiar w/ SendKeys in VBScript...but that is a disaster waiting to happen.

Also the "string /usr/bin/passwd | less" was very nice. I will look into that some more as well.

Thank you and keep up the great work.

Nov 29, 2010 9:43 PM in response to BobHarris

Here is the finished script.


#!/usr/bin/env bash
#Display notification
/usr/bin/osascript <<-EOF
tell application "System Events"
activate
display dialog "This utility will set both your Apple system password and your Sophos SafeGuard Encryption password. This will fail if your Apple and Sophos accounts and passwords are not already in sync. They are in sync when deployed." buttons {"OK"} default button "OK"
end tell
EOF
#Prompting User for Password
read OLDPSWD0 < <(/usr/bin/osascript -e '
tell application "System Events"
activate
display dialog "Please enter your old Password:" default answer "" with hidden answer buttons {"OK"} default button "OK"
set the PSWD0 to text returned of the result
end tell
')
printf -v OLDPSWD0 "%q" "$OLDPSWD0"
passWdNtSt="true"
while [ $passWdNtSt == true ];
do
read PSWD0 < <(/usr/bin/osascript -e '
tell application "System Events"
activate
display dialog "Please enter a new password:" default answer "" with hidden answer buttons {"OK"} default button "OK"
set the PSWD0 to text returned of the result
end tell
')
printf -v PSWD0 "%q" "$PSWD0"
read PSWD1 < <(/usr/bin/osascript -e '
tell application "System Events"
activate
display dialog "Please verify your new password:" default answer "" with hidden answer buttons {"OK"} default button "OK"
set the PSWD1 to text returned of the result
end tell
')
printf -v PSWD1 "%q" "$PSWD1"
if [ "$PSWD0" == "$PSWD1" ]; then
passWdNtSt="false"
else
/usr/bin/osascript <<-EOF
tell application "System Events"
activate
display dialog "Your Passwords do not match, please try again!" buttons {"OK"} default button "OK"
end tell
EOF
fi
done
#Setting OSX account password
/usr/bin/expect -c "
spawn /usr/bin/passwd
expect word:
sleep 1
send $OLDPSWD0
expect word:
sleep 1
send $PSWD0
expect word:
sleep 1
send $PSWD0
expect {
failure {exit 1}
success {exp_continue}
}
"
if [ $? != 0 ]; then
/usr/bin/osascript <<-EOF
tell application "System Events"
activate
display dialog "The OS X account password you typed is incorrect. Please try again." buttons {"OK"} default button "OK"
end tell
EOF
exit
else
#Setting SafeGuard User Password
/usr/bin/sgadmin --list-users --authenticate-user $USER --authenticate-password $OLDPSWD0
if [ "$?" != "0" ]; then
/usr/bin/osascript <<-EOF
tell application "System Events"
activate
display dialog "The SafeGuard Encryption password you typed is incorrect. Please try again." buttons {"OK"} default button "OK"
end tell
EOF
exit
else
/usr/bin/sgadmin --change-password --user $USER --old-password $OLDPSWD0 --new-password $PSWD0 --confirm-password $PSWD1
/usr/bin/osascript <<-EOF
tell application "System Events"
activate
display dialog "Your password has been set." buttons {"OK"} default button "OK"
end tell
EOF
fi
fi



Thank you very much BobHarris, the code you posted worked perfect. It is sad but true that this is most likely not a secure script to use and I will not implement it based on earlier posts, but frankly it was fun and I learned a lot. I really appreciate you taking the time to break down, and explain your findings as well. I will admit I looked at the man pages for "Expect" and couldn't make heads or tails out of most of it. I found a few sites explaining error checking in Expect, but I could not figure out where to add my brackets and the syntax to use.

The -d in expect I will be playing with to learn more about the command. I have been dabbling in shell scripts for a few years and have never come across it. I am familiar w/ SendKeys in VBScript...but that is a disaster waiting to happen.

Also the "string /usr/bin/passwd | less" was very nice. I will look into that some more as well.

Thank you and keep up the great work.

Nov 29, 2010 9:48 PM in response to iDam81

Also, in all seriousness, if someone could please post some of the risks associated to using this I would be greatly appreciative.
Simply as a learning mechanism if nothing more. I understand it could create issues if the account are not synced, but I believe it
is at a point where it will just simply fail if the passwords are not the same, and the safeguard account change could fail if the account
is not the same as the OS X account, but I think I could check for that in the script....more fun.

Besides that I would like to know some of the potential security risks and or other risks that using this could cause.

Thank you in advance.

Shell Script to set a user password from variables

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple ID.