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