diff --git a/debian/security-misc.displace b/debian/security-misc.displace
index 06b6187..b7cba93 100644
--- a/debian/security-misc.displace
+++ b/debian/security-misc.displace
@@ -2,4 +2,5 @@
## See the file COPYING for copying conditions.
/etc/securetty.security-misc
+/etc/security/faillock.conf.security-misc
/etc/dkms/framework.conf.security-misc
diff --git a/etc/security/faillock.conf.security-misc b/etc/security/faillock.conf.security-misc
new file mode 100644
index 0000000..bb81754
--- /dev/null
+++ b/etc/security/faillock.conf.security-misc
@@ -0,0 +1,62 @@
+# Configuration for locking the user after multiple failed
+# authentication attempts.
+#
+# The directory where the user files with the failure records are kept.
+# The default is /var/run/faillock.
+# dir = /var/run/faillock
+#
+# Will log the user name into the system log if the user is not found.
+# Enabled if option is present.
+audit
+#
+# Don't print informative messages.
+# Enabled if option is present.
+# silent
+#
+# Don't log informative messages via syslog.
+# Enabled if option is present.
+# no_log_info
+#
+# Only track failed user authentications attempts for local users
+# in /etc/passwd and ignore centralized (AD, IdM, LDAP, etc.) users.
+# The `faillock` command will also no longer track user failed
+# authentication attempts. Enabling this option will prevent a
+# double-lockout scenario where a user is locked out locally and
+# in the centralized mechanism.
+# Enabled if option is present.
+# local_users_only
+#
+# Deny access if the number of consecutive authentication failures
+# for this user during the recent interval exceeds n tries.
+# The default is 3.
+deny = 50
+#
+# The length of the interval during which the consecutive
+# authentication failures must happen for the user account
+# lock out is n seconds.
+# The default is 900 (15 minutes).
+# fail_interval = 900
+#
+# The access will be re-enabled after n seconds after the lock out.
+# The value 0 has the same meaning as value `never` - the access
+# will not be re-enabled without resetting the faillock
+# entries by the `faillock` command.
+# The default is 600 (10 minutes).
+# unlock_time = 600
+#
+# Root account can become locked as well as regular accounts.
+# Enabled if option is present.
+even_deny_root
+#
+# This option implies the `even_deny_root` option.
+# Allow access after n seconds to root account after the
+# account is locked. In case the option is not specified
+# the value is the same as of the `unlock_time` option.
+# root_unlock_time = 900
+#
+# If a group name is specified with this option, members
+# of the group will be handled by this module the same as
+# the root account (the options `even_deny_root>` and
+# `root_unlock_time` will apply to them.
+# By default, the option is not set.
+# admin_group =
diff --git a/usr/libexec/security-misc/pam-abort-on-locked-password b/usr/libexec/security-misc/pam-abort-on-locked-password
index d8f1888..1fc8013 100755
--- a/usr/libexec/security-misc/pam-abort-on-locked-password
+++ b/usr/libexec/security-misc/pam-abort-on-locked-password
@@ -22,9 +22,13 @@ if ! passwd_output="$("$passwd_bin" -S "$PAM_USER" 2>/dev/null)" ; then
exit 3
fi
-if [ "$(echo "$passwd_output" | cut -d ' ' -f 2)" = "P" ]; then
- true "INFO: Password not locked."
-else
+password_status_field="$(echo "$passwd_output" | cut -d ' ' -f 2)"
+
+if [ "$password_status_field" = "P" ]; then
+ true "$0: INFO: user \"$PAM_USER\" has a usable password."
+elif [ "$password_status_field" = "NP" ]; then
+ true "$0: INFO: user \"$PAM_USER\" has no password."
+elif [ "$password_status_field" = "L" ]; then
echo "$0: INFO: Password for user \"$PAM_USER\" is locked."
if [ -f /usr/share/whonix/marker ] || [ -f /usr/share/kicksecure/marker ]; then
@@ -42,6 +46,8 @@ else
## 'exit 1' would be good for usability here because then the user would get
## faster feedback. A new login attempt would not be needlessly delayed.
exit 0
+else
+ echo "$0: INFO: Password status field for user \"$PAM_USER\" could not be parsed. Please report this bug."
fi
exit 0
diff --git a/usr/libexec/security-misc/pam-info b/usr/libexec/security-misc/pam-info
index 2bb7461..1c69845 100755
--- a/usr/libexec/security-misc/pam-info
+++ b/usr/libexec/security-misc/pam-info
@@ -43,9 +43,9 @@ fi
if [ ! "$(id -u)" = "0" ]; then
## as user "user"
- ## /sbin/pam_faillock -u user
- ## pam_faillock: Error opening /var/log/tallylog for update: Permission denied
- ## /sbin/pam_faillock: Authentication error
+ ## /usr/sbin/faillock -u user
+ ## faillock: Error opening /var/log/tallylog for update: Permission denied
+ ## /usr/sbin/faillock: Authentication error
##
## xscreensaver runs as user "user", therefore pam_faillock cannot function.
## xscreensaver has its own failed login counter.
@@ -53,7 +53,8 @@ if [ ! "$(id -u)" = "0" ]; then
## https://askubuntu.com/questions/983183/how-lock-the-unlock-screen-after-wrong-password-attempts
##
## https://www.whonix.org/pipermail/whonix-devel/2019-September/001439.html
- true "$0: not started as root, exiting."
+ ## TODO: echo -> true
+ echo "$0: not started as root, exiting."
exit 0
fi
@@ -74,7 +75,7 @@ fi
# fi
## Using || true to not break read-only disk boot without ro-mode-init or grub-live.
-pam_faillock_output="$(pam_faillock --user "$PAM_USER")" || true
+pam_faillock_output="$(faillock --user "$PAM_USER")" || true
if [ "$pam_faillock_output" = "" ]; then
true "$0: no failed login"
@@ -82,16 +83,17 @@ if [ "$pam_faillock_output" = "" ]; then
fi
## Example:
-#Login Failures Latest failure From
-#user 0
+## user:
+## When Type Source Valid
+## 2021-08-10 16:26:33 RHOST V
+## 2021-08-10 16:26:54 RHOST V
-pam_faillock_output_last_line="$(echo "$pam_faillock_output" | tail -1)"
-## Example:
-#user 0
+pam_faillock_output_first_line="$(echo "$pam_faillock_output" | head -1)"
+user_name="$(echo "$pam_faillock_output_first_line" | str_replace ":" "")"
-arr=($pam_faillock_output_last_line)
-user_name="${arr[0]}"
-failed_login_counter="${arr[1]}"
+pam_faillock_output_count="$(echo "$pam_faillock_output" | wc -l)"
+
+failed_login_counter=$(( pam_faillock_output_count - 2 ))
if [ ! "$PAM_USER" = "$user_name" ]; then
echo "$0: ERROR: PAM_USER: '$PAM_USER' does not equal user_name: '$user_name'." >&2
@@ -105,19 +107,18 @@ if [ "$failed_login_counter" = "0" ]; then
exit 0
fi
-deny_line="$(cat /etc/pam.d/common-auth | grep deny=)"
-## Example:
-#auth requisite pam_faillock.so even_deny_root deny=50 onerr=fail audit debug
+## pam_faillock default
+deny=3
-for word in $deny_line ; do
- if echo "$word" | grep -q "deny=" ; then
- deny="$(echo "$word" | cut -d "=" -f 2)"
- break
- fi
-done
+if test -f /etc/security/faillock.conf ; then
+ deny_line=$(grep --invert-match "#" /etc/security/faillock.conf | grep "deny =")
+ deny="$(echo "$deny_line" | str_replace "=" "" | str_replace "deny" "" | str_replace " " "")"
+ ## Example:
+ #deny=50
+fi
if [[ "$deny" == *[!0-9]* ]]; then
- echo "$0: ERROR: deny is not numeric." >&2
+ echo "$0: ERROR: deny is not numeric. deny: '$deny'" >&2
echo "$0: ERROR: Please report this bug." >&2
echo "" >&2
exit 0
@@ -130,7 +131,7 @@ if [ "$remaining_attempts" -le "0" ]; then
echo "$0: To unlock, run the following command as superuser:" >&2
echo "$0: (If you still have a sudo/root shell somewhere.)" >&2
echo "" >&2
- echo "pam_faillock --quiet -r --user $PAM_USER" >&2
+ echo "faillock --reset --user $PAM_USER" >&2
echo "" >&2
echo "$0: However, most likely unlock procedure is required." >&2
echo "$0: First boot into recovery mode at grub boot menu and then run above command." >&2
diff --git a/usr/share/pam-configs/faillock-security-misc b/usr/share/pam-configs/faillock-security-misc
index 0f88f53..d337690 100644
--- a/usr/share/pam-configs/faillock-security-misc
+++ b/usr/share/pam-configs/faillock-security-misc
@@ -1,11 +1,11 @@
-Name: lock accounts after 50 failed authentication attempts (by package security-misc)
+Name: lock accounts after 50 failed authentication attempts (part 1) (by package security-misc)
Default: yes
Priority: 290
Auth-Type: Primary
Auth:
optional pam_exec.so debug stdout seteuid /usr/libexec/security-misc/pam-info
[success=1 default=ignore] pam_exec.so seteuid quiet /usr/libexec/security-misc/pam_faillock_not_if_x
- requisite pam_faillock.so even_deny_root deny=50 onerr=fail audit debug
+ required pam_faillock.so preauth
Account-Type: Primary
Account:
- requisite pam_faillock.so debug
+ requisite pam_faillock.so
diff --git a/usr/share/pam-configs/faillock2-security-misc b/usr/share/pam-configs/faillock2-security-misc
new file mode 100644
index 0000000..f5eb508
--- /dev/null
+++ b/usr/share/pam-configs/faillock2-security-misc
@@ -0,0 +1,7 @@
+Name: lock accounts after 50 failed authentication attempts (part 2) (by package security-misc)
+Default: yes
+Priority: 245
+Auth-Type: Primary
+Auth:
+ [default=die] pam_faillock.so authfail
+ sufficient pam_faillock.so authsucc