#!/bin/bash
# howdy-authselect - Enable/disable howdy face authentication in PAM
#
# WARNING: This is a gruesome AI-dreamed hack.
#
# Fedora's authselect has an "all or nothing" profile problem - you cannot
# extend profiles, only replace them entirely. Rather than maintaining full
# copies of upstream profiles just to add one PAM module, this script patches
# pam_howdy.so into the existing authselect-managed configuration.
#
# It can be run manually or triggered automatically via systemd path unit.

set -euo pipefail

# Both files need patching: system-auth (sudo, etc) and password-auth (GDM, login)
AUTH_FILES=(
    "/etc/authselect/system-auth"
    "/etc/authselect/password-auth"
)
PAM_HOWDY="/usr/lib64/security/pam_howdy.so"
HOWDY_LINE="auth        sufficient                                   pam_howdy.so"
# Insert after this pattern (pam_faillock preauth line or early auth line)
INSERT_AFTER="pam_faillock.so preauth"

usage() {
    cat <<EOF
Usage: howdy-authselect [enable|disable|status]

Commands:
  enable   Add pam_howdy.so to PAM configuration (system-auth and password-auth)
  disable  Remove pam_howdy.so from PAM configuration
  status   Show whether howdy is currently enabled in PAM

This tool patches the authselect-managed PAM configuration to enable
face authentication via howdy. Run this after 'authselect select' to
re-enable howdy, or use the systemd service for automatic patching.
EOF
}

check_root() {
    if [[ $EUID -ne 0 ]]; then
        echo "Error: This script must be run as root" >&2
        exit 1
    fi
}

check_pam_module() {
    if [[ ! -f "$PAM_HOWDY" ]]; then
        echo "Error: pam_howdy.so not found at $PAM_HOWDY" >&2
        echo "Please install the howdy package first." >&2
        exit 1
    fi
}

check_authselect() {
    for auth_file in "${AUTH_FILES[@]}"; do
        if [[ ! -f "$auth_file" ]]; then
            echo "Error: $auth_file not found" >&2
            echo "authselect does not appear to be managing PAM configuration." >&2
            exit 1
        fi
    done
}

is_howdy_enabled_in_file() {
    local file="$1"
    grep -q "pam_howdy.so" "$file" 2>/dev/null
}

is_howdy_enabled() {
    # Check if enabled in all files
    for auth_file in "${AUTH_FILES[@]}"; do
        if ! is_howdy_enabled_in_file "$auth_file"; then
            return 1
        fi
    done
    return 0
}

enable_file() {
    local auth_file="$1"

    if is_howdy_enabled_in_file "$auth_file"; then
        echo "howdy already enabled in $(basename "$auth_file")"
        return 0
    fi

    # Create backup
    cp "$auth_file" "${auth_file}.bak"

    # Insert howdy line after pam_faillock preauth (or after pam_faildelay if no faillock)
    if grep -q "$INSERT_AFTER" "$auth_file"; then
        sed -i "/$INSERT_AFTER/a\\$HOWDY_LINE" "$auth_file"
    else
        # Fallback: insert after pam_faildelay
        sed -i "/pam_faildelay.so/a\\$HOWDY_LINE" "$auth_file"
    fi

    if is_howdy_enabled_in_file "$auth_file"; then
        echo "howdy enabled in $(basename "$auth_file")"
    else
        echo "Error: Failed to enable howdy in $auth_file" >&2
        mv "${auth_file}.bak" "$auth_file"
        return 1
    fi
}

disable_file() {
    local auth_file="$1"

    if ! is_howdy_enabled_in_file "$auth_file"; then
        echo "howdy not enabled in $(basename "$auth_file")"
        return 0
    fi

    # Create backup
    cp "$auth_file" "${auth_file}.bak"

    # Remove howdy line
    sed -i '/pam_howdy.so/d' "$auth_file"

    if ! is_howdy_enabled_in_file "$auth_file"; then
        echo "howdy disabled in $(basename "$auth_file")"
    else
        echo "Error: Failed to disable howdy in $auth_file" >&2
        mv "${auth_file}.bak" "$auth_file"
        return 1
    fi
}

enable_howdy() {
    check_root
    check_pam_module
    check_authselect

    local failed=0
    for auth_file in "${AUTH_FILES[@]}"; do
        enable_file "$auth_file" || failed=1
    done

    if [[ $failed -eq 0 ]]; then
        echo "howdy enabled successfully in PAM configuration"
    else
        echo "Error: Failed to enable howdy in some files" >&2
        exit 1
    fi
}

disable_howdy() {
    check_root
    check_authselect

    local failed=0
    for auth_file in "${AUTH_FILES[@]}"; do
        disable_file "$auth_file" || failed=1
    done

    if [[ $failed -eq 0 ]]; then
        echo "howdy disabled successfully in PAM configuration"
    else
        echo "Error: Failed to disable howdy in some files" >&2
        exit 1
    fi
}

show_status() {
    check_authselect

    for auth_file in "${AUTH_FILES[@]}"; do
        if is_howdy_enabled_in_file "$auth_file"; then
            echo "$(basename "$auth_file"): ENABLED"
        else
            echo "$(basename "$auth_file"): DISABLED"
        fi
    done
}

case "${1:-}" in
    enable)
        enable_howdy
        ;;
    disable)
        disable_howdy
        ;;
    status)
        show_status
        ;;
    -h|--help|help)
        usage
        ;;
    *)
        usage
        exit 1
        ;;
esac
