Mac OS X,  Mac OS X Server,  Mac Security,  Mass Deployment

Programatically Setting Password Policies

Mac OS X, like many operating systems has a robust password policy engine.  One that is not leveraged by default on either Mac OS X client or on Mac OS X Server.  In Mac OS X Server, when using Open Directory, you can easily click on Open Directory in the SERVERS sidebar list of Server Admin and then click on the Settings icon in the Server Admin toolbar.  Here, if you click on Policies you’ll see the available Policies for Open Directory accounts.
However, in order to use Password Policies in non-Directory Services environments (ie – on standalone Mac OS X clients or servers) you’ll need to use the command line.  To set policies, Apple has provided an easy to use command line facility in the form of pwpolicy.  When you use pwpolicy, you will first need to specify the directory node by using an -n option followed by the path to the directory node you will be assigning the password policy to.  In a standalone Mac OS X client environment this would simply be /Local/Default, by default (although you can specify other local directory nodes if you need to).  To see global password policies for all users you can then use the -getglobalpolicy option.  This will show all of the options, whether enabled or not that are available and their current setting:
pwpolicy -n /Local/Default -getglobalpolicy
Which would produce output similar to the following:
usingHistory=0 canModifyPasswordforSelf=1 usingExpirationDate=0 usingHardExpirationDate=0 requiresAlpha=0 requiresNumeric=0 expirationDateGMT=12/31/69 hardExpireDateGMT=12/31/69 maxMinutesUntilChangePassword=0 maxMinutesUntilDisabled=0 maxMinutesOfNonUse=0 maxFailedLoginAttempts=0 minChars=0 maxChars=0 passwordCannotBeName=0 requiresMixedCase=0 requiresSymbol=0 newPasswordRequired=0 minutesUntilFailedLoginReset=0 notGuessablePattern=0
usingHistory=0 canModifyPasswordforSelf=1 usingExpirationDate=0 usingHardExpirationDate=0 requiresAlpha=0 requiresNumeric=0 expirationDateGMT=12/31/69 hardExpireDateGMT=12/31/69 maxMinutesUntilChangePassword=0 maxMinutesUntilDisabled=0 maxMinutesOfNonUse=0 maxFailedLoginAttempts=0 minChars=0 maxChars=0 passwordCannotBeName=0 requiresMixedCase=0 requiresSymbol=0 newPasswordRequired=0 minutesUntilFailedLoginReset=0 notGuessablePattern=0
Although these options, by name, are fairly self explanatory it is worth noting that each of the above is explained in more detail in the pwpolicy man page.  Once you have the policies that you would like to set you can then use the -setglobalpolicy option followed by the options that you would like to set.  These options would have a space between each with quotes surrounding the full array.  For example, the following pwpolicy command would set up a policy to change the password every 30 days, with each password having a minimum length of 8 characters, requiring at least one letter and at least one number and would force you to use a password that is different from the last 3 passwords:
pwpolicy -n /Local/Default -setglobalpolicy “minChars=8 requiresAlpha=1 requiresNumeric=1 maxMinutesUntilChangePassword=43200 usingHistory=3 maxFailedLoginAttempts=0”

The pwpolicy can also be used on specific accounts using the -u option in place of the -setglobalpolicy or -getglobalpolicy options.  To see the policies in force for a given account use the -get policy along with the -u followed by the account name, as follows:

pwpolicy -u cedge -getpolicy

For example, you can quickly disable a local account with the following command:

pwpolicy -u cedge -setpolicy isdisabled

Or if you’d rather make that user an administrator:

pwpolicy -u cedge -setpolicy isadminuser

To set that user with the same policies that were indicated in the previous -setglobalpolicy command:

pwpolicy -u cedge -setpolicy “minChars=8 requiresAlpha=1 requiresNumeric=1 maxMinutesUntilChangePassword=43200 usingHistory=3 maxFailedLoginAttempts=0”

Once you start setting global and user policies you’re bound to run into conflicts.  Use the –get-effective-policy to troubleshoot as needed, as follows:

pwpolicy -u cedge –get-effective-policy

Because it’s fairly simple to set policies, if you don’t place them into your image and you don’t have Open Directory then you can still use them by wrapping your required policies into a login hook that runs sudo’d as the user.