From b36019dfc97cb080186c4dbebf791c365dfb1a8e Mon Sep 17 00:00:00 2001 From: Giorgio Ravera Date: Sun, 18 Jan 2026 18:52:13 +0100 Subject: [PATCH] Added script to check domain healtj --- domain_check.sh | 172 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100755 domain_check.sh diff --git a/domain_check.sh b/domain_check.sh new file mode 100755 index 0000000..468c02c --- /dev/null +++ b/domain_check.sh @@ -0,0 +1,172 @@ +#!/usr/bin/env bash +# Samba NT4 + OpenLDAP — Domain Health Check (v1.4 FULL) +# Autore: Copilot per Giorgio Ravera +# Uso: sudo ./domain_health_check_v1.4.sh +# Note: esegue controlli su SID, utenti, gruppi, LDAP e mapping Samba. + +set -uo pipefail + +# ---- Colori & contatori ---- +GREEN="\e[32m"; YELLOW="\e[33m"; RED="\e[31m"; CYAN="\e[36m"; BOLD="\e[1m"; RESET="\e[0m" +pass_n=0; warn_n=0; fail_n=0 +ok() { echo -e "${GREEN}[OK]${RESET} $*"; ((pass_n++)) || true; } +warn() { echo -e "${YELLOW}[WARN]${RESET} $*"; ((warn_n++)) || true; } +fail() { echo -e "${RED}[FAIL]${RESET} $*"; ((fail_n++)) || true; } +info() { echo -e "${CYAN}[*]${RESET} $*"; } +hr() { echo -e "${BOLD}------------------------------------------------------------${RESET}"; } + +if [[ $(id -u) -ne 0 ]]; then + warn "Esegui come root per ottenere tutti i risultati (alcuni comandi richiedono privilegi)."; +fi + +# Comandi utili (non tutti obbligatori) +CMDS=(net pdbedit getent awk sed grep cut sort uniq slapcat ldapsearch testparm id) +for c in "${CMDS[@]}"; do command -v "$c" >/dev/null 2>&1 || warn "Comando non trovato: $c (alcuni check potrebbero essere saltati)"; done + +# --- CHECKS --- +check_sids() { + hr; info "Controllo SID di dominio vs SID locale" + command -v net >/dev/null 2>&1 || { warn "net non disponibile"; return; } + local local_sid domain_sid + local_sid=$(net getlocalsid 2>/dev/null | awk -F': ' '{print $2}' | tr -d '\r\n') + domain_sid=$(net getdomainsid 2>/dev/null | awk -F': ' '{print $2}' | tr -d '\r\n') + [[ -n "$local_sid" ]] && info "Local SID: $local_sid" || warn "Impossibile leggere Local SID" + [[ -n "$domain_sid" ]] && info "Domain SID: $domain_sid" || warn "Impossibile leggere Domain SID" + [[ -n "$local_sid" && -n "$domain_sid" ]] && { + [[ "$local_sid" == "$domain_sid" ]] && ok "SID locale e di dominio coincidono" || fail "SID locale e di dominio NON coincidono"; } +} + +check_admin_500_512() { + hr; info "Verifica Administrator (RID 500) e Primary Group (512)" + command -v pdbedit >/dev/null 2>&1 || { warn "pdbedit non disponibile"; return; } + if pdbedit -L | cut -d: -f1 | grep -qx "admin"; then + local out; out=$(pdbedit -L -v admin 2>/dev/null) + echo "$out" | grep -Eq "User SID: .*-500$" && ok "admin ha RID 500" || fail "admin NON ha RID 500" + echo "$out" | grep -Eq "Primary Group SID: .*-512$" && ok "admin ha Primary Group 512 (Domain Admins)" || fail "admin NON ha Primary Group 512" + else + warn "Utente 'admin' non trovato, cerco chi ha RID 500" + local u; u=$(pdbedit -L -v 2>/dev/null | awk '/User SID:/ {sid=$3} /Unix username:/ {user=$3} {if (sid ~ /-500$/) print user}' | head -n1) + [[ -n "$u" ]] && ok "Trovato utente con RID 500: $u" || fail "Nessun utente con RID 500 trovato" + fi +} + +check_admin_membership() { + hr; info "Verifica membership effettiva di 'admin' in Domain Admins (gid 512)" + command -v id >/dev/null 2>&1 || { warn "id non disponibile"; return; } + if id admin >/dev/null 2>&1; then + id admin | grep -Eq 'gid=512\(| 512\(' && ok "'admin' ha gid primario 512 (Domain Admins) oppure è membro di 512" || warn "'admin' non appare con gid/membro 512 nell'output di id" + else + warn "Utente 'admin' non risolto da id(1)" + fi +} + +check_low_rids() { + hr; info "Verifica RIDs bassi indesiderati (<1000, esclusi 500 e 501)" + command -v pdbedit >/dev/null 2>&1 || { warn "pdbedit non disponibile"; return; } + local bad; bad=$(pdbedit -L -v 2>/dev/null | awk '/User SID:/ {sid=$3; split(sid,a,"-"); rid=a[length(a)]; if (rid+0 < 1000 && rid != 500 && rid != 501) print sid}') + [[ -z "$bad" ]] && ok "Nessun utente con RID anomalo basso" || fail "RIDs bassi trovati:\n$bad" +} + +check_guest_501() { + hr; info "Verifica account Guest (RID 501)" + command -v pdbedit >/dev/null 2>&1 || { warn "pdbedit non disponibile"; return; } + # Usa AWK per evitare problemi con '$' nei pattern + local found + found=$(pdbedit -L -v 2>/dev/null | awk ' + /^Unix username:/ {user=$3} + /^User SID:/ {sid=$3; n=split(sid,a,"-"); rid=a[n]; if (rid==501) {print user ":" sid}} + ') + if [[ -n "$found" ]]; then + ok "Account Guest trovato: $found" + else + warn "RID 501 non trovato. (Inusuale per NT4, verifica configurazione)" + fi +} + +check_groupmap_core() { + hr; info "Verifica groupmap core (512, 513, 514, 515)" + command -v net >/dev/null 2>&1 || { warn "net non disponibile"; return; } + local gm; gm=$(net groupmap list 2>/dev/null) + [[ -z "$gm" ]] && { warn "net groupmap list non ha restituito output"; return; } + echo "$gm" | grep -Fq -- "-512)" && ok "Domain Admins (512) presente" || fail "Domain Admins (512) mancante" + echo "$gm" | grep -Fq -- "-513)" && ok "Domain Users (513) presente" || fail "Domain Users (513) mancante" + echo "$gm" | grep -Fq -- "-514)" && ok "Domain Guests (514) presente" || fail "Domain Guests (514) mancante" + echo "$gm" | grep -Fq -- "-515)" && ok "Domain Computers (515) presente" || fail "Domain Computers (515) mancante" +} + +check_group_name_collisions() { + hr; info "Verifica collisioni di NOME gruppo tra sorgenti (files/ldap)" + command -v getent >/dev/null 2>&1 || { warn "getent non disponibile"; return; } + local dups; dups=$(getent group | cut -d: -f1 | sort | uniq -d) + [[ -z "$dups" ]] && ok "Nessuna collisione di nome gruppo rilevata" || warn "Collisioni nomi gruppo rilevate:\n$dups" +} + +check_nobody_guest_split() { + hr; info "Verifica separazione nobody (locale) vs guest (LDAP)" + command -v getent >/dev/null 2>&1 || { warn "getent non disponibile"; return; } + local nb ge; nb=$(getent passwd nobody); ge=$(getent passwd guest) + [[ -n "$nb" ]] && ok "nobody locale presente: $(echo "$nb" | cut -d: -f1,3,4,7)" || warn "nobody locale non trovato" + if [[ -n "$ge" ]]; then + local uid gid; uid=$(echo "$ge" | cut -d: -f3); gid=$(echo "$ge" | cut -d: -f4) + [[ "$uid" == "65534" && "$gid" == "514" ]] && ok "guest LDAP coerente (uid=65534, gid=514)" || warn "guest LDAP anomalo (atteso uid=65534,gid=514): $(echo "$ge" | cut -d: -f1,3,4,7)" + else + warn "guest LDAP non trovato" + fi +} + +check_ldap_domain_objects() { + hr; info "Verifica oggetti sambaDomain in LDAP" + if command -v slapcat >/dev/null 2>&1; then + local count sid arid + count=$(slapcat -n 1 2>/dev/null | grep -c "^objectClass: sambaDomain") + sid=$(slapcat -n 1 2>/dev/null | awk -F': ' '/^sambaSID:/ {print $2}' | sort -u) + arid=$(slapcat -n 1 2>/dev/null | awk -F': ' '/^sambaAlgorithmicRidBase:/ {print $2}' | tr -d '\r\n') + info "sambaDomain objects: $count" + info "sambaSID (dominio) trovato/i: $(echo "$sid" | tr '\n' ' ')" + [[ "$count" -eq 1 ]] && ok "Unico oggetto sambaDomain presente" || warn "Attesi 1 sambaDomain, trovati $count" + [[ -n "$arid" ]] && ok "sambaAlgorithmicRidBase=$arid" || warn "sambaAlgorithmicRidBase non trovato" + else + warn "slapcat non disponibile: salto controlli oggetto sambaDomain" + fi +} + +check_machine_accounts() { + hr; info "Verifica account macchina (uid che terminano con $) con primary group 515" + command -v slapcat >/dev/null 2>&1 || { warn "slapcat non disponibile"; return; } + local bad + bad=$(slapcat -n 1 2>/dev/null | awk '/^dn: uid=.*\$,/ {inhost=1; uid=$2} /^sambaPrimaryGroupSID:/ {if (inhost){pg=$2; if (pg !~ /-515$/) print uid" -> "pg; inhost=0}}') + [[ -z "$bad" ]] && ok "Tutti gli account macchina hanno primary group 515 (Domain Computers)" || warn "Account macchina con primary group non 515:\n$bad" +} + +check_testparm() { + hr; info "Validazione configurazione Samba con testparm" + command -v testparm >/dev/null 2>&1 || { warn "testparm non disponibile"; return; } + if testparm -s >/dev/null 2>&1; then + ok "testparm OK (configurazione Samba valida)" + else + fail "testparm ha rilevato errori nella configurazione" + testparm -s 2>&1 | sed -n '1,120p' + fi +} + +summary() { + hr; echo -e "${BOLD}Riepilogo:${RESET} PASS=$pass_n WARN=$warn_n FAIL=$fail_n"; [[ $fail_n -eq 0 ]] && exit 0 || exit 1 +} + +main() { + echo -e "${BOLD}Samba NT4 + OpenLDAP — Health Check (v1.4 FULL)${RESET}" + check_sids + check_admin_500_512 + check_admin_membership + check_low_rids + check_guest_501 + check_groupmap_core + check_group_name_collisions + check_nobody_guest_split + check_ldap_domain_objects + check_machine_accounts + check_testparm + summary +} + +main "$@" -- 2.47.3