Skip to content

Instantly share code, notes, and snippets.

@lucascantor
Created January 27, 2018 08:33
Show Gist options
  • Save lucascantor/f53d92bfe2231af15debefdcd1d3cc6a to your computer and use it in GitHub Desktop.
Save lucascantor/f53d92bfe2231af15debefdcd1d3cc6a to your computer and use it in GitHub Desktop.
Generate and apply a standalone macOS password policy, exempting a specified local admin
#!/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: Only edit the variables in the Variable flowerbox below.
## 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="company.com" # Company name
LOCKOUT=60 # 1 minute lockout
MAX_FAILED=5 # 5 max failed logins before locking
MIN_LENGTH=10 # at least 10 chars for password
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
# --------------------------------------------------
# pw's must be at least 8 chars
# 10 failed login attempts results in a 60 second lockout
echo "<dict>
<key>policyCategoryAuthentication</key>
<array>
<dict>
<key>policyContent</key>
<string>(policyAttributeFailedAuthentications &lt; policyAttributeMaximumFailedAuthentications) OR (policyAttributeCurrentTime &gt; (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>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>
</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 to $LOGGEDINUSER."
echo "Run \"sudo pwpolicy -u $LOGGEDINUSER -getaccountpolicies\" to see it."
echo "Run \"sudo pwpolicy -u $LOGGEDINUSER -clearaccountpolicies\" to remove it."
exit 0
@DDC-96
Copy link

DDC-96 commented May 2, 2024

Hello Lucas,
Thank you for this script. I'm considering a similar approach and have a question about your choice of location path, specifically using <pwpolicy.plist in /private/var/tmp>. Could you explain the reason behind this choice?

I ask because I've developed a similar pwpolicy using bash/XML, but I've set it to /tmp/pwpolicy.xml. While my script functions as intended, I've noticed the difference in staging directories.

I'd greatly appreciate any insights you can offer on this matter

@lucascantor
Copy link
Author

@DDC-96 the /private/var/tmp location was chosen by the script's authors:

Danny Friedman, Civis Analytics IT Manager, CCA, civisanalytics.com
Jeff Holland, Civis Analytics Sr. Security Engineer, CISSP/GCUX, civisanalytics.com

I've just re-hosted it on GitHub after finding it elsewhere, and finding it useful, but it's VERY old at this point. It hasn't been tested since macOS 10.11 which came out nearly a decade ago now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment