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
@lucascantor
Copy link
Author

@leonleonardo23 it sounds like you're either not in the same directory as your 2policyMacos.sh script and/or you've got a typo in the script's filename.

That said, this gist is just a re-hosted copy of the original written by Danny Friedman and Jeff Holland, from Civis Analytics, and it hasn't been updated or tested on any remotely modern version of macOS, so I'd discourage you from using it as-is.

@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