#!/bin/bash

# ----------------------------------------------------
# Definimos el fichero donde se volcará todo el output
LOGFILE="auditoria_permisos.txt"
# Redirigimos stdout y stderr a tee, de forma que se muestre en pantalla
# y se guarde en $LOGFILE simultáneamente:
exec > >(tee "$LOGFILE") 2>&1
# ----------------------------------------------------

RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

# Verificación de permisos
if [ "$EUID" -ne 0 ]; then
  echo -e "${RED}Este script debe ejecutarse como root (usar: sudo ./audit_linux.sh)${NC}"
  exit 1
fi

echo -e "\n==============================="
echo -e "Control Op.acc.1 – Identificación"
echo -e "===============================\n"
echo -e "Verificar si hay usuarios duplicados (mismo UID para distintos nombres)"

uids=$(cut -d: -f3 /etc/passwd | sort | uniq -d)
vuln=0

for uid in $uids; do
  users=$(awk -F: -v u="$uid" '($3==u){print $1}' /etc/passwd | paste -sd "," -)
  echo -e "${RED}UID duplicado: $uid pertenece a: $users${NC}"
  vuln=1
done

if [ $vuln -eq 0 ]; then
  echo -e "${GREEN}No se han encontrado UIDs duplicados${NC}"
fi

echo -e "\nVerificar si hay usuarios con shell no válido (por ejemplo /bin/false o /usr/sbin/nologin sin justificación)"

awk -F: '($3>=1000 && $1 != "nobody" && ($7 ~ /false/ || $7 ~ /nologin/)) {print $1 " -> " $7}' /etc/passwd | while read -r line; do
  echo -e "${RED}Usuario con shell sospechosa: $line${NC}"
  vuln=1
done

if ! awk -F: '($3>=1000 && $1 != "nobody" && ($7 ~ /false/ || $7 ~ /nologin/))' /etc/passwd | grep -q .; then
  echo -e "${GREEN}Todos los usuarios tienen shells válidas${NC}"
fi
echo -e "===============================\n"


echo -e "\n==============================="
echo -e "Control Op.acc.2 – Requisitos de acceso"
echo -e "===============================\n"
echo -e "Verificar si hay usuarios en grupos con privilegios elevados (sudo, adm, wheel, shadow)"

# 1) Usuarios en grupo sudo
if getent group sudo > /dev/null; then
  sudo_users=$(getent group sudo | awk -F: '{print $4}' | tr ',' '\n' | sed '/^$/d')
  if [ -n "$sudo_users" ]; then
    echo "$sudo_users" | while read -r user; do
      echo -e "${RED}Usuario con privilegios sudo: $user${NC}"
    done
  else
    echo -e "${GREEN}No hay usuarios en el grupo sudo${NC}"
  fi
else
  echo -e "${GREEN}Grupo sudo no existe en este sistema${NC}"
fi

# 2) Otros grupos críticos (adm, wheel, shadow)
for grp in adm wheel shadow; do
  if getent group "$grp" > /dev/null; then
    users=$(getent group "$grp" | awk -F: '{print $4}' | tr ',' '\n' | sed '/^$/d')
    if [ -n "$users" ]; then
      echo "$users" | while read -r user; do
        echo -e "${RED}Usuario con privilegios elevados en grupo $grp: $user${NC}"
      done
    else
      echo -e "${GREEN}No hay usuarios en el grupo $grp${NC}"
    fi
  fi
done

echo -e "===============================\n"


echo -e "\n==============================="
echo -e "Control Op.acc.4 – Proceso de gestión de derechos de acceso"
echo -e "===============================\n"

echo -e "Verificar si existen usuarios bloqueados (cuentas deshabilitadas pero no eliminadas)"

while IFS=: read -r user pass _; do
  uid=$(id -u "$user" 2>/dev/null)
  if [[ "$pass" =~ ^[\!\*] ]] && [ "$uid" -ge 1000 ] && [ "$user" != "nobody" ]; then
    echo -e "${RED}Cuenta bloqueada: $user${NC}"
  fi
done < /etc/shadow

echo -e "\nVerificar si existen usuarios con cuenta expirada"

while IFS=: read -r user _ _ _ _ _ _ expire_days _; do
  uid=$(id -u "$user" 2>/dev/null)
  if [ "$uid" -ge 1000 ] && [ "$user" != "nobody" ] && [ "$expire_days" != "" ] && [ "$expire_days" -ne -1 ]; then
    expire_date=$(date -d "1970-01-01 + $expire_days days" +%Y-%m-%d)
    if [ "$(date -d "$expire_date" +%s)" -lt "$(date +%s)" ]; then
      echo -e "${RED}Usuario expirado: $user (expiró el $expire_date)${NC}"
    fi
  fi
done < /etc/shadow

echo -e "===============================\n"


echo -e "\n==============================="
echo -e "Control Op.acc.5 – Mecanismos de autenticación (usuarios externos)"
echo -e "===============================\n"

ssh_config="/etc/ssh/sshd_config"

if [ ! -f "$ssh_config" ]; then
  echo -e "${RED}No se ha encontrado el archivo de configuración SSH: $ssh_config${NC}"
else
  echo -e "Verificar si se permite el inicio de sesión remoto como root"
  if grep -Ei "^PermitRootLogin\s+yes" "$ssh_config" > /dev/null; then
    echo -e "${RED}PermitRootLogin está activado (root puede iniciar sesión por SSH)${NC}"
  else
    echo -e "${GREEN}PermitRootLogin está desactivado o restringido correctamente${NC}"
  fi

  echo -e "\nVerificar si se permite autenticación por contraseña"
  if grep -Ei "^PasswordAuthentication\s+yes" "$ssh_config" > /dev/null; then
    echo -e "${RED}PasswordAuthentication está activado (se permite autenticación por contraseña)${NC}"
  else
    echo -e "${GREEN}PasswordAuthentication está desactivado o correctamente configurado${NC}"
  fi

  echo -e "\nVerificar si se ha desactivado la autenticación con clave pública"
  if grep -Ei "^PubkeyAuthentication\s+no" "$ssh_config" > /dev/null; then
    echo -e "${RED}PubkeyAuthentication está desactivado (no se permite autenticación con clave pública)${NC}"
  else
    echo -e "${GREEN}PubkeyAuthentication está activado (clave pública permitida)${NC}"
  fi
fi

echo -e "===============================\n"


echo -e "\n==============================="
echo -e "Control Op.acc.6 – Mecanismos de autenticación (usuarios internos)"
echo -e "===============================\n"

echo -e "Verificar configuración de políticas de contraseña en /etc/login.defs"

login_defs="/etc/login.defs"

check_def() {
  key=$1
  expected=$2
  cmp=$3
  value=$(grep -E "^$key" "$login_defs" | awk '{print $2}')
  if [ -z "$value" ]; then
    echo -e "${RED}No se ha encontrado $key en login.defs${NC}"
  elif [ "$cmp" = "le" ] && [ "$value" -le "$expected" ]; then
    echo -e "${GREEN}$key = $value (correcto)${NC}"
  elif [ "$cmp" = "ge" ] && [ "$value" -ge "$expected" ]; then
    echo -e "${GREEN}$key = $value (correcto)${NC}"
  else
    echo -e "${RED}$key = $value (revisar, valor esperado: $cmp $expected)${NC}"
  fi
}

check_def PASS_MAX_DAYS 90 le
check_def PASS_MIN_DAYS 1 ge
check_def PASS_MIN_LEN 8 ge
check_def PASS_WARN_AGE 7 ge

echo -e "\nVerificar uso de políticas de complejidad en /etc/pam.d/common-password"

pam_file="/etc/pam.d/common-password"
if grep -qE "pam_(pwquality|cracklib)\.so" "$pam_file"; then
  echo -e "${GREEN}Se está utilizando pam_pwquality o pam_cracklib para validar contraseñas${NC}"
else
  echo -e "${RED}No se encontró pam_pwquality.so ni pam_cracklib.so en $pam_file${NC}"
fi

minlen=$(grep -E "pam_(pwquality|cracklib)\.so" "$pam_file" | grep -oE "minlen=[0-9]+" | cut -d= -f2 | head -n1)
if [ -n "$minlen" ]; then
  if [ "$minlen" -ge 8 ]; then
    echo -e "${GREEN}minlen=$minlen (correcto)${NC}"
  else
    echo -e "${RED}minlen=$minlen (debería ser al menos 8)${NC}"
  fi
else
  echo -e "${RED}No se ha encontrado directiva minlen= en common-password${NC}"
fi

echo -e "===============================\n"

# ----------------------------------------------------
# Mensaje final reforzando dónde quedó el archivo
if [ -f "$LOGFILE" ]; then
  if [ "$vuln" -ne 0 ]; then
    echo -e "${RED}Se detectaron vulnerabilidades. Revise el informe en: $LOGFILE${NC}"
  else
    echo -e "${GREEN}No se detectaron vulnerabilidades. El informe está en: $LOGFILE${NC}"
  fi
else
  echo -e "${RED}No se pudo generar el archivo $LOGFILE${NC}"
fi
# ----------------------------------------------------

# Fin del script
