Posted on 01-24-2016 06:16 AM
on our devices (10.10.x) we have two local accounts, one "ITadmin" and one "enduser" (also admin level).
We want to set a password policy that only applies to the enduser account as we need to keep the ITadmin accounts the same.
I've tried creating a configuration profile that is set to be user level with only a password payload configured but it doesn't show as applicable to the scoped devices. If I change to computer level it deploys just fine, but is applied to all the accounts.
I've tried using pwpolicy but I can't get the xml file to be in a readable format to be applied.
there is very little help that I can find on how to make a working xml file for this, the man page is very dodgy to say the least and none of the few examples I can find seem to work.
I don't really want to go down the line of using the deprecated command set as I want them to work on 10.11.
Has anyone got a clear example of a working xml file to feed into pwpolicy?
Solved! Go to Solution.
Posted on 01-25-2016 06:59 AM
The man page for pwpolicy has errors in it. Here's the script we use to deploy a password policy using the correct syntax for pwpollicy. Be sure to edit the variables. Tested and works on 10.10 and 10.11.
#!/bin/sh
##########################################################################################################
## Pupose: Create a pwpolicy XML file based upon variables and options included below.
## Policy is applied and then file gets deleted. Use "sudo pwpolicy -u <user> -getaccountpolicies"
## to see it, and "sudo pwpolicy -u <user> -clearaccountpolicies" to clear it.
##
## Usage: Edit variables in Variable flowerbox below.
## Then run as a policy from Casper, or standalone as root.
##
## Tested on: OS X 10.10 and 10.11
##
## Authors: Danny Friedman, Civis Analytics IT Manager, CCA, civisanalytics.com
## Jeff Holland, Civis Analytics Sr. Security Engineer, CISSP/GCUX, civisanalytics.com
#########################################################################################################
# get logged-in user and assign it to a variable
LOGGEDINUSER=$(ls -l /dev/console | awk '{print $3}')
echo "LOGGEDINUSER is: $LOGGEDINUSER"
##############################################################################
# Variables for script and commands generated below.
#
# EDIT AS NECESSARY FOR YOUR OWN PASSWORD POLICY
# AND COMPANY INFORMATION
#
COMPANY_NAME="yourcompany.com" # CHANGE THIS TO YOUR COMPANY NAME
LOCKOUT=300 # 5min lockout
MAX_FAILED=10 # 10 max failed logins before locking
PW_EXPIRE=90 # 90 days password expiration
MIN_LENGTH=8 # at least 8 chars for password
MIN_NUMERIC=1 # at least 1 number in password
MIN_ALPHA_LOWER=1 # at least 1 lower case letter in password
MIN_UPPER_ALPHA=1 # at least 1 upper case letter in password
MIN_SPECIAL_CHAR=1 # at least one special character in password
PW_HISTORY=10 # remember last 10 passwords
exemptAccount1="admin" #Exempt account used for remote management. CHANGE THIS TO YOUR EXEMPT ACCOUNT
#
##############################################################################
#################################################
##### create pwpolicy.plist in /private/var/tmp
# Password policy using variables above is:
# Change as necessary in variable flowerbox above
# --------------------------------------------------
# pw's must be at least 8 chars
# pw's must have at least 1 lower case letter
# pw's must have at least 1 upper case letter
# pw's must have at least 1 special non-alpha/non-numeric character
# pw's must have at least 1 number
# can't use any of the previous 10 passwords
# pw's expire at 90 days
# 10 failed successive login attempts results in a 300sec lockout, then auto enables
echo "<dict>
<key>policyCategoryAuthentication</key>
<array>
<dict>
<key>policyContent</key>
<string>(policyAttributeFailedAuthentications < policyAttributeMaximumFailedAuthentications) OR (policyAttributeCurrentTime > (policyAttributeLastFailedAuthenticationTime + autoEnableInSeconds))</string>
<key>policyIdentifier</key>
<string>Authentication Lockout</string>
<key>policyParameters</key>
<dict>
<key>autoEnableInSeconds</key>
<integer>$LOCKOUT</integer>
<key>policyAttributeMaximumFailedAuthentications</key>
<integer>$MAX_FAILED</integer>
</dict>
</dict>
</array>
<key>policyCategoryPasswordChange</key>
<array>
<dict>
<key>policyContent</key>
<string>policyAttributeCurrentTime > policyAttributeLastPasswordChangeTime + (policyAttributeExpiresEveryNDays * 24 * 60 * 60)</string>
<key>policyIdentifier</key>
<string>Change every $PW_EXPIRE days</string>
<key>policyParameters</key>
<dict>
<key>policyAttributeExpiresEveryNDays</key>
<integer>$PW_EXPIRE</integer>
</dict>
</dict>
</array>
<key>policyCategoryPasswordContent</key>
<array>
<dict>
<key>policyContent</key>
<string>policyAttributePassword matches '.{$MIN_LENGTH,}+'</string>
<key>policyIdentifier</key>
<string>Has at least $MIN_LENGTH characters</string>
<key>policyParameters</key>
<dict>
<key>minimumLength</key>
<integer>$MIN_LENGTH</integer>
</dict>
</dict>
<dict>
<key>policyContent</key>
<string>policyAttributePassword matches '(.*[0-9].*){$MIN_NUMERIC,}+'</string>
<key>policyIdentifier</key>
<string>Has a number</string>
<key>policyParameters</key>
<dict>
<key>minimumNumericCharacters</key>
<integer>$MIN_NUMERIC</integer>
</dict>
</dict>
<dict>
<key>policyContent</key>
<string>policyAttributePassword matches '(.*[a-z].*){$MIN_ALPHA_LOWER,}+'</string>
<key>policyIdentifier</key>
<string>Has a lower case letter</string>
<key>policyParameters</key>
<dict>
<key>minimumAlphaCharactersLowerCase</key>
<integer>$MIN_ALPHA_LOWER</integer>
</dict>
</dict>
<dict>
<key>policyContent</key>
<string>policyAttributePassword matches '(.*[A-Z].*){$MIN_UPPER_ALPHA,}+'</string>
<key>policyIdentifier</key>
<string>Has an upper case letter</string>
<key>policyParameters</key>
<dict>
<key>minimumAlphaCharacters</key>
<integer>$MIN_UPPER_ALPHA</integer>
</dict>
</dict>
<dict>
<key>policyContent</key>
<string>policyAttributePassword matches '(.*[^a-zA-Z0-9].*){$MIN_SPECIAL_CHAR,}+'</string>
<key>policyIdentifier</key>
<string>Has a special character</string>
<key>policyParameters</key>
<dict>
<key>minimumSymbols</key>
<integer>$MIN_SPECIAL_CHAR</integer>
</dict>
</dict>
<dict>
<key>policyContent</key>
<string>none policyAttributePasswordHashes in policyAttributePasswordHistory</string>
<key>policyIdentifier</key>
<string>Does not match any of last $PW_HISTORY passwords</string>
<key>policyParameters</key>
<dict>
<key>policyAttributePasswordHistoryDepth</key>
<integer>$PW_HISTORY</integer>
</dict>
</dict>
</array>
</dict>" > /private/var/tmp/pwpolicy.plist
##### end of pwpolicy.plist generation script
###################################################
#Check for non-admin account before deploying policy
if [ "$LOGGEDINUSER" != "$exemptAccount1" ]; then
chown $LOGGEDINUSER:staff /private/var/tmp/pwpolicy.plist
chmod 644 /private/var/tmp/pwpolicy.plist
# clear account policy before loading a new one
pwpolicy -u $LOGGEDINUSER -clearaccountpolicies
pwpolicy -u $LOGGEDINUSER -setaccountpolicies /private/var/tmp/pwpolicy.plist
elif [ "$LOGGEDINUSER" == "$exemptAccount1" ]; then
echo "Currently $exemptAccount1 is logged in and the password policy was NOT set. This script can only be run if the standard computer user is logged in."
rm -f /private/var/tmp/pwpolicy.plist
exit 1
fi
#delete staged pwploicy.plist
rm -f /private/var/tmp/pwpolicy.plist
echo "Password policy successfully applied. Run "sudo pwpolicy -u <user> -getaccountpolicies" to see it."
exit 0
Posted on 01-25-2016 07:09 AM
To add to Jeff's post above – we found the script above to be extremely effective in administering a password policy without LDAP.
In addition to the script above, you can create an Extension Attribute (script) to check if a computer has the password policy. The the Extension Attribute can then be used no only to see if individual computers have your password policy, but you can also create a Smart Group based on the attribute to deploy to computers that do not have your password policy.
We use this extension attribute (using a value of "5" for the number of previous passwords that pwpolicy tracks):
#!/bin/sh
# This script checks if the existing pwpolicy (or non-existent pwpolicy) matches the pwpolicy by looking to see if
# the string <string>Does not match any of last 5 passwords</string> exists in the current computer's pwpolicy
# get logged-in user and assign it to a variable
LOGGEDINUSER=`who -q | head -1 | cut -d ' ' -f1`
if [ "$LOGGEDINUSER" == "_mbsetupuser" ]; then
LOGGEDINUSER=`who -q | head -1 | cut -d ' ' -f2`
fi
CURRENTPWPOLICY=`pwpolicy -u $LOGGEDINUSER -getaccountpolicies | grep 'Does not match any of last 5 passwords' | sed -e 's/ //g' `
PWPOLICY="<string>Does not match any of last 5 passwords</string>"
if [ "$CURRENTPWPOLICY" == "$PWPOLICY" ]; then
echo "<result>$LOGGEDINUSER has the password policy</result>"
else
echo "<result>$LOGGEDINUSER DOES NOT have the password policy</result>"
fi
exit 0
There are other ways to accomplish this, but we have found this one to be a simple and easy way to do it.
Posted on 01-24-2016 10:22 PM
You could just run a policy with a script payload using a pwpolicy command in the script. the -u option allows you to specify the user account that the pwpolicy applies to. The man page also has an example XML file.
Posted on 01-25-2016 06:59 AM
The man page for pwpolicy has errors in it. Here's the script we use to deploy a password policy using the correct syntax for pwpollicy. Be sure to edit the variables. Tested and works on 10.10 and 10.11.
#!/bin/sh
##########################################################################################################
## Pupose: Create a pwpolicy XML file based upon variables and options included below.
## Policy is applied and then file gets deleted. Use "sudo pwpolicy -u <user> -getaccountpolicies"
## to see it, and "sudo pwpolicy -u <user> -clearaccountpolicies" to clear it.
##
## Usage: Edit variables in Variable flowerbox below.
## Then run as a policy from Casper, or standalone as root.
##
## Tested on: OS X 10.10 and 10.11
##
## Authors: Danny Friedman, Civis Analytics IT Manager, CCA, civisanalytics.com
## Jeff Holland, Civis Analytics Sr. Security Engineer, CISSP/GCUX, civisanalytics.com
#########################################################################################################
# get logged-in user and assign it to a variable
LOGGEDINUSER=$(ls -l /dev/console | awk '{print $3}')
echo "LOGGEDINUSER is: $LOGGEDINUSER"
##############################################################################
# Variables for script and commands generated below.
#
# EDIT AS NECESSARY FOR YOUR OWN PASSWORD POLICY
# AND COMPANY INFORMATION
#
COMPANY_NAME="yourcompany.com" # CHANGE THIS TO YOUR COMPANY NAME
LOCKOUT=300 # 5min lockout
MAX_FAILED=10 # 10 max failed logins before locking
PW_EXPIRE=90 # 90 days password expiration
MIN_LENGTH=8 # at least 8 chars for password
MIN_NUMERIC=1 # at least 1 number in password
MIN_ALPHA_LOWER=1 # at least 1 lower case letter in password
MIN_UPPER_ALPHA=1 # at least 1 upper case letter in password
MIN_SPECIAL_CHAR=1 # at least one special character in password
PW_HISTORY=10 # remember last 10 passwords
exemptAccount1="admin" #Exempt account used for remote management. CHANGE THIS TO YOUR EXEMPT ACCOUNT
#
##############################################################################
#################################################
##### create pwpolicy.plist in /private/var/tmp
# Password policy using variables above is:
# Change as necessary in variable flowerbox above
# --------------------------------------------------
# pw's must be at least 8 chars
# pw's must have at least 1 lower case letter
# pw's must have at least 1 upper case letter
# pw's must have at least 1 special non-alpha/non-numeric character
# pw's must have at least 1 number
# can't use any of the previous 10 passwords
# pw's expire at 90 days
# 10 failed successive login attempts results in a 300sec lockout, then auto enables
echo "<dict>
<key>policyCategoryAuthentication</key>
<array>
<dict>
<key>policyContent</key>
<string>(policyAttributeFailedAuthentications < policyAttributeMaximumFailedAuthentications) OR (policyAttributeCurrentTime > (policyAttributeLastFailedAuthenticationTime + autoEnableInSeconds))</string>
<key>policyIdentifier</key>
<string>Authentication Lockout</string>
<key>policyParameters</key>
<dict>
<key>autoEnableInSeconds</key>
<integer>$LOCKOUT</integer>
<key>policyAttributeMaximumFailedAuthentications</key>
<integer>$MAX_FAILED</integer>
</dict>
</dict>
</array>
<key>policyCategoryPasswordChange</key>
<array>
<dict>
<key>policyContent</key>
<string>policyAttributeCurrentTime > policyAttributeLastPasswordChangeTime + (policyAttributeExpiresEveryNDays * 24 * 60 * 60)</string>
<key>policyIdentifier</key>
<string>Change every $PW_EXPIRE days</string>
<key>policyParameters</key>
<dict>
<key>policyAttributeExpiresEveryNDays</key>
<integer>$PW_EXPIRE</integer>
</dict>
</dict>
</array>
<key>policyCategoryPasswordContent</key>
<array>
<dict>
<key>policyContent</key>
<string>policyAttributePassword matches '.{$MIN_LENGTH,}+'</string>
<key>policyIdentifier</key>
<string>Has at least $MIN_LENGTH characters</string>
<key>policyParameters</key>
<dict>
<key>minimumLength</key>
<integer>$MIN_LENGTH</integer>
</dict>
</dict>
<dict>
<key>policyContent</key>
<string>policyAttributePassword matches '(.*[0-9].*){$MIN_NUMERIC,}+'</string>
<key>policyIdentifier</key>
<string>Has a number</string>
<key>policyParameters</key>
<dict>
<key>minimumNumericCharacters</key>
<integer>$MIN_NUMERIC</integer>
</dict>
</dict>
<dict>
<key>policyContent</key>
<string>policyAttributePassword matches '(.*[a-z].*){$MIN_ALPHA_LOWER,}+'</string>
<key>policyIdentifier</key>
<string>Has a lower case letter</string>
<key>policyParameters</key>
<dict>
<key>minimumAlphaCharactersLowerCase</key>
<integer>$MIN_ALPHA_LOWER</integer>
</dict>
</dict>
<dict>
<key>policyContent</key>
<string>policyAttributePassword matches '(.*[A-Z].*){$MIN_UPPER_ALPHA,}+'</string>
<key>policyIdentifier</key>
<string>Has an upper case letter</string>
<key>policyParameters</key>
<dict>
<key>minimumAlphaCharacters</key>
<integer>$MIN_UPPER_ALPHA</integer>
</dict>
</dict>
<dict>
<key>policyContent</key>
<string>policyAttributePassword matches '(.*[^a-zA-Z0-9].*){$MIN_SPECIAL_CHAR,}+'</string>
<key>policyIdentifier</key>
<string>Has a special character</string>
<key>policyParameters</key>
<dict>
<key>minimumSymbols</key>
<integer>$MIN_SPECIAL_CHAR</integer>
</dict>
</dict>
<dict>
<key>policyContent</key>
<string>none policyAttributePasswordHashes in policyAttributePasswordHistory</string>
<key>policyIdentifier</key>
<string>Does not match any of last $PW_HISTORY passwords</string>
<key>policyParameters</key>
<dict>
<key>policyAttributePasswordHistoryDepth</key>
<integer>$PW_HISTORY</integer>
</dict>
</dict>
</array>
</dict>" > /private/var/tmp/pwpolicy.plist
##### end of pwpolicy.plist generation script
###################################################
#Check for non-admin account before deploying policy
if [ "$LOGGEDINUSER" != "$exemptAccount1" ]; then
chown $LOGGEDINUSER:staff /private/var/tmp/pwpolicy.plist
chmod 644 /private/var/tmp/pwpolicy.plist
# clear account policy before loading a new one
pwpolicy -u $LOGGEDINUSER -clearaccountpolicies
pwpolicy -u $LOGGEDINUSER -setaccountpolicies /private/var/tmp/pwpolicy.plist
elif [ "$LOGGEDINUSER" == "$exemptAccount1" ]; then
echo "Currently $exemptAccount1 is logged in and the password policy was NOT set. This script can only be run if the standard computer user is logged in."
rm -f /private/var/tmp/pwpolicy.plist
exit 1
fi
#delete staged pwploicy.plist
rm -f /private/var/tmp/pwpolicy.plist
echo "Password policy successfully applied. Run "sudo pwpolicy -u <user> -getaccountpolicies" to see it."
exit 0
Posted on 01-25-2016 07:09 AM
To add to Jeff's post above – we found the script above to be extremely effective in administering a password policy without LDAP.
In addition to the script above, you can create an Extension Attribute (script) to check if a computer has the password policy. The the Extension Attribute can then be used no only to see if individual computers have your password policy, but you can also create a Smart Group based on the attribute to deploy to computers that do not have your password policy.
We use this extension attribute (using a value of "5" for the number of previous passwords that pwpolicy tracks):
#!/bin/sh
# This script checks if the existing pwpolicy (or non-existent pwpolicy) matches the pwpolicy by looking to see if
# the string <string>Does not match any of last 5 passwords</string> exists in the current computer's pwpolicy
# get logged-in user and assign it to a variable
LOGGEDINUSER=`who -q | head -1 | cut -d ' ' -f1`
if [ "$LOGGEDINUSER" == "_mbsetupuser" ]; then
LOGGEDINUSER=`who -q | head -1 | cut -d ' ' -f2`
fi
CURRENTPWPOLICY=`pwpolicy -u $LOGGEDINUSER -getaccountpolicies | grep 'Does not match any of last 5 passwords' | sed -e 's/ //g' `
PWPOLICY="<string>Does not match any of last 5 passwords</string>"
if [ "$CURRENTPWPOLICY" == "$PWPOLICY" ]; then
echo "<result>$LOGGEDINUSER has the password policy</result>"
else
echo "<result>$LOGGEDINUSER DOES NOT have the password policy</result>"
fi
exit 0
There are other ways to accomplish this, but we have found this one to be a simple and easy way to do it.
Posted on 01-25-2016 07:52 AM
thanks for the help @jholland @dfriedman , much appreciated.
Posted on 01-25-2016 08:08 AM
No problem. Glad it did the trick!
Posted on 01-25-2016 08:21 AM
Thank you jholland, that script works great. One question that I have is how would you turn this policy off?
Posted on 01-25-2016 08:26 AM
@lpadmin – you can clear policies for a specific user with
sudo pwpolicy -u <username> -clearaccountpolicies
I am not sure how to clear policies for all users in a single command, as the man page for pwpolicy leaves quite a bit to be desired, but you can do this for every user on a given system to remove the password policy.
Posted on 01-25-2016 08:35 AM
Thanks Jeff I think that is the 1st public use of the policyCategory.plist, for sure it's the 1st I have found !!!
Thanks
C
PS Do you "guys" have a git repository? : )
Posted on 01-25-2016 09:09 AM
Because this happens within the logged in user account, does it affect the KeyChain in anyway or is the KeyChain automatically synced with the new user password?
Posted on 01-25-2016 09:45 AM
@gachowski I'll have to create a repo for it. Will try and get that up soon.
Posted on 01-25-2016 09:45 AM
@acaveny – pwpolicy does not interact at all with login.keychain. When pwpolicy enforcement triggers the OS to prompt the user to change the password, the login password is automatically synced in the same way that a user manually changing their password would (as it is the standard core OS process controlling the actual password change).
Posted on 01-25-2016 10:06 AM
@jholland No rush, you "guys" know what is going on and the more you can share the better : ) : )
C
Posted on 01-25-2016 10:13 AM
@acaveny – Sorry, I realize that I didn't directly answer your question, but tried to imply the answer. The login keychain will sync properly and automatically, and you should not have to perform any additional steps.
@gachowski – We should have the repo up relatively soon. I have a bunch of scripts that I'll be putting up. If you use FileVault 2, I imagine that you will really enjoy these ;)
Posted on 01-25-2016 10:30 AM
Posted on 01-26-2016 06:34 AM
I just encountered a weird issue, not sure if it is related to this script. Sorry for being long I just want to give all of the details.
I configured the variables in the script to work for my environment. The biggest change that I made was to remove the sections looking for a minimum amount of special characters. I then pushed this out to 20 test computers and everything was working. I then pushed it to my Computer yesterday afternoon. SInce my password was old it prompted me to change it and I did. I have logged out and signed back in multiple times since changing the password without any issues. (Quick note my computer is using FireVault). This morning I turned on the computer and successfully logged in, I then walked away for a view minutes. When I came back I went to unlock the computer by using my password. The computer would not accept the password and acted like it was the wrong one. After being denied a few times I logged into the admin account just to make sure my Keyboard was not messed up, and was able to. I then restarted the computer and got the prompt to enter a password to unlock the disk, I entered the same new password and it unlocked the disk, at the login screen though it still denied the password. I then logged into the admin account and just the password again from Users & Groups, then I was able to get back into my account.
Has anyone else encountered this, or know what could have caused it?
Posted on 01-26-2016 08:54 AM
Update;
So it locked me out again. This time I turned off FileVault and it allowed me back in after the restart.
Posted on 01-26-2016 09:20 AM
@lpadmin That hasn't been the case with our user base, which is 100 strong.
You can determine if it's the pw policy by logging in as your admin user and clearing the account policy for the specific user (sudo pwpolicy -u <username> -clearaccountpolicies).
Posted on 01-26-2016 09:29 AM
That is pretty odd. I did see some issues that now sound similar, relating to FileVault 2. The issue that I experienced was that a user, while seemingly showing up as a FileVault 2 user in the OS X GUI (in System Preferences and the FV2 login screen post-boot), was not in fact a FileVault 2 authenticated user, despite OS X acting like it was.
Thus, the user visibly shows up to unlock the disk after boot (at the FV2 login screen), but no password worked for that user to unlock the disk. The admin user on the computer, that also was an approved FV2 user, was able unlock the disk. The admin could then log out or use fast user switching get to a non-FV2 user login. There, the account that previously wasn't able to unlock the disk was able to log in with the same password that the FV2 authentication did not accept prior.
The fix for this issue was to remove the user in question from FV2 and then re-add the user (via command line). This would imply that whenever the user was forced to change his password, the password did not sync with the FV2 mechanism that allows that password to decrypt/unlock the encrypted disk. Disabling and re-enabling FV2 also resolved this issue, which is a long, arduous process.
This has not been an issue for the many of our machines, but I have dealt with it on about 4 of our 100 managed computers.
Posted on 01-26-2016 10:07 AM
Danny and I just talked about this. It seems to be a edge case that Apple didn't take into account, even though only resident OS X tools like pwpolicy are used.
Assume your password is 100 days old, and you apply a policy that says passwords cannot be older than 90 days. You are then immediately dumped into a prompt to change your password. When you do, it seems the password associated with your user in FileVault2 is not updated. Conversely, if you change your password via system preferences, the password associated with FileVault2 is updated.
If filevault2 is not in use, or your password is not older than your expiration time, everything is kosher when using this script.
We get around this particular issue by warning users with some other Casper scripts that tell them "User, your password expires in 7 days, please change it now" using notifications and repeats every 8 hours. We'll try and get that script and a few others up on a GitHub page we're going to build soon.
One solution for your 20 computers is to have them all change their password, then push the policy. The password will not be older than the expiration time so they won't get the prompt. In addition, have them change their password before it expires so they don't prompted to change their password as you did and run into filevault issues.
Hope that helps.
Posted on 01-26-2016 10:48 AM
Thanks for the input jholland & dfriedman.
This issue is definitely being caused by FileVault. As soon as my computer checked in without FileVault enabled and the JSS forced me to re-enable it, the password stopped working. I have turned it back off and removed my computer from the policy. Hopefully that fixes it for now, I will be looking for the scripts that you post on Github. Until then I will just leave FileVault turned off.
Posted on 01-26-2016 01:11 PM
Ok that sounds good for now. I think it's ridiculous that Apple hasn't resolved this issue, but I suppose the man page for pwpolicy adequately shows Apple's dedication to the tool.
Either Jeff or I will post an update to this posting as soon as our GitHub is up.
Posted on 02-04-2016 10:13 AM
#!/bin/sh
# This script checks if the existing pwpolicy (or non-existent pwpolicy) matches the pwpolicy by looking to see if
# the string <string>Does not match any of last 5 passwords</string> exists in the current computer's pwpolicy
# get logged-in user and assign it to a variable
LOGGEDINUSER=`who -q | head -1 | cut -d ' ' -f1`
if [ "$LOGGEDINUSER" == "_mbsetupuser" ]; then
LOGGEDINUSER=`who -q | head -1 | cut -d ' ' -f2`
fi
CURRENTPWPOLICY=`pwpolicy -u $LOGGEDINUSER -getaccountpolicies | grep 'Does not match any of last 5 passwords' | sed -e 's/ //g' `
PWPOLICY="<string>Does not match any of last 5 passwords</string>"
if [ "$CURRENTPWPOLICY" == "$PWPOLICY" ]; then
echo "<result>$LOGGEDINUSER has the password policy</result>"
else
echo "<result>$LOGGEDINUSER DOES NOT have the password policy</result>"
fi
exit 0
If I run the extension attribute code above I never get "$LOGGEDINUSER has the password policy"
My result is always:
<result>test DOES NOT have the password policy</result>
Yet the result of:
echo $CURRENTPWPOLICY
echo $PWPOLICY
Yields:
<string>Does not match any of last 10 passwords</string>
<string>Does not match any of last 10 passwords</string>
So $CURRENTPWPOLICY = $PWPOLICY
Yet if at the terminal I type:pwpolicy -u test -getaccountpolicies | grep 'Does not match any of last 10 passwords' | sed -e 's/ //g'
I get:
<string>Does not match any of last 10 passwords</string>
So I know the script policy (way above) is applied. Somehow CURRENTPWPOLICY is not equaling PWPOLICY. Even though I know we cut&pasted both scripts verbatim, but only changed the 5 to a 10. Even changing everything back to the original 5 in both scripts, does not help.
Thoughts?
Posted on 02-04-2016 10:45 AM
@dellis one possibility is that there is an issue with the $LOGGEDINUSER
variable definition.
Most of the time the
$LOGGEDINUSER=`who -q | head -1 | cut -d ' ' -f1`
if [ "$LOGGEDINUSER" == "_mbsetupuser" ]; then
LOGGEDINUSER=`who -q | head -1 | cut -d ' ' -f2`
fi
works, but I have recently started using LOGGEDINUSER=$( ls -l /dev/console | awk '{print $3}' )
which always returns the correct user. The reason the above command does not always works has to do with the many hidden system users in OS X.
Changing the way that $LOGGEDINUSER
is set (in both the script and the Extension Attribute) could do it.
That is one possibility. If that doesn't work, another possibility is that when you copied the script above, it copied the tab incorrectly in the sed -e 's/ //g'
expression (the space between the first and second slashes). You could try editing both of the scripts in a text editor (like TextWrangler or Atom), and replace that tab/space character with a tab, resave, upload to JSS, and see if that resolves it.
Posted on 02-04-2016 12:59 PM
@dfriedman Yep, it was the tab....so easy to miss. Thanks
Posted on 02-04-2016 01:01 PM
@dellis no problem! Glad it worked!
Posted on 02-17-2016 09:07 AM
I am seeing the same issue with some AD accounts a FV2.. In the GUI the accounts added after the 1st user, look like they are FV2 enable and show up at the FV2 log in screen but can't authenticate at the FV2 log in. However they can log in at the OS level...
C
Posted on 02-17-2016 09:31 AM
That's too bad. Unfortunately, this problem isn't easily resolved, as this is an issue with stock Apple tools (pwpolicy, FileVault 2), and how they interact. Removing and re-adding that user as a File Vault 2 user will fix this, but it's ugly (you will also need another existing account to be encrypted with FileVault 2 in order to use the method below).
You can remove the user with
fdesetup remove <username>
Then, re-enable for the user with
fdesetup add <username>
This can be scripted and you can prompt the user for input using the -inputlist
functionality. @rtrouton has documented fdesetup very well on his blog.
Posted on 02-18-2016 09:21 AM
This script seems perfect for what our org is trying to do but everytime I run it I get "error: Credential operation failed because an invalid parameter was provided." I cannot figure out where I'm going wrong. I did change the LOGGEDINUSER to =$( ls -l /dev/console | awk '{print $3}' ) , but I received the same results before and after the change. Can anyone guide me as to what I might be missing here?
Posted on 02-18-2016 10:19 AM
@evobe What version of OS X are you running this on? This was written for Yosemite/El Cap (10.10/10.11) which deprecated the old pwpolicy commands for the XML formatted plist.
Posted on 02-18-2016 11:00 AM
@jholland I'm using el capitan (10.11.3), only a few of our machines are on yosemite and we're in the process of upgrading them to El Cap.
Posted on 02-18-2016 11:11 AM
@evobe Are you running the script as root locally (or using sudo), or are you running from a Casper policy? It should work either way, but if you are running locally you need to run it with privileges.
Posted on 02-18-2016 11:50 AM
@jholland, I've done it as both, I've run it using a policy with a trigger through JSS and I've run it locally, each time I've received the same error. I put in my password and it just doesn't work. Driving us crazy since it seems to work perfectly for you guys.
Posted on 02-18-2016 12:02 PM
@evobe Hmm, strange, it should work. Must be something simple:
(sudo pwpolicy -u <user> -getaccountpolicies)
(sudo pwpolicy -u <user> -clearaccountpolicies)
Posted on 08-21-2017 07:13 AM
@jholland I just ran this script to be pushed out to two devices, even though the JSS says they completed it only one actually asked for a password change.
I did have to comment out some of the rules, but it seemed to work.
Flushed out the logs and reran the script, it says it runs, but still nothing runs:
The following Log is noted:
Executing Policy Password reset script
Running script Password reset script...
Script exit code: 0
Script result: LOGGEDINUSER is: teacher<br/>Clearing account policies for user <teacher><br/>Error: The data is not in the correct format.<br/>Password policy successfully applied. Run "sudo pwpolicy -u <user> -getaccountpolicies" to see it.<br/>
The OS is 10.12.5
We may need to run this script a few times a year or on an as needed basis. Is this going to cause problems?
Any help is greatly appreciated.
Posted on 08-25-2017 02:19 PM
FYI,
Parts of this are broken in High Sierra when using FV2... please test and open feedback with Apple if you have access..
C
Posted on 09-05-2017 09:32 AM
Thanks for the input jholland & dfriedman. This issue is definitely being caused by FileVault. As soon as my computer checked in without FileVault enabled and the JSS forced me to re-enable it, the password stopped working. I have turned it back off and removed my computer from the policy. Hopefully that fixes it for now, I will be looking for the scripts that you post on Github. Until then I will just leave FileVault turned off.
There are any news about this issue? I have the same problem in the macs of my enterprise
Posted on 03-08-2018 08:27 PM
This script is great for enforcing password complexity on the next password change. Is there a way to for this to also expire the user's existing password?
I am using this as part of an imaging process via deploy studio.
Posted on 03-09-2018 07:53 AM
There is another policy in pwpolicy called "newPasswordRequired":
newPasswordRequired If 1, the user will be prompted for a new
password at the next authentication. Appli-
cations that do not support change password
will not authenticate.
Not sure how you would apply it in your environment, but that is the command.
Posted on 03-09-2018 09:12 AM
@jason.bracy 100% correct. Within a few moments of posting I found the the command and entered it below the set new policies section
-setpolicy "newPasswordRequired=1" being added resolved this issue.