Password change script

rhooper
Contributor III

Greetings JAMF'rs, We are trying to allow standard users to change their passwords, but first you some background: We have re-imaged each machine in our school, setup each account to be assured that each device has hit the JSS Server, setup the account with one standard password(not very secure though), and have Users & Groups, Sharing and Security & Privacy blocked in Sys Prefs.

We are trying to find a script, JAMF sent one option, that asks each user to change their password on their initial login. Problem is, the password can be the same one as before. I would love a script to enforce complexity rules (Alphanumeric, with at least 1 Symbol, Uppercase, and Lowercase and a Number, with minimum of 8 characters)
Has anyone had any success with doing this?
I am not a scripter but I can follow along what is occurring within the script, just no luck in making my basic script work correctly.
Thanks all for any and all help you can send out.
R

1 ACCEPTED SOLUTION

rhooper
Contributor III

@Gachowski the script sent seemed to work, but only on one of the 2 devices. After a reimage the script does not work at all, even though it says it is completed.
The script used is:

!/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="KIDSRSU.org" # CHANGE THIS TO YOUR COMPANY NAME

LOCKOUT=300 # 5min lockout

MAX_FAILED=10 # 10 max failed logins before locking

PW_EXPIRE=365 # 90 days password expiration, changed to 365 days - rhoooper081817
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=0 # at least one special character in password, chnaged to zero -RHooper 081817

PW_HISTORY=10 # remember last 10 passwords

exemptAccount1="RSU2Admin" #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 &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>policyCategoryPasswordChange</key> <array> <dict> <key>policyContent</key> <string>policyAttributeCurrentTime &gt; 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

View solution in original post

4 REPLIES 4

antonio_ong
New Contributor

Have you thought of using the config profile for enforcing password complexity?

Also if you can pass the script from jamf we can have a crack at it.

gachowski
Valued Contributor II

So like Antonio_ong said use profiles they are the easiest and Apple 1st choice.. Here is the second Apple "way"

https://www.jamf.com/jamf-nation/discussions/18574/user-password-policies-on-non-ad-machines

and how to force a password change..

#!/bin/sh
pwpolicy -u $3 -setpolicy "newPasswordRequired=1"

C

rhooper
Contributor III

Thanks #antonio_ong for the update.
Thanks #gachowskiI will have to look at that link.

Sorry I forgot to add the script being used: 'pwpolicy -setglobalpolicy "newPasswordRequired=1" ; sudo pkill loginwindow'

We had to use globalpolicy as the other method did not prompt at all for a password change. The other item I noticed was it also asks for the hidden admin to change their password as well if they log into the device.

The complexity, the only location I have seen that to be set is in pre-stage. Is there another location?

rhooper
Contributor III

@Gachowski the script sent seemed to work, but only on one of the 2 devices. After a reimage the script does not work at all, even though it says it is completed.
The script used is:

!/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="KIDSRSU.org" # CHANGE THIS TO YOUR COMPANY NAME

LOCKOUT=300 # 5min lockout

MAX_FAILED=10 # 10 max failed logins before locking

PW_EXPIRE=365 # 90 days password expiration, changed to 365 days - rhoooper081817
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=0 # at least one special character in password, chnaged to zero -RHooper 081817

PW_HISTORY=10 # remember last 10 passwords

exemptAccount1="RSU2Admin" #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 &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>policyCategoryPasswordChange</key> <array> <dict> <key>policyContent</key> <string>policyAttributeCurrentTime &gt; 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