#!/bin/bash

## Copyright (C) 2019 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

## This is only a usability feature to avoid needlessly bumping pam_faillock
## counter. This is not a security feature.
## https://forums.whonix.org/t/restrict-root-access/7658/1

set -o errexit
set -o nounset
set -o pipefail
set -o errtrace
shopt -s inherit_errexit
shopt -s shift_verbose

PAM_USER="${PAM_USER:-}"

passwd_bin="$(type -P -- "passwd")"

if ! test -x "${passwd_bin}" ; then
   printf '%s\n' "\
$0: ERROR: passwd_bin \"${passwd_bin}\" is not executable.
See https://www.kicksecure.com/wiki/SUID_Disabler_and_Permission_Hardener#passwd" >&2
   ## Identifiable exit codes in case stdout / stderr is not logged in journal.
   exit 2
fi

if ! passwd_output="$("${passwd_bin}" -S -- "${PAM_USER}" 2>/dev/null)" ; then
   printf '%s\n' "$0: ERROR: user \"${PAM_USER}\" does not exist." >&2
   exit 3
fi

password_status_field="$(printf '%s\n' "${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
   printf '%s\n' "$0: INFO: Password for user \"${PAM_USER}\" is locked."

   if [ -f /usr/share/whonix/marker ] || [ -f /usr/share/kicksecure/marker ]; then
      if [ "${PAM_USER}" = "root" ]; then
         printf '%s\n' "$0: ERROR: root account is locked by default. See:" >&2
         printf '%s\n' "https://www.kicksecure.com/wiki/root" >&2
         printf '%s\n' "" >&2
         exit 4
      fi
   fi

   ## Should not unconditionally 'exit 1' here.
   ## Locked user accounts might have valid sudoers exceptions.
   ## https://forums.whonix.org/t/pam-abort-on-locked-password-and-running-privileged-command-from-web-browser/10521
   ## '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
   printf '%s\n' "$0: INFO: Password status field for user \"${PAM_USER}\" could not be parsed. Please report this bug."
fi

exit 0
