#!/bin/bash

echo "--- Security Configuration Check Script (Read-Only) ---"
echo "This script checks password complexity, account lockout, and password expiry settings."
echo "It does NOT modify any configuration files."
echo

# Check for root privileges (needed for chage -l on other users and potentially reading some files)
if [ "$EUID" -ne 0 ]; then
  echo "Warning: Running without root privileges. Some checks (like other users' expiry) might fail."
  echo "It's recommended to run this script using 'sudo'."
  echo
fi

# --- 1. Password Complexity Check (/etc/security/pwquality.conf) ---
echo "[1] Checking Password Complexity Settings..."
PWQUALITY_CONF="/etc/security/pwquality.conf"

if [ -f "$PWQUALITY_CONF" ]; then
  echo "  Configuration file: $PWQUALITY_CONF"
  
  # Helper function to check and print parameter value
  check_pw_param() {
    local param_name=$1
    local file=$2
    local value=$(grep "^${param_name}=" "$file" | cut -d'=' -f2 | tr -d ' ')
    if [ -n "$value" ]; then
      echo "    - $param_name: $value"
    else
      local commented_value=$(grep "^#\s*${param_name}=" "$file" | cut -d'=' -f2 | tr -d ' ')
      if [ -n "$commented_value" ]; then
         echo "    - $param_name: Not set (Default or commented out: $commented_value)"
      else
         echo "    - $param_name: Not set"
      fi
    fi
  }
  
  # Helper function for boolean-like parameters (e.g., dictcheck=1)
  check_pw_flag_param() {
      local param_name=$1
      local file=$2
      local line=$(grep "^${param_name}" "$file")
       if [[ -n "$line" && ! "$line" =~ ^# ]]; then
           local value=$(echo "$line" | cut -d'=' -f2 | tr -d ' ')
           if [ "$value" == "1" ]; then
                echo "    - $param_name: Enabled (Value: $value)"
           else
                echo "    - $param_name: Explicitly set (Value: $value) - Check documentation if '1' expected"
           fi
       elif [[ -n "$line" && "$line" =~ ^# ]]; then
            echo "    - $param_name: Disabled (Commented out)"
       else
            echo "    - $param_name: Not explicitly set (Using default)"
       fi
  }

  # Check specific parameters
  check_pw_param "minlen" "$PWQUALITY_CONF"
  check_pw_param "minclass" "$PWQUALITY_CONF"
  check_pw_flag_param "dictcheck" "$PWQUALITY_CONF"
  check_pw_flag_param "usercheck" "$PWQUALITY_CONF"
  check_pw_flag_param "palindrome" "$PWQUALITY_CONF" # Assuming 'palindrome=1' means enabled

  # Check similarcheck (logic is slightly different due to #no_similar_check)
  if grep -q "^#no_similar_check" "$PWQUALITY_CONF"; then
      echo "    - similar_check: Enabled (via '#no_similar_check')"
  elif grep -q "^no_similar_check" "$PWQUALITY_CONF"; then
       echo "    - similar_check: Disabled (via 'no_similar_check')"
  elif grep -q "^similarcheck=" "$PWQUALITY_CONF"; then
        check_pw_flag_param "similarcheck" "$PWQUALITY_CONF"
  else
       echo "    - similar_check: Not explicitly set (Using default)"
  fi

else
  echo "  Error: Configuration file $PWQUALITY_CONF not found."
fi
echo

# --- 2. Account Lockout Check (/etc/pam.d/common-auth) ---
echo "[2] Checking Account Lockout Settings..."
# Note: The exact PAM file can vary (common-auth, system-auth, password-auth)
PAM_FILES=("/etc/pam.d/common-auth" "/etc/pam.d/system-auth" "/etc/pam.d/password-auth")
FOUND_PAM_LOCKOUT=false

for PAM_FILE in "${PAM_FILES[@]}"; do
  if [ -f "$PAM_FILE" ]; then
    echo "  Checking file: $PAM_FILE"
    # Look for pam_unix.so with lockout parameters
    PAM_UNIX_LINE=$(grep "pam_unix.so" "$PAM_FILE" | grep -v "^#")
    if echo "$PAM_UNIX_LINE" | grep -q "deny="; then
      echo "    Found pam_unix.so lockout settings:"
      LOCKOUT_PARAMS=$(echo "$PAM_UNIX_LINE" | grep -oE 'deny=[0-9]+|unlock_time=[0-9]+|root_unlock_time=[0-9]+')
      if [ -n "$LOCKOUT_PARAMS" ]; then
           echo "      Parameters: $LOCKOUT_PARAMS"
      else
           echo "      Parameters found, but format differs. Line:"
           echo "        $PAM_UNIX_LINE"
      fi
      FOUND_PAM_LOCKOUT=true
      # break # Uncomment if you only want the first finding
    fi

    # Also check for pam_faillock.so or pam_tally2.so as common alternatives
    PAM_FAILLOCK_LINE=$(grep "pam_faillock.so" "$PAM_FILE" | grep -v "^#")
     if [ -n "$PAM_FAILLOCK_LINE" ]; then
        echo "    Found pam_faillock.so settings (alternative lockout mechanism):"
        echo "      Line: $PAM_FAILLOCK_LINE"
        FOUND_PAM_LOCKOUT=true
     fi
     PAM_TALLY2_LINE=$(grep "pam_tally2.so" "$PAM_FILE" | grep -v "^#")
     if [ -n "$PAM_TALLY2_LINE" ]; then
        echo "    Found pam_tally2.so settings (older lockout mechanism):"
        echo "      Line: $PAM_TALLY2_LINE"
        FOUND_PAM_LOCKOUT=true
     fi

  else
    echo "  Info: File $PAM_FILE not found, skipping."
  fi
done

if [ "$FOUND_PAM_LOCKOUT" = false ]; then
  echo "  No common PAM lockout settings (deny= on pam_unix.so, pam_faillock.so, pam_tally2.so) found in checked files."
fi
echo

# --- 3. Password Expiry Check ---
echo "[3] Checking Password Expiry Settings..."

# 3a. Default settings for new users (/etc/login.defs)
echo "  Checking defaults for new users (/etc/login.defs):"
LOGIN_DEFS_FILE="/etc/login.defs"
if [ -f "$LOGIN_DEFS_FILE" ]; then
  MAX_DAYS=$(grep -E "^PASS_MAX_DAYS\s+" "$LOGIN_DEFS_FILE" | awk '{print $2}')
  MIN_DAYS=$(grep -E "^PASS_MIN_DAYS\s+" "$LOGIN_DEFS_FILE" | awk '{print $2}')
  WARN_AGE=$(grep -E "^PASS_WARN_AGE\s+" "$LOGIN_DEFS_FILE" | awk '{print $2}')

  echo "    - PASS_MAX_DAYS (Max validity): ${MAX_DAYS:-Not set or commented out}"
  echo "    - PASS_MIN_DAYS (Min validity): ${MIN_DAYS:-Not set or commented out}"
  echo "    - PASS_WARN_AGE (Warning period): ${WARN_AGE:-Not set or commented out}"
else
  echo "    Error: Configuration file $LOGIN_DEFS_FILE not found."
fi
echo

# 3b. Settings for existing users (using chage)
echo "  Checking settings for existing users (requires root/sudo for accuracy):"
# Check root user
echo "    - User: root"
if command -v chage &> /dev/null; then
    if [ "$EUID" -eq 0 ]; then
        MAX_DAYS_ROOT=$(sudo chage -l root | grep "Maximum number of days between password change" | cut -d: -f2 | tr -d ' ')
        echo "      Max days between change: ${MAX_DAYS_ROOT:-Error reading value}"
    else
        echo "      Skipping root check (requires sudo)."
    fi
else
    echo "      'chage' command not found. Cannot check existing users."
fi

# Optionally, check other specific users or all interactive users
# Example: Check the user who ran sudo (if applicable)
if [ -n "$SUDO_USER" ] && [ "$SUDO_USER" != "root" ]; then
    echo "    - User: $SUDO_USER (User who ran sudo)"
     if command -v chage &> /dev/null && [ "$EUID" -eq 0 ]; then
        MAX_DAYS_SUDOER=$(sudo chage -l "$SUDO_USER" | grep "Maximum number of days between password change" | cut -d: -f2 | tr -d ' ')
        echo "      Max days between change: ${MAX_DAYS_SUDOER:-Error reading value}"
     else
         echo "      Skipping $SUDO_USER check (requires sudo and chage)."
     fi
fi

# Example: Check all users with a standard shell (might be verbose)
# echo "    Checking all interactive users (might take a moment)..."
# if command -v chage &> /dev/null && [ "$EUID" -eq 0 ]; then
#    awk -F: '$2 != "*" && $2 != "!" && $7 !~ /(\/sbin\/nologin|\/bin\/false|\/usr\/sbin\/nologin)$/ {print $1}' /etc/shadow | while read -r user; do
#        if [ "$user" != "root" ] && [ "$user" != "$SUDO_USER" ]; then # Avoid re-checking known users
#             MAX_DAYS_USER=$(sudo chage -l "$user" | grep "Maximum number of days between password change" | cut -d: -f2 | tr -d ' ')
#             echo "    - User: $user"
#             echo "      Max days between change: ${MAX_DAYS_USER:-Error reading value}"
#        fi
#    done
# else
#    echo "      Skipping check for all interactive users (requires sudo and chage)."
# fi

echo
echo "--- Check Complete ---"

exit 0
