Limit Password Reuse

Classification:

compliance

Framework:

Control:

Description

Do not allow users to reuse recent passwords. This can be accomplished by using the remember option for the pam_pwhistory PAM modules.

In the file /etc/pam.d/common-password, make sure the parameters remember and use_authtok are present, and that the value for the remember parameter is 5 or greater. For example:

password requisite pam_pwhistory.so *...existing\_options...* remember=5 use_authtok

The DoD STIG requirement is 5 passwords.

Rationale

Preventing re-use of previous passwords helps ensure that a compromised password is not re-used by a user.

Remediation

Shell script

The following script can be run on the host to remediate the issue.

# Remediation is applicable only in certain platforms
if dpkg-query --show --showformat='${db:Status-Status}\n' 'libpam-runtime' 2>/dev/null | grep -q installed; then

declare -a VALUES=()
declare -a VALUE\_NAMES=()
declare -a ARGS=()
declare -a NEW\_ARGS=()

var\_password\_pam\_remember='5'

VALUES+=("$var\_password\_pam\_remember")
VALUE\_NAMES+=("remember")
ARGS+=("")
NEW\_ARGS+=("")
VALUES+=("")
VALUE\_NAMES+=("")
ARGS+=("use\_authtok")
NEW\_ARGS+=("use\_authtok")

for idx in "${!VALUES[@]}"
do
 if [ -e "/etc/pam.d/common-password" ] ; then
 valueRegex="${VALUES[$idx]}" defaultValue="${VALUES[$idx]}"
 # non-empty values need to be preceded by an equals sign
 [ -n "${valueRegex}" ] && valueRegex="=${valueRegex}"
 # add an equals sign to non-empty values
 [ -n "${defaultValue}" ] && defaultValue="=${defaultValue}"

 # fix the value for 'option' if one exists but does not match 'valueRegex'
 if grep -q -P "^\\s\*password\\s+requisite\\s+pam\_pwhistory.so(\\s.+)?\\s+${VALUE\_NAMES[$idx]}(?"'!'"${valueRegex}(\\s|\$))" < "/etc/pam.d/common-password" ; then
 sed --follow-symlinks -i -E -e "s/^(\\s\*password\\s+requisite\\s+pam\_pwhistory.so(\\s.+)?\\s)${VALUE\_NAMES[$idx]}=[^[:space:]]\*/\\1${VALUE\_NAMES[$idx]}${defaultValue}/" "/etc/pam.d/common-password"

 # add 'option=default' if option is not set
 elif grep -q -E "^\\s\*password\\s+requisite\\s+pam\_pwhistory.so" < "/etc/pam.d/common-password" &&
 grep -E "^\\s\*password\\s+requisite\\s+pam\_pwhistory.so" < "/etc/pam.d/common-password" | grep -q -E -v "\\s${VALUE\_NAMES[$idx]}(=|\\s|\$)" ; then

 sed --follow-symlinks -i -E -e "s/^(\\s\*password\\s+requisite\\s+pam\_pwhistory.so[^\\n]\*)/\\1 ${VALUE\_NAMES[$idx]}${defaultValue}/" "/etc/pam.d/common-password"
 # add a new entry if none exists
 elif ! grep -q -P "^\\s\*password\\s+requisite\\s+pam\_pwhistory.so(\\s.+)?\\s+${VALUE\_NAMES[$idx]}${valueRegex}(\\s|\$)" < "/etc/pam.d/common-password" ; then
 echo "password requisite pam\_pwhistory.so ${VALUE\_NAMES[$idx]}${defaultValue}" >> "/etc/pam.d/common-password"
 fi
 else
 echo "/etc/pam.d/common-password doesn't exist" >&2
 fi
done

for idx in "${!ARGS[@]}"
do
 if ! grep -q -P "^\s\*password\s+requisite\s+pam\_pwhistory.so.\*\s+${ARGS[$idx]}\s\*$" /etc/pam.d/common-password ; then
 sed --follow-symlinks -i -E -e "s/^\\s\*password\\s+requisite\\s+pam\_pwhistory.so.\*\$/& ${NEW\_ARGS[$idx]}/" /etc/pam.d/common-password
 fi
done

else
 >&2 echo 'Remediation is not applicable, nothing was done'
fi