#!/bin/bash
# Privilegierter Teil von cisco-profil-reset. Wird ausschliesslich ueber
# pkexec aus /usr/bin/cisco-profil-reset aufgerufen und laeuft als root.
#
# Aufruf:  helper [--dienst]
#          --dienst = vpnagentd vorher stoppen und hinterher wieder starten
#
# Hier gibt es bewusst KEINE Dialoge: pkexec bereinigt die Umgebung,
# DISPLAY und XAUTHORITY sind weg, zenity wuerde hier nicht zuverlaessig
# funktionieren. Die Rueckmeldung erledigt der GUI-Teil anhand des
# Rueckgabewerts.
#
# stdout: der Pfad der angelegten Sicherung, sobald das Umbenennen
#         geklappt hat - auch dann, wenn danach noch etwas schiefgeht.

set -euo pipefail

BIBLIOTHEK="/usr/lib/cisco-profil-reset/lib.sh"

if [ ! -r "$BIBLIOTHEK" ]; then
    echo "helper: $BIBLIOTHEK fehlt." >&2
    exit 20
fi
# shellcheck source=lib.sh
. "$BIBLIOTHEK"

if [ "$(id -u)" -ne 0 ]; then
    echo "helper: laeuft nicht als root." >&2
    exit "$EXIT_KEIN_ROOT"
fi

dienst_behandeln=0
[ "${1:-}" = "--dienst" ] && dienst_behandeln=1

dienst_gestoppt=0

# Wird an mehreren Stellen gebraucht: nach einem Fehler soll der Dienst
# nicht gestoppt zurueckbleiben, wenn wir ihn selbst angehalten haben.
dienst_wieder_starten() {
    [ "$dienst_gestoppt" -eq 1 ] || return 0
    systemctl start "$DIENST" >/dev/null 2>&1
}

if ! zielverzeichnis=$(profilverzeichnis_finden); then
    echo "helper: kein Profilverzeichnis gefunden." >&2
    exit "$EXIT_NICHT_GEFUNDEN"
fi

if ! existiert "$zielverzeichnis"; then
    echo "helper: $zielverzeichnis existiert nicht." >&2
    exit "$EXIT_NICHT_GEFUNDEN"
fi

sicherung="${zielverzeichnis}.bak-$(date +%Y%m%d-%H%M%S)"

# Eine vorhandene Sicherung wird nie ueberschrieben - das waere genau der
# Datenverlust, den dieses Werkzeug verhindern soll.
if existiert "$sicherung"; then
    echo "helper: $sicherung existiert bereits." >&2
    exit "$EXIT_ZIEL_EXISTIERT"
fi

# Rechte und Eigentuemer merken, damit der leere Ersatz hinterher genauso
# aussieht wie das Original. Muss vor dem Umbenennen passieren.
if [ -d "$zielverzeichnis" ] && [ ! -L "$zielverzeichnis" ]; then
    ist_verzeichnis=1
    modus=$(stat -c %a "$zielverzeichnis")
    eigner=$(stat -c %u:%g "$zielverzeichnis")
else
    ist_verzeichnis=0
fi

if [ "$dienst_behandeln" -eq 1 ] && dienst_laeuft; then
    if ! systemctl stop "$DIENST" >/dev/null 2>&1; then
        echo "helper: $DIENST liess sich nicht stoppen." >&2
        exit "$EXIT_DIENST_STOPP"
    fi
    dienst_gestoppt=1
fi

if ! mv -n -- "$zielverzeichnis" "$sicherung"; then
    echo "helper: Umbenennen fehlgeschlagen." >&2
    dienst_wieder_starten
    exit "$EXIT_MV_FEHLER"
fi

# mv -n meldet je nach Version auch dann Erfolg, wenn es nichts getan hat.
# Deshalb das Ergebnis nachkontrollieren, statt ihm zu vertrauen.
if ! existiert "$sicherung" || existiert "$zielverzeichnis"; then
    echo "helper: Ergebnis unerwartet." >&2
    dienst_wieder_starten
    exit "$EXIT_MV_FEHLER"
fi

# Ab hier ist die Sicherung angelegt. Der Pfad wird auf jeden Fall
# gemeldet, damit der Benutzer ihn auch bei Folgefehlern erfaehrt.
printf '%s\n' "$sicherung"

# Leeres Verzeichnis mit den urspruenglichen Rechten wieder anlegen, damit
# der Cisco-Client eine Ablage vorfindet und ein frisches Profil schreiben
# kann.
if [ "$ist_verzeichnis" -eq 1 ]; then
    if ! mkdir -- "$zielverzeichnis" \
       || ! chmod "$modus" "$zielverzeichnis" \
       || ! chown "$eigner" "$zielverzeichnis"; then
        echo "helper: Ersatzverzeichnis konnte nicht angelegt werden." >&2
        dienst_wieder_starten
        exit "$EXIT_ERSATZ_FEHLER"
    fi

    # Bestandteile der Cisco-Installation zuruecklegen - im Gegensatz zum
    # Profil liefert das Gateway sie nicht neu. In der Sicherung bleiben
    # sie ohnehin erhalten, hier entsteht nur eine Kopie.
    schema_fehler=0
    shopt -s nullglob
    for muster in "${BEHALTEN_MUSTER[@]}"; do
        for datei in "$sicherung"/$muster; do
            [ -f "$datei" ] || continue
            cp -p -- "$datei" "$zielverzeichnis/" || schema_fehler=1
        done
    done
    shopt -u nullglob

    if [ "$schema_fehler" -eq 1 ]; then
        echo "helper: Schema-Dateien konnten nicht zurueckgelegt werden." >&2
        dienst_wieder_starten
        exit "$EXIT_SCHEMA_FEHLER"
    fi
fi

if [ "$dienst_gestoppt" -eq 1 ]; then
    if ! systemctl start "$DIENST" >/dev/null 2>&1; then
        echo "helper: $DIENST liess sich nicht wieder starten." >&2
        exit "$EXIT_DIENST_START"
    fi
fi

exit "$EXIT_OK"
