From fae29e928d52917d253b971f8ac5f974cb9fc35e Mon Sep 17 00:00:00 2001 From: Thorsten Spille Date: Sat, 1 Aug 2026 09:09:05 +0200 Subject: [PATCH] Create zmb-ad_tls_manager --- scripts/zmb-ad_tls_manager | 709 +++++++++++++++++++++++++++++++++++++ 1 file changed, 709 insertions(+) create mode 100644 scripts/zmb-ad_tls_manager diff --git a/scripts/zmb-ad_tls_manager b/scripts/zmb-ad_tls_manager new file mode 100644 index 0000000..2bc69f6 --- /dev/null +++ b/scripts/zmb-ad_tls_manager @@ -0,0 +1,709 @@ +#!/usr/bin/env bash +# +# samba-dc-tls.sh - CA und TLS-Zertifikate fuer Samba AD DCs generisch neu bauen +# +# Auslegung: mehrere DCs teilen sich EINE CA. Die CA liegt auf DC1, die +# weiteren DCs bekommen ein Bundle (cert/key/ca) oder lassen einen CSR +# signieren. Alle Aenderungen werden gesichert; schlaegt der Health-Check +# nach dem Restart fehl, wird automatisch zurueckgerollt. +# +# Getestet mit Samba 4.17+ / OpenSSL 1.1.1+ / 3.x auf Debian und RHEL. +# +# Lizenz: MIT +# +set -euo pipefail +umask 077 + +VERSION="1.1" +PROG="$(basename "$0")" + +# --------------------------------------------------------------------------- +# Defaults - per Umgebungsvariable oder Option ueberschreibbar +# --------------------------------------------------------------------------- +CA_DIR="${CA_DIR:-/var/lib/samba/private/tls-ca}" +CA_DAYS="${CA_DAYS:-3650}" # CA-Laufzeit (10 Jahre) +CERT_DAYS="${CERT_DAYS:-825}" # DC-Zertifikat; 825 = Apple/Chrome-Limit +KEY_BITS="${KEY_BITS:-4096}" # RSA; breiteste Client-Kompatibilitaet +CA_CN="${CA_CN:-}" # Default: " Samba AD CA" +ORG="${ORG:-}" # Default: Realm +EXTRA_DNS="${EXTRA_DNS:-}" # zusaetzliche DNS-SANs, komma-/leerzeichensepariert +EXTRA_IP="${EXTRA_IP:-}" # zusaetzliche IP-SANs +BACKUP_KEEP="${BACKUP_KEEP:-10}" # wie viele Backup-Generationen behalten + +DO_RESTART=1 +DO_ROLLBACK=1 +DRY_RUN=0 +FORCE=0 +ASSUME_YES=0 + +# --------------------------------------------------------------------------- +# Ausgabe-Helfer +# --------------------------------------------------------------------------- +if [[ -t 1 ]]; then + C_R=$'\e[31m'; C_G=$'\e[32m'; C_Y=$'\e[33m'; C_B=$'\e[34m'; C_0=$'\e[0m' +else + C_R=""; C_G=""; C_Y=""; C_B=""; C_0="" +fi +log() { printf '%s[*]%s %s\n' "$C_B" "$C_0" "$*"; } +ok() { printf '%s[+]%s %s\n' "$C_G" "$C_0" "$*"; } +warn() { printf '%s[!]%s %s\n' "$C_Y" "$C_0" "$*" >&2; } +die() { printf '%s[x]%s %s\n' "$C_R" "$C_0" "$*" >&2; exit 1; } +run() { if (( DRY_RUN )); then printf ' would run: %s\n' "$*"; else "$@"; fi; } + +confirm() { + (( ASSUME_YES )) && return 0 + local a; read -r -p " $1 [j/N] " a || true + [[ "$a" =~ ^([jJ]|[yY])$ ]] +} + +need_root() { [[ "$(id -u)" -eq 0 ]] || die "Bitte als root ausfuehren."; } + +need_bin() { + local m=() + for b in "$@"; do command -v "$b" >/dev/null 2>&1 || m+=("$b"); done + ((${#m[@]})) && die "Fehlende Programme: ${m[*]}" + return 0 +} + +# --------------------------------------------------------------------------- +# Samba-Umgebung einlesen +# --------------------------------------------------------------------------- +tp() { testparm -s --parameter-name="$1" 2>/dev/null | tail -n1 | tr -d '\r'; } + +abspath_in_private() { + local p="$1" + [[ "$p" == /* ]] && { printf '%s' "$p"; return; } + printf '%s/%s' "$PRIVATE_DIR" "$p" +} + +detect_env() { + need_bin testparm openssl + + SERVER_ROLE="$(tp 'server role')" + [[ "$SERVER_ROLE" == *"domain controller"* ]] || \ + warn "server role = '${SERVER_ROLE:-?}' - das sieht nicht nach einem AD DC aus." + + REALM="$(tp realm)" + [[ -n "$REALM" ]] || die "Kein 'realm' in der smb.conf gefunden." + REALM_LC="${REALM,,}" + NETBIOS="$(tp 'netbios name')" + PRIVATE_DIR="$(tp 'private dir')" + PRIVATE_DIR="${PRIVATE_DIR:-/var/lib/samba/private}" + + TLS_ENABLED="$(tp 'tls enabled')" + TLS_CERT="$(abspath_in_private "$(tp 'tls certfile')")" + TLS_KEY="$(abspath_in_private "$(tp 'tls keyfile')")" + TLS_CA="$(abspath_in_private "$(tp 'tls cafile')")" + TLS_DIR="$(dirname "$TLS_CERT")" + + # FQDN ermitteln - hostname -f kann bei kaputtem DNS luegen + local short; short="$(hostname -s 2>/dev/null || true)" + FQDN="$(hostname -f 2>/dev/null || true)" + if [[ -z "$FQDN" || "$FQDN" != *.* || "${FQDN,,}" != *"$REALM_LC" ]]; then + FQDN="${short,,}.${REALM_LC}" + fi + FQDN="${FQDN,,}" + SHORTNAME="${short,,}" + + ORG="${ORG:-$REALM}" + CA_CN="${CA_CN:-$REALM Samba AD CA}" + + CA_KEY="$CA_DIR/ca-key.pem" + CA_CERT="$CA_DIR/ca-cert.pem" + CA_SRL="$CA_DIR/ca.srl" + STATE_FILE="$TLS_DIR/.samba-dc-tls.state" +} + +# NTDS-DSA-GUID fuer den ._msdcs. SAN +detect_dsa_guid() { + local samdb="$PRIVATE_DIR/sam.ldb" dsdn guid + DSA_GUID="" + command -v ldbsearch >/dev/null 2>&1 || return 0 + [[ -r "$samdb" ]] || return 0 + dsdn="$(ldbsearch -H "$samdb" -s base -b '' dsServiceName 2>/dev/null \ + | sed -n 's/^dsServiceName: //p' | head -n1)" || true + [[ -n "$dsdn" ]] || return 0 + guid="$(ldbsearch -H "$samdb" -s base -b "$dsdn" objectGUID 2>/dev/null \ + | sed -n 's/^objectGUID: //p' | head -n1)" || true + [[ "$guid" =~ ^[0-9a-fA-F-]{36}$ ]] && DSA_GUID="${guid,,}" + return 0 +} + +print_env() { + cat <"$out" + + log "SANs: ${udns[*]} ${ips[*]:-}" +} + +write_ca_conf() { + cat >"$1" <"$CA_SRL" + ok "CA erstellt (gueltig $CA_DAYS Tage)." + openssl x509 -in "$CA_CERT" -noout -subject -enddate | sed 's/^/ /' +} + +require_ca() { + [[ -f "$CA_KEY" && -f "$CA_CERT" ]] || \ + die "Keine CA unter $CA_DIR. Erst '$PROG init-ca' ausfuehren (auf dem CA-DC)." +} + +# --------------------------------------------------------------------------- +# Zertifikat erzeugen / signieren +# --------------------------------------------------------------------------- +# $1 = FQDN, $2 = Ausgabeverzeichnis, $3 = optionale DSA-GUID +make_cert() { + local cn="$1" dir="$2" guid="${3:-}" + local conf="$dir/openssl.cnf" + install -d -m 0700 "$dir" + write_cert_conf "$cn" "$conf" "$guid" + + openssl req -new -nodes -newkey "rsa:$KEY_BITS" -sha256 \ + -keyout "$dir/key.pem" -out "$dir/csr.pem" -config "$conf" + chmod 0600 "$dir/key.pem" + + [[ -s "$CA_SRL" ]] || openssl rand -hex 16 >"$CA_SRL" + openssl x509 -req -in "$dir/csr.pem" -sha256 -days "$CERT_DAYS" \ + -CA "$CA_CERT" -CAkey "$CA_KEY" -CAserial "$CA_SRL" \ + -extfile "$conf" -extensions v3_sign -out "$dir/cert.pem" 2>/dev/null + chmod 0644 "$dir/cert.pem" + cp -f "$CA_CERT" "$dir/ca.pem"; chmod 0644 "$dir/ca.pem" + rm -f "$dir/csr.pem" +} + +# --------------------------------------------------------------------------- +# Pruefungen +# --------------------------------------------------------------------------- +check_pair() { + local cert="$1" key="$2" ca="$3" fqdn="${4:-}" + local a b + + a="$(openssl x509 -in "$cert" -noout -pubkey | openssl pkey -pubin -outform DER 2>/dev/null | openssl dgst -sha256 -r | cut -d' ' -f1)" + b="$(openssl pkey -in "$key" -pubout -outform DER 2>/dev/null | openssl dgst -sha256 -r | cut -d' ' -f1)" + [[ -n "$a" && "$a" == "$b" ]] || die "Key und Zertifikat passen nicht zusammen: $cert / $key" + + openssl verify -CAfile "$ca" "$cert" >/dev/null 2>&1 \ + || die "Zertifikat wird von der CA nicht verifiziert: $cert" + + openssl x509 -in "$cert" -noout -ext extendedKeyUsage 2>/dev/null | grep -q 'TLS Web Server Authentication' \ + || die "Zertifikat hat kein serverAuth-EKU." + + if [[ -n "$fqdn" ]]; then + openssl x509 -in "$cert" -noout -ext subjectAltName 2>/dev/null | grep -qi "DNS:$fqdn" \ + || die "SAN enthaelt den FQDN '$fqdn' nicht." + fi + ok "Zertifikat, Key und CA sind konsistent." +} + +health_check() { + local host="${1:-$FQDN}" rc=0 + log "Health-Check gegen ldaps://$host:636" + if ! timeout 15 openssl s_client -connect "127.0.0.1:636" -servername "$host" \ + -CAfile "$TLS_CA" -verify_return_error /dev/null 2>&1; then + warn "LDAPS-Handshake auf 127.0.0.1:636 fehlgeschlagen." + rc=1 + else + ok "LDAPS-Handshake ok (Kette gegen eigene CA verifiziert)." + fi + + if command -v ldbsearch >/dev/null 2>&1; then + if ldbsearch -H "ldaps://$host" -k yes -s base -b '' defaultNamingContext >/dev/null 2>&1 \ + || ldbsearch -H "ldap://$host" -k yes -s base -b '' defaultNamingContext >/dev/null 2>&1; then + ok "LDAP-Abfrage gegen $host beantwortet." + else + warn "LDAP-Abfrage gegen $host fehlgeschlagen (evtl. kein Kerberos-Ticket - nicht zwingend ein Fehler)." + fi + fi + + if command -v samba-tool >/dev/null 2>&1; then + if samba-tool drs showrepl >/tmp/.drs.$$ 2>&1; then + if grep -qiE 'consecutive failure|WERR_|failed' /tmp/.drs.$$; then + warn "drs showrepl meldet Fehler:"; sed 's/^/ /' /tmp/.drs.$$ | head -n 30 + rc=1 + else + ok "Replikation (drs showrepl) ohne Fehler." + fi + else + warn "samba-tool drs showrepl fehlgeschlagen."; rc=1 + fi + rm -f /tmp/.drs.$$ + fi + return $rc +} + +# --------------------------------------------------------------------------- +# Dienststeuerung +# --------------------------------------------------------------------------- +detect_unit() { + local u + for u in samba-ad-dc samba sernet-samba-ad; do + if systemctl cat "$u.service" >/dev/null 2>&1; then + if systemctl is-enabled "$u.service" >/dev/null 2>&1 || systemctl is-active "$u.service" >/dev/null 2>&1; then + printf '%s' "$u.service"; return 0 + fi + fi + done + return 1 +} + +restart_samba() { + local unit + if ! unit="$(detect_unit)"; then + warn "Keine aktive Samba-AD-Unit gefunden - bitte manuell neu starten." + return 0 + fi + log "Starte $unit neu ..." + run systemctl restart "$unit" + (( DRY_RUN )) && return 0 + sleep 4 + systemctl is-active --quiet "$unit" || die "$unit ist nach dem Restart nicht aktiv!" + ok "$unit laeuft." +} + +# --------------------------------------------------------------------------- +# Installation mit Backup / Rollback +# --------------------------------------------------------------------------- +backup_current() { + local ts bdir + ts="$(date +%Y%m%d-%H%M%S)" + bdir="$TLS_DIR/backup-$ts" + install -d -m 0700 "$bdir" + local f + for f in "$TLS_CERT" "$TLS_KEY" "$TLS_CA"; do + [[ -f "$f" ]] && cp -a "$f" "$bdir/" + done + printf '%s\n' "$bdir" >"$STATE_FILE"; chmod 0600 "$STATE_FILE" + ok "Backup: $bdir" + + # alte Generationen aufraeumen + local -a old + mapfile -t old < <(ls -1d "$TLS_DIR"/backup-* 2>/dev/null | sort) + if (( ${#old[@]} > BACKUP_KEEP )); then + local del=$(( ${#old[@]} - BACKUP_KEEP )) i + for ((i=0; i/dev/null | sed 's/^/ alt: /' || true + else + printf ' alt: (keine vorhanden)\n' + fi + openssl x509 -in "$src/cert.pem" -noout -subject -enddate | sed 's/^/ neu: /' + + if ! confirm "Zertifikate installieren und Samba neu starten?"; then + die "Abgebrochen." + fi + + local bdir; bdir="$(backup_current)" + + install -d -m 0700 -o root -g root "$TLS_DIR" + install -m 0600 -o root -g root "$src/key.pem" "$TLS_KEY.new" + install -m 0644 -o root -g root "$src/cert.pem" "$TLS_CERT.new" + install -m 0644 -o root -g root "$src/ca.pem" "$TLS_CA.new" + mv -f "$TLS_KEY.new" "$TLS_KEY" + mv -f "$TLS_CERT.new" "$TLS_CERT" + mv -f "$TLS_CA.new" "$TLS_CA" + command -v restorecon >/dev/null 2>&1 && restorecon -R "$TLS_DIR" >/dev/null 2>&1 || true + ok "Dateien installiert." + + restart_samba + + if ! health_check "$FQDN"; then + if (( DO_ROLLBACK )); then + warn "Health-Check fehlgeschlagen - rolle zurueck auf $bdir" + restore_backup "$bdir" + restart_samba + health_check "$FQDN" || warn "Auch nach Rollback nicht sauber - bitte manuell pruefen!" + die "Rollback durchgefuehrt. Zertifikate wurden NICHT geaendert." + fi + warn "Health-Check fehlgeschlagen (Rollback deaktiviert)." + return 1 + fi + ok "Fertig. Neues Zertifikat ist aktiv." +} + +restore_backup() { + local bdir="$1" + [[ -d "$bdir" ]] || die "Backup-Verzeichnis nicht gefunden: $bdir" + [[ -f "$bdir/$(basename "$TLS_KEY")" ]] && install -m 0600 "$bdir/$(basename "$TLS_KEY")" "$TLS_KEY" + [[ -f "$bdir/$(basename "$TLS_CERT")" ]] && install -m 0644 "$bdir/$(basename "$TLS_CERT")" "$TLS_CERT" + [[ -f "$bdir/$(basename "$TLS_CA")" ]] && install -m 0644 "$bdir/$(basename "$TLS_CA")" "$TLS_CA" + ok "Backup zurueckgespielt: $bdir" +} + +# --------------------------------------------------------------------------- +# Kommandos +# --------------------------------------------------------------------------- +cmd_renew() { + need_root; require_ca; detect_dsa_guid + local tmp; tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' RETURN + log "Erzeuge Zertifikat fuer $FQDN" + (( DRY_RUN )) && { log "(dry-run) kein Schluesselmaterial erzeugt"; return 0; } + make_cert "$FQDN" "$tmp" "${DSA_GUID:-}" + install_bundle "$tmp" +} + +cmd_issue_for() { + need_root; require_ca + local host="${1,,}"; shift || true + local guid="${1:-}" + [[ -n "$host" ]] || die "Verwendung: $PROG issue-for [dsa-guid]" + [[ "$host" == *.* ]] || die "Bitte den vollstaendigen FQDN angeben." + + local out="${OUT_DIR:-/root/samba-tls-$host}" + log "Erzeuge Bundle fuer $host in $out" + (( DRY_RUN )) && return 0 + rm -rf "$out" + make_cert "$host" "$out" "$guid" + check_pair "$out/cert.pem" "$out/key.pem" "$out/ca.pem" "$host" + + local tgz="/root/samba-tls-$host.tar.gz" + tar -czf "$tgz" -C "$out" cert.pem key.pem ca.pem + chmod 0600 "$tgz" + ok "Bundle: $tgz" + cat <:/tmp/ + ssh root@ '$PROG sign /tmp/csr.pem $FQDN' + Danach cert.pem + ca.pem zurueckkopieren und: + $PROG install-files $out/cert.pem $out/key.pem $out/ca.pem +EOF +} + +cmd_sign() { + need_root; require_ca + local csr="$1" cn="${2:-}" + [[ -f "$csr" ]] || die "CSR nicht gefunden: $csr" + [[ -n "$cn" ]] || cn="$(openssl req -in "$csr" -noout -subject | sed -n 's/.*CN *= *\([^,/]*\).*/\1/p')" + [[ -n "$cn" ]] || die "CN konnte nicht ermittelt werden - bitte als 2. Argument angeben." + local out="${OUT_DIR:-/root/samba-tls-signed-$cn}" + install -d -m 0700 "$out" + local conf="$out/openssl.cnf" + write_cert_conf "${cn,,}" "$conf" "${DSA_GUID:-}" + (( DRY_RUN )) && return 0 + [[ -s "$CA_SRL" ]] || openssl rand -hex 16 >"$CA_SRL" + openssl x509 -req -in "$csr" -sha256 -days "$CERT_DAYS" \ + -CA "$CA_CERT" -CAkey "$CA_KEY" -CAserial "$CA_SRL" \ + -extfile "$conf" -extensions v3_sign -out "$out/cert.pem" 2>/dev/null + cp -f "$CA_CERT" "$out/ca.pem" + chmod 0644 "$out/cert.pem" "$out/ca.pem" + ok "Signiert: $out/cert.pem (+ ca.pem)" +} + +cmd_install() { + need_root + local arg="$1" + local tmp; tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' RETURN + if [[ -d "$arg" ]]; then + cp -f "$arg/cert.pem" "$arg/key.pem" "$arg/ca.pem" "$tmp/" + elif [[ -f "$arg" ]]; then + tar -xzf "$arg" -C "$tmp" + else + die "Bundle nicht gefunden: $arg" + fi + chmod 0600 "$tmp/key.pem" + install_bundle "$tmp" +} + +cmd_install_files() { + need_root + local c="$1" k="$2" a="$3" + local tmp; tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' RETURN + install -m 0644 "$c" "$tmp/cert.pem" + install -m 0600 "$k" "$tmp/key.pem" + install -m 0644 "$a" "$tmp/ca.pem" + install_bundle "$tmp" +} + +cmd_status() { + print_env + echo + local f + for f in "$CA_CERT:CA" "$TLS_CERT:DC-Zertifikat"; do + local p="${f%%:*}" n="${f##*:}" + if [[ -f "$p" ]]; then + printf ' %s (%s)\n' "$n" "$p" + openssl x509 -in "$p" -noout -subject -issuer -startdate -enddate 2>/dev/null | sed 's/^/ /' + openssl x509 -in "$p" -noout -ext subjectAltName 2>/dev/null | sed -n '2p' | sed 's/^ */ SAN: /' + if ! openssl x509 -in "$p" -noout -checkend $((30*86400)) >/dev/null 2>&1; then + warn " laeuft in weniger als 30 Tagen ab!" + fi + echo + else + warn "$n fehlt: $p" + fi + done + [[ -f "$STATE_FILE" ]] && printf ' letztes Backup: %s\n' "$(cat "$STATE_FILE")" + return 0 +} + +cmd_verify() { + need_root + [[ -f "$TLS_CERT" && -f "$TLS_KEY" && -f "$TLS_CA" ]] || die "Zertifikatsdateien unvollstaendig." + check_pair "$TLS_CERT" "$TLS_KEY" "$TLS_CA" "$FQDN" + health_check "$FQDN" +} + +cmd_rollback() { + need_root + local bdir="${1:-}" + if [[ -z "$bdir" ]]; then + [[ -f "$STATE_FILE" ]] || die "Kein Backup-Zeiger gefunden. Pfad bitte angeben." + bdir="$(cat "$STATE_FILE")" + fi + confirm "Auf $bdir zurueckrollen?" || die "Abgebrochen." + restore_backup "$bdir" + restart_samba + health_check "$FQDN" || warn "Health-Check nach Rollback nicht sauber." +} + +cmd_export_ca() { + require_ca + local out="${1:-/root/$(printf '%s' "$REALM_LC" | tr '.' '-')-ca.crt}" + cp -f "$CA_CERT" "$out"; chmod 0644 "$out" + ok "CA-Zertifikat exportiert: $out" + cat < [Argumente] + +Kommandos: + status Umgebung und aktuelle Zertifikate anzeigen + init-ca Neue CA anlegen (einmalig, auf DC1) + renew Zertifikat fuer DIESEN DC neu bauen + installieren + issue-for [dsa-guid] Bundle fuer einen anderen DC erzeugen (auf dem CA-DC) + install Bundle auf diesem DC installieren + request Key + CSR lokal erzeugen (CA-Key bleibt auf DC1) + sign [cn] CSR auf dem CA-DC signieren + install-files + verify Konsistenz- und Health-Check + rollback [backup-dir] Letzten Stand zurueckspielen + export-ca [datei] CA-Zertifikat zur Client-Verteilung exportieren + +Optionen: + --ca-dir DIR CA-Verzeichnis (Default: $CA_DIR) + --days N Laufzeit DC-Zertifikat (Default: $CERT_DAYS) + --ca-days N Laufzeit CA (Default: $CA_DAYS) + --bits N RSA-Schluessellaenge (Default: $KEY_BITS) + --dns a,b,c zusaetzliche DNS-SANs (z.B. Alias-Namen, ldap.firma.de) + --ip 10.0.0.1,... zusaetzliche IP-SANs + --out DIR Ausgabeverzeichnis fuer issue-for/request/sign + --no-restart Samba nicht neu starten + --no-rollback kein automatischer Rollback bei fehlgeschlagenem Check + --yes keine Rueckfragen + --force bestehende CA ueberschreiben + --dry-run nur anzeigen, nichts aendern + -h, --help diese Hilfe + +Ablauf bei zwei DCs (empfohlen): + DC1: $PROG init-ca + $PROG renew + $PROG issue-for dc2.${REALM_LC:-example.local} + scp /root/samba-tls-dc2.${REALM_LC:-example.local}.tar.gz root@dc2:/root/ + DC2: $PROG install /root/samba-tls-dc2.${REALM_LC:-example.local}.tar.gz + DC1: $PROG export-ca # CA an alle Clients verteilen + +Immer nur EINEN DC nach dem anderen anfassen und dazwischen +'samba-tool drs showrepl' auf beiden Seiten pruefen. +EOF +} + +# --------------------------------------------------------------------------- +# Argumente +# --------------------------------------------------------------------------- +OUT_DIR="${OUT_DIR:-}" +ARGS=() +while (( $# )); do + case "$1" in + --ca-dir) CA_DIR="$2"; shift 2 ;; + --days) CERT_DAYS="$2"; shift 2 ;; + --ca-days) CA_DAYS="$2"; shift 2 ;; + --bits) KEY_BITS="$2"; shift 2 ;; + --dns) EXTRA_DNS="$2"; shift 2 ;; + --ip) EXTRA_IP="$2"; shift 2 ;; + --out) OUT_DIR="$2"; shift 2 ;; + --ca-cn) CA_CN="$2"; shift 2 ;; + --org) ORG="$2"; shift 2 ;; + --no-restart) DO_RESTART=0; shift ;; + --no-rollback) DO_ROLLBACK=0; shift ;; + --yes|-y) ASSUME_YES=1; shift ;; + --force) FORCE=1; shift ;; + --dry-run) DRY_RUN=1; shift ;; + -h|--help) usage; exit 0 ;; + --) shift; ARGS+=("$@"); break ;; + -*) die "Unbekannte Option: $1" ;; + *) ARGS+=("$1"); shift ;; + esac +done + +if (( ! DO_RESTART )); then + restart_samba() { + warn "Restart uebersprungen (--no-restart) - das Zertifikat wird erst nach einem Neustart aktiv." + } +fi + +CMD="${ARGS[0]:-status}" +detect_env + +case "$CMD" in + status) cmd_status ;; + init-ca) cmd_init_ca ;; + renew) cmd_init_ca; cmd_renew ;; + issue-for) cmd_issue_for "${ARGS[1]:-}" "${ARGS[2]:-}" ;; + install) cmd_install "${ARGS[1]:?Bundle angeben}" ;; + install-files) cmd_install_files "${ARGS[1]:?cert}" "${ARGS[2]:?key}" "${ARGS[3]:?ca}" ;; + request) cmd_request ;; + sign) cmd_sign "${ARGS[1]:?CSR angeben}" "${ARGS[2]:-}" ;; + verify) cmd_verify ;; + rollback) cmd_rollback "${ARGS[1]:-}" ;; + export-ca) cmd_export_ca "${ARGS[1]:-}" ;; + help) usage ;; + *) usage; die "Unbekanntes Kommando: $CMD" ;; +esac