
#!/bin/bash
#
# snuk-audit
# Snukware System Integrity Audit
#

VERSION="1.0"

ROOTS=(
    /bin /sbin /usr/bin /usr/sbin
    /lib64 /usr/lib64
)

MODULE_DIR="/usr/libexec/snuk-audit"

tmp_elf=$(mktemp) || exit 1
tmp_missing=$(mktemp) || exit 1
tmp_symlinks=$(mktemp) || exit 1
tmp_files=$(mktemp) || exit 1

cleanup()
{
    rm -f "$tmp_elf" "$tmp_missing" \
          "$tmp_symlinks" "$tmp_files"
}
trap cleanup EXIT

echo "Snukware System Integrity Audit v$VERSION"
echo

########################################
# FILE LIST
########################################

find "${ROOTS[@]}" -type f 2>/dev/null > "$tmp_files"

TOTAL=$(wc -l < "$tmp_files")
COUNT=0

########################################
# BROKEN SYMLINK CHECK
########################################

while IFS= read -r link; do
    target=$(readlink "$link")
    printf '%s -> %s\n' "$link" "$target" >> "$tmp_symlinks"
done < <(
    find "${ROOTS[@]}" -xtype l -print 2>/dev/null
)

########################################
# SCAN
########################################

while IFS= read -r file; do
    COUNT=$((COUNT + 1))

    if (( TOTAL > 0 )); then
        PERCENT=$((COUNT * 100 / TOTAL))
    else
        PERCENT=100
    fi

    printf '\r[snuk-audit] scanning: %d/%d (%d%%)' \
        "$COUNT" "$TOTAL" "$PERCENT"

    # ELF?
    head -c 4 "$file" 2>/dev/null |
        grep -q $'\x7fELF' || continue

    ####################################
    # ELF HEADER CHECK
    ####################################

    if ! readelf -h "$file" >/dev/null 2>&1; then
        echo "$file" >> "$tmp_elf"
        continue
    fi

    ####################################
    # SPECIAL RUNTIME MODULES
    #
    # These files are checked by their
    # dedicated validators below.
    ####################################

    case "$file" in
        /usr/lib64/firefox/*|\
        /usr/lib64/thunderbird/*|\
        /usr/lib64/seamonkey/*|\
        /usr/lib64/systemd/*)
            continue
            ;;
    esac

    ####################################
    # GENERAL RUNTIME DEPENDENCIES
    ####################################

    while IFS= read -r line; do
        printf '%s :: %s\n' "$file" "$line" >> "$tmp_missing"
    done < <(
        ldd "$file" 2>/dev/null |
            grep 'not found'
    )

done < "$tmp_files"

echo
echo

########################################
# GENERAL RESULTS
########################################

echo "=== BROKEN ELF FILES ==="

if [[ -s "$tmp_elf" ]]; then
    sort -u "$tmp_elf"
else
    echo "none"
fi

echo
echo "=== MISSING DEPENDENCIES ==="

if [[ -s "$tmp_missing" ]]; then
    sort -u "$tmp_missing"
else
    echo "none"
fi

echo
echo "=== BROKEN SYMLINKS ==="

if [[ -s "$tmp_symlinks" ]]; then
    sort -u "$tmp_symlinks"
else
    echo "none"
fi

ELF_COUNT=$(sort -u "$tmp_elf" | wc -l)
MISSING_COUNT=$(sort -u "$tmp_missing" | wc -l)
SYMLINK_COUNT=$(sort -u "$tmp_symlinks" | wc -l)

echo
echo "=== GENERAL SUMMARY ==="
echo "Broken ELF files:    $ELF_COUNT"
echo "Missing dependencies: $MISSING_COUNT"
echo "Broken symlinks:     $SYMLINK_COUNT"

########################################
# SPECIAL RUNTIME CHECKS
########################################

echo
echo "=== SPECIAL RUNTIME CHECKS ==="

SPECIAL_FAILS=0

if [[ -r "$MODULE_DIR/snuk-audit-mozilla.sh" ]]; then
    source "$MODULE_DIR/snuk-audit-mozilla.sh"

    if snuk_mozilla_check; then
        echo "[OK]   Mozilla runtime checks"
    else
        echo "[FAIL] Mozilla runtime checks"
        SPECIAL_FAILS=$((SPECIAL_FAILS + 1))
    fi
else
    echo "[FAIL] Mozilla audit module unavailable"
    SPECIAL_FAILS=$((SPECIAL_FAILS + 1))
fi

if [[ -r "$MODULE_DIR/snuk-audit-systemd.sh" ]]; then
    source "$MODULE_DIR/snuk-audit-systemd.sh"

    if snuk_systemd_check; then
        echo "[OK]   systemd runtime checks"
    else
        echo "[FAIL] systemd runtime checks"
        SPECIAL_FAILS=$((SPECIAL_FAILS + 1))
    fi
else
    echo "[FAIL] systemd audit module unavailable"
    SPECIAL_FAILS=$((SPECIAL_FAILS + 1))
fi

########################################
# FINAL SUMMARY
########################################

GENERAL_ERRORS=$((ELF_COUNT + MISSING_COUNT + SYMLINK_COUNT))
TOTAL_ERRORS=$((GENERAL_ERRORS + SPECIAL_FAILS))

echo
echo "=== FINAL SUMMARY ==="
echo "General findings: $GENERAL_ERRORS"
echo "Special check failures: $SPECIAL_FAILS"
echo "Total errors: $TOTAL_ERRORS"

if (( TOTAL_ERRORS == 0 )); then
    echo
    echo "System integrity checks passed."
    exit 0
else
    echo
    echo "System integrity problems detected."
    exit 1
fi
