diff --git a/debian/security-misc-shared.install b/debian/security-misc-shared.install index 9ae61fb..e9e0dd7 100755 --- a/debian/security-misc-shared.install +++ b/debian/security-misc-shared.install @@ -56,6 +56,7 @@ usr/libexec/security-misc/disable-kernel-module-loading#security-misc-shared => usr/libexec/security-misc/hide-hardware-info#security-misc-shared => /usr/libexec/security-misc/hide-hardware-info usr/libexec/security-misc/virusforget#security-misc-shared => /usr/libexec/security-misc/virusforget usr/libexec/security-misc/pam_faillock_not_if_x#security-misc-shared => /usr/libexec/security-misc/pam_faillock_not_if_x +usr/libexec/security-misc/block-unsafe-logins#security-misc-shared => /usr/libexec/security-misc/block-unsafe-logins usr/src/security-misc/emerg-shutdown.c#security-misc-shared => /usr/src/security-misc/emerg-shutdown.c usr/bin/disabled-gps-by-security-misc#security-misc-shared => /usr/bin/disabled-gps-by-security-misc usr/bin/disabled-netfilesys-by-security-misc#security-misc-shared => /usr/bin/disabled-netfilesys-by-security-misc @@ -129,6 +130,7 @@ usr/share/pam-configs/unix-faillock-security-misc#security-misc-shared => /usr/s usr/share/pam-configs/console-lockdown-security-misc#security-misc-shared => /usr/share/pam-configs/console-lockdown-security-misc usr/share/pam-configs/mkhomedir-security-misc#security-misc-shared => /usr/share/pam-configs/mkhomedir-security-misc usr/share/pam-configs/pam-abort-on-locked-password-security-misc#security-misc-shared => /usr/share/pam-configs/pam-abort-on-locked-password-security-misc +usr/share/pam-configs/block-unsafe-logins-security-misc#security-misc-shared => /usr/share/pam-configs/block-unsafe-logins-security-misc usr/share/lintian/overrides/security-misc-shared#security-misc-shared => /usr/share/lintian/overrides/security-misc-shared usr/share/security-misc/lkrg/30-lkrg-virtualbox.conf#security-misc-shared => /usr/share/security-misc/lkrg/30-lkrg-virtualbox.conf usr/share/security-misc/lkrg/lkrg-virtualbox#security-misc-shared => /usr/share/security-misc/lkrg/lkrg-virtualbox diff --git a/usr/libexec/security-misc/block-unsafe-logins#security-misc-shared b/usr/libexec/security-misc/block-unsafe-logins#security-misc-shared new file mode 100755 index 0000000..c565daa --- /dev/null +++ b/usr/libexec/security-misc/block-unsafe-logins#security-misc-shared @@ -0,0 +1,107 @@ +#!/bin/bash + +## Copyright (C) 2025 - 2025 ENCRYPTED SUPPORT LLC +## See the file COPYING for copying conditions. + +set -o errexit +set -o nounset +set -o errtrace +set -o pipefail + +if [ -z "${PAM_USER:-}" ]; then + true "$0: ERROR: Environment variable PAM_USER is unset!" + exit 0 +fi + +kernel_cmdline='' +if [ -r /proc/cmdline ]; then + kernel_cmdline="$(cat /proc/cmdline)" +elif [ -r /proc/1/cmdline ]; then + kernel_cmdline="$(cat /proc/1/cmdline)" +fi + +if [[ "$kernel_cmdline" =~ 'boot-role=sysmaint' ]]; then + if [ "$PAM_USER" != 'sysmaint' ]; then + printf '%s\n' 'ERROR: Rejecting non-sysmaint account in sysmaint mode!' + exit 1 + fi + true 'INFO: Running in sysmaint mode and logging into sysmaint account, allowing authentication to proceed.' + exit 0 +else + if ! output="$(/usr/libexec/helper-scripts/get-user-list)"; then + printf '%s\n' 'ERROR: Failed to get user list!' + exit 1 + fi + readarray -t user_list <<< "$output" + if [ "${#user_list[@]}" = '0' ] || [ -z "${user_list[0]}" ]; then + printf '%s\n' 'ERROR: No user accounts found!' + exit 1 + fi + + ## Minor race condition here, quick deletion of users during this process + ## could result in user_list and passwd_status_list becoming misaligned. This + ## attack would require root privileges to execute though, so this is likely + ## not a concern. We do this before checking if $PAM_USER is in the list of + ## interactive users to keep the race window as short as possible. + if ! output="$(/usr/libexec/helper-scripts/get-password-status-list)"; then + printf '%s\n' 'ERROR: Failed to get password status list!' + eixt 1 + fi + readarray -t passwd_status_list <<< "$output" + if [ "${#passwd_status_list[@]}" = '0' ] \ + || [ -z "${passwd_status_list[0]}" ] \ + || (( ${#passwd_status_list[@]} != ${#user_list[@]} )); then + printf '%s\n' 'ERROR: Unexpected number of password status entries!' + exit 1 + fi + + if [ "$PAM_USER" = 'sysmaint' ]; then + printf '%s\n' 'ERROR: Rejecting sysmaint account in user mode!' + exit 1 + fi + + interactive_user_idx='-1' + for user_idx in "${!user_list[@]}"; do + if [ "${user_list[user_idx]}" = "$PAM_USER" ]; then + interactive_user_idx="$user_idx" + break + fi + done + if [ "$interactive_user_idx" = '-1' ]; then + ## This isn't a user account we care about (it's not an interactive + ## account), therefore allow authentication to proceed. + true "INFO: Account '$PAM_USER' is not an interactive account, allowing authentication to proceed." + exit 0 + fi + + IFS=' ' read -r -a user_gid_list < <(id -G "$PAM_USER") + sensitive_group_list=( 'sudo' 'root' 'sysmaint' ) + is_user_sensitive='false' + + for sensitive_group in "${sensitive_group_list[@]}"; do + sensitive_gid="$(accountctl "$sensitive_group" get-entry group gid)" + for user_gid in "${user_gid_list[@]}"; do + if [ "$sensitive_gid" = "$user_gid" ]; then + is_user_sensitive='true' + break + fi + done + if [ "$is_user_sensitive" = 'true' ]; then + break + fi + done + + if [ "$is_user_sensitive" = 'true' ]; then + if [ "${passwd_status_list[interactive_user_idx]}" = 'Absent' ]; then + ## User account is sensitive and passwordless, deny authentication + printf '%s\n' "ERROR: Rejecting passwordless sensitive account '$PAM_USER'!" + exit 1 + else + true "INFO: Account '$PAM_USER' is sensitive but protected, allowing authentication to proceed." + exit 0 + fi + fi + + true "INFO: Account '$PAM_USER' is not sensitive, allowing authentication to proceed." + exit 0 +fi diff --git a/usr/share/pam-configs/block-unsafe-logins-security-misc#security-misc-shared b/usr/share/pam-configs/block-unsafe-logins-security-misc#security-misc-shared new file mode 100644 index 0000000..eec6702 --- /dev/null +++ b/usr/share/pam-configs/block-unsafe-logins-security-misc#security-misc-shared @@ -0,0 +1,6 @@ +Name: block unsafe passwordless login (by package security-misc-shared) +Default: yes +Priority: 1100 +Auth-Type: Primary +Auth: + requisite pam_exec.so seteuid stdout /usr/libexec/security-misc/block-unsafe-logins