Forked from lucascantor/applyPasswordPolicy.sh
Last active
December 13, 2021 06:36
-
-
Save Allistah/c3b1fead3ab7c13c2526abf26ea79978 to your computer and use it in GitHub Desktop.
Generate and apply a standalone macOS password policy, exempting a specified local admin
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
######################################################################################### | |
## Creates a local password policy on a Mac running OS 10 or 11. | |
## | |
## Created from various files I found around the internet and man pages | |
## for pwpolicy. I've added the ability to edit the default password | |
## length which was difficult to find. I attempted to preserve original author names. | |
## | |
## This script builds a password policy in a .plist file, imports that | |
## policy from the file, then deletes that file. | |
## | |
## Use "sudo pwpolicy -u <user> -getaccountpolicies" | |
## to see it, and "sudo pwpolicy -u <user> -clearaccountpolicies" to clear it. | |
## | |
## Tested on: OS X 10.10, 10.11, 10.12, and 11.5 | |
## | |
## Authors: | |
## Danny Friedman, Civis Analytics IT Manager, CCA, civisanalytics.com | |
## Jeff Holland, Civis Analytics Sr. Security Engineer, CISSP/GCUX, civisanalytics.com | |
## Jaime Pirnie, Director of Information Systems | |
## | |
## Version 1.x - Initial releases, unknown number of iterations | |
## Version 2.0 - Jaime Pirnie - Added logic to only include policies needed | |
## Added ability to modify default password length | |
## Organized options with mandatory and opotional settings | |
## | |
######################################################################################### | |
###################################################### | |
# 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 | |
# | |
# Mandatory settings | |
COMPANY_NAME="mycompany.com" # Company name | |
MIN_LENGTH=12 # at least x chars for password | |
MAX_FAILED=5 # max failed logins before locking | |
LOCKOUT_SECONDS=600 # seconds lockout | |
PW_EXPIRE=180 # days password expiration | |
# Optional Settings, set to 0 to disable | |
MIN_ALPHA_LOWER=0 # at least x lower case letter in password | |
MIN_UPPER_ALPHA=0 # at least x upper case letter in password | |
MIN_SPECIAL_CHAR=0 # at least x special character in password | |
PW_HISTORY=10 # remember last x passwords | |
exemptAccount1="<exempt local admin username>" #Exempt account used for management. | |
# | |
############################################################################## | |
################################################### | |
# create pwpolicy.plist in /private/var/tmp | |
# Password policy using variables above is: | |
# Change as necessary in variable flowerbox above | |
# ------------------------------------------------- | |
echo " | |
<?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
<plist version="1.0"> | |
<dict> | |
<key>policyCategoryAuthentication</key> | |
<array> | |
<dict> | |
<key>policyContent</key> | |
<string>(policyAttributeFailedAuthentications < policyAttributeMaximumFailedAuthentications) OR (policyAttributeCurrentTime > (policyAttributeLastFailedAuthenticationTime + autoEnableInSeconds))</string> | |
<key>policyIdentifier</key> | |
<string>ProfilePayload:d79bf40f-9771-4a35-a568-15833429b9e7:minutesUntilFailedLoginReset</string> | |
<key>policyParameters</key> | |
<dict> | |
<key>autoEnableInSeconds</key> | |
<integer>$LOCKOUT_SECONDS</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>ProfilePayload:d79bf40f-9771-4a35-a568-15833429b9e7:maxPINAgeInDays</string> | |
<key>policyParameters</key> | |
<dict> | |
<key>policyAttributeExpiresEveryNDays</key> | |
<integer>$PW_EXPIRE</integer> | |
</dict> | |
</dict> | |
<dict> | |
<key>policyContent</key> | |
<string>(policyAttributeLastPasswordChangeTime < policyAttributeNewPasswordRequiredTime) and (policyAttributeCurrentTime >= policyAttributeNewPasswordRequiredTime)</string> | |
<key>policyIdentifier</key> | |
<string>ProfilePayload:d79bf40f-9771-4a35-a568-15833429b9e7:changeAtNextAuth</string> | |
<key>policyParameters</key> | |
<dict> | |
<key>policyAttributeNewPasswordRequiredTime</key> | |
<real>1630158879.499939</real> | |
</dict> | |
</dict> | |
</array> | |
<key>policyCategoryPasswordContent</key> | |
<array> | |
<dict> | |
<key>policyContent</key> | |
<string>policyAttributePassword matches '.{$MIN_LENGTH,}+'</string> | |
<key>policyContentDescription</key> | |
<dict> | |
<key>en</key> | |
<string>Enter a password that is $MIN_LENGTH characters or more. (Def)</string> | |
</dict> | |
<key>policyIdentifier</key> | |
<string>com.apple.defaultpasswordpolicy.fde</string> | |
</dict> | |
<dict> | |
<key>policyContent</key> | |
<string>none policyAttributePasswordHashes in policyAttributePasswordHistory</string> | |
<key>policyContentDescription</key> | |
<dict> | |
<key>en</key> | |
<string>Not be the same as the previous $PW_HISTORY passwords.</string> | |
</dict> | |
<key>policyIdentifier</key> | |
<string>ProfilePayload:d79bf40f-9771-4a35-a568-15833429b9e7:pinHistory</string> | |
<key>policyParameters</key> | |
<dict> | |
<key>policyAttributePasswordHistoryDepth</key> | |
<integer>$PW_HISTORY</integer> | |
</dict> | |
</dict>" >> /private/var/tmp/pwpolicy.plist | |
if [ "$MIN_ALPHA_LOWER" != "0" ]; then | |
echo " | |
<dict> | |
<key>policyContent</key> | |
<string>policyAttributePassword matches '(.*[a-z].*){$MIN_ALPHA_LOWER,}+'</string> | |
<key>policyIdentifier</key> | |
<string>At least $MIN_ALPHA_LOWER lower case letter</string> | |
<key>policyParameters</key> | |
<dict> | |
<key>minimumAlphaCharactersLowerCase</key> | |
<integer>$MIN_ALPHA_LOWER</integer> | |
</dict> | |
</dict>" >> /private/var/tmp/pwpolicy.plist | |
fi | |
if [ "$MIN_UPPER_ALPHA" != "0" ]; then | |
echo " | |
<dict> | |
<key>policyContent</key> | |
<string>policyAttributePassword matches '(.*[A-Z].*){$MIN_UPPER_ALPHA,}+'</string> | |
<key>policyIdentifier</key> | |
<string>At least $MIN_UPPER_ALPHA upper case letter</string> | |
<key>policyParameters</key> | |
<dict> | |
<key>minimumAlphaCharactersUpperCase</key> | |
<integer>$MIN_UPPER_ALPHA</integer> | |
</dict> | |
</dict>" >> /private/var/tmp/pwpolicy.plist | |
fi | |
if [ "$MIN_SPECIAL_CHAR" != "0" ]; then | |
echo " | |
<dict> | |
<key>policyContent</key> | |
<string>policyAttributePassword matches '(.*[^a-zA-Z0-9].*){$MIN_SPECIAL_CHAR,}+'</string> | |
<key>policyIdentifier</key> | |
<string>At least $MIN_SPECIAL_CHAR special character</string> | |
<key>policyParameters</key> | |
<dict> | |
<key>minimumSymbols</key> | |
<integer>$MIN_SPECIAL_CHAR</integer> | |
</dict> | |
</dict>" >> /private/var/tmp/pwpolicy.plist | |
fi | |
echo " | |
</array> | |
</dict> | |
</plist>" >> /private/var/tmp/pwpolicy.plist | |
################################################### | |
#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 to $LOGGEDINUSER." | |
echo "Run \"sudo pwpolicy -u $LOGGEDINUSER -getaccountpolicies\" to see it." | |
echo "Run \"sudo pwpolicy -u $LOGGEDINUSER -clearaccountpolicies\" to remove it." | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment