mirror of
https://github.com/kuhyx/testsAndMisc-archive.git
synced 2026-11-10 20:27:04 +01:00
fix: shellcheck issues
This commit is contained in:
parent
dcd4251992
commit
fef44f0015
@ -9,24 +9,24 @@ TARGET="/etc/hosts"
|
||||
LOG_FILE="/var/log/hosts-guard.log"
|
||||
|
||||
log() {
|
||||
printf '%s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" | tee -a "$LOG_FILE" >&2
|
||||
printf '%s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" | tee -a "$LOG_FILE" >&2
|
||||
}
|
||||
|
||||
if [[ ! -f "$CANONICAL_SOURCE" ]]; then
|
||||
log "Canonical hosts not found at $CANONICAL_SOURCE; aborting enforcement"
|
||||
exit 0
|
||||
if [[ ! -f $CANONICAL_SOURCE ]]; then
|
||||
log "Canonical hosts not found at $CANONICAL_SOURCE; aborting enforcement"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! cmp -s "$CANONICAL_SOURCE" "$TARGET"; then
|
||||
log "Difference detected – restoring $TARGET from canonical copy"
|
||||
cp "$CANONICAL_SOURCE" "$TARGET"
|
||||
chmod 644 "$TARGET"
|
||||
log "Difference detected – restoring $TARGET from canonical copy"
|
||||
cp "$CANONICAL_SOURCE" "$TARGET"
|
||||
chmod 644 "$TARGET"
|
||||
else
|
||||
log "No drift detected (contents identical)"
|
||||
log "No drift detected (contents identical)"
|
||||
fi
|
||||
|
||||
# Re-apply protective attributes: immutable first, then read-only bind mount handled by separate unit
|
||||
chattr -i -a "$TARGET" 2>/dev/null || true
|
||||
chattr -i -a "$TARGET" 2> /dev/null || true
|
||||
chattr +i "$TARGET" || log "Failed to set immutable attribute"
|
||||
|
||||
log "Enforcement complete"
|
||||
log "Enforcement complete"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
require_root() { if [[ $EUID -ne 0 ]]; then exec sudo -E bash "$0" "$@"; fi }
|
||||
require_root() { if [[ $EUID -ne 0 ]]; then exec sudo -E bash "$0" "$@"; fi; }
|
||||
require_root "$@"
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
@ -10,7 +10,7 @@ HOOKS_DIR="/etc/pacman.d/hooks"
|
||||
install -d -m 755 "$HOOKS_DIR"
|
||||
|
||||
# Pre-transaction hook
|
||||
cat >"$HOOKS_DIR/10-unlock-etc-hosts.hook" <<'HOOK'
|
||||
cat > "$HOOKS_DIR/10-unlock-etc-hosts.hook" << 'HOOK'
|
||||
[Trigger]
|
||||
Operation = Upgrade
|
||||
Operation = Install
|
||||
@ -26,7 +26,7 @@ NeedsTargets
|
||||
HOOK
|
||||
|
||||
# Post-transaction hook
|
||||
cat >"$HOOKS_DIR/90-relock-etc-hosts.hook" <<'HOOK'
|
||||
cat > "$HOOKS_DIR/90-relock-etc-hosts.hook" << 'HOOK'
|
||||
[Trigger]
|
||||
Operation = Upgrade
|
||||
Operation = Install
|
||||
|
||||
@ -5,22 +5,22 @@ TARGET=/etc/hosts
|
||||
ENFORCE=/usr/local/sbin/enforce-hosts.sh
|
||||
LOGTAG=hosts-guard-hook
|
||||
|
||||
mount_layers_count() { awk '$5=="/etc/hosts"{c++} END{print c+0}' /proc/self/mountinfo 2>/dev/null || echo 0; }
|
||||
mount_layers_count() { awk '$5=="/etc/hosts"{c++} END{print c+0}' /proc/self/mountinfo 2> /dev/null || echo 0; }
|
||||
collapse_mounts() {
|
||||
local i=0
|
||||
if command -v mountpoint >/devnull 2>&1; then
|
||||
if command -v mountpoint > /devnull 2>&1; then
|
||||
while mountpoint -q "$TARGET"; do
|
||||
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||
i=$((i+1))
|
||||
(( i > 20 )) && break
|
||||
umount -l "$TARGET" > /dev/null 2>&1 || break
|
||||
i=$((i + 1))
|
||||
((i > 20)) && break
|
||||
done
|
||||
else
|
||||
local cnt
|
||||
cnt=$(mount_layers_count)
|
||||
while (( cnt > 1 )); do
|
||||
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||
i=$((i+1))
|
||||
(( i > 20 )) && break
|
||||
while ((cnt > 1)); do
|
||||
umount -l "$TARGET" > /dev/null 2>&1 || break
|
||||
i=$((i + 1))
|
||||
((i > 20)) && break
|
||||
cnt=$(mount_layers_count)
|
||||
done
|
||||
fi
|
||||
@ -28,23 +28,23 @@ collapse_mounts() {
|
||||
|
||||
# Ensure we end with a single read-only bind mount layer
|
||||
logger -t "$LOGTAG" "post: relocking /etc/hosts (starting)"
|
||||
echo "$(date -Is) post-relock(start)" >> /run/hosts-guard-hook.log 2>/dev/null || true
|
||||
echo "$(date -Is) post-relock(start)" >> /run/hosts-guard-hook.log 2> /dev/null || true
|
||||
collapse_mounts
|
||||
|
||||
if [[ -x "$ENFORCE" ]]; then
|
||||
"$ENFORCE" >/dev/null 2>&1 || true
|
||||
if [[ -x $ENFORCE ]]; then
|
||||
"$ENFORCE" > /dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
# Apply exactly one ro bind layer
|
||||
mount --bind "$TARGET" "$TARGET" >/dev/null 2>&1 || true
|
||||
mount -o remount,ro,bind "$TARGET" >/dev/null 2>&1 || true
|
||||
mount --bind "$TARGET" "$TARGET" > /dev/null 2>&1 || true
|
||||
mount -o remount,ro,bind "$TARGET" > /dev/null 2>&1 || true
|
||||
|
||||
# Start only the path watcher; avoid bind-mount service (we already bound once)
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl start hosts-guard.path >/dev/null 2>&1 || true
|
||||
if command -v systemctl > /dev/null 2>&1; then
|
||||
systemctl start hosts-guard.path > /dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
logger -t "$LOGTAG" "post: relocking /etc/hosts (done)"
|
||||
echo "$(date -Is) post-relock(done)" >> /run/hosts-guard-hook.log 2>/dev/null || true
|
||||
echo "$(date -Is) post-relock(done)" >> /run/hosts-guard-hook.log 2> /dev/null || true
|
||||
|
||||
exit 0
|
||||
|
||||
@ -7,58 +7,57 @@ LOGTAG=hosts-guard-hook
|
||||
stop_units_if_present() {
|
||||
local units=(hosts-bind-mount.service hosts-guard.path)
|
||||
for u in "${units[@]}"; do
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
if systemctl list-unit-files 2>/dev/null | grep -q "^$u"; then
|
||||
systemctl stop "$u" >/dev/null 2>&1 || true
|
||||
if command -v systemctl > /dev/null 2>&1; then
|
||||
if systemctl list-unit-files 2> /dev/null | grep -q "^$u"; then
|
||||
systemctl stop "$u" > /dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
is_ro_mount() { findmnt -no OPTIONS -T "$TARGET" 2>/dev/null | grep -qw ro; }
|
||||
is_bind_mount() { findmnt -no OPTIONS -T "$TARGET" 2>/dev/null | grep -qw bind; }
|
||||
is_ro_mount() { findmnt -no OPTIONS -T "$TARGET" 2> /dev/null | grep -qw ro; }
|
||||
|
||||
mount_layers_count() { awk '$5=="/etc/hosts"{c++} END{print c+0}' /proc/self/mountinfo 2>/dev/null || echo 0; }
|
||||
mount_layers_count() { awk '$5=="/etc/hosts"{c++} END{print c+0}' /proc/self/mountinfo 2> /dev/null || echo 0; }
|
||||
cleanup_mount_stacks() {
|
||||
local i=0
|
||||
# Unmount bind layers until /etc/hosts is no longer a mountpoint
|
||||
if command -v mountpoint >/dev/null 2>&1; then
|
||||
if command -v mountpoint > /dev/null 2>&1; then
|
||||
while mountpoint -q "$TARGET"; do
|
||||
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||
i=$((i+1))
|
||||
(( i > 20 )) && break
|
||||
umount -l "$TARGET" > /dev/null 2>&1 || break
|
||||
i=$((i + 1))
|
||||
((i > 20)) && break
|
||||
done
|
||||
else
|
||||
# Fallback to best-effort using mountinfo count
|
||||
local cnt
|
||||
cnt=$(mount_layers_count)
|
||||
while (( cnt > 1 )); do
|
||||
umount -l "$TARGET" >/dev/null 2>&1 || break
|
||||
i=$((i+1))
|
||||
(( i > 20 )) && break
|
||||
while ((cnt > 1)); do
|
||||
umount -l "$TARGET" > /dev/null 2>&1 || break
|
||||
i=$((i + 1))
|
||||
((i > 20)) && break
|
||||
cnt=$(mount_layers_count)
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Drop protective attributes if present
|
||||
if command -v lsattr >/dev/null 2>&1; then
|
||||
attrs=$(lsattr -d "$TARGET" 2>/dev/null || true)
|
||||
echo "$attrs" | grep -q " i " && chattr -i "$TARGET" >/dev/null 2>&1 || true
|
||||
echo "$attrs" | grep -q " a " && chattr -a "$TARGET" >/dev/null 2>&1 || true
|
||||
if command -v lsattr > /dev/null 2>&1; then
|
||||
attrs=$(lsattr -d "$TARGET" 2> /dev/null || true)
|
||||
echo "$attrs" | grep -q " i " && chattr -i "$TARGET" > /dev/null 2>&1 || true
|
||||
echo "$attrs" | grep -q " a " && chattr -a "$TARGET" > /dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
stop_units_if_present
|
||||
|
||||
logger -t "$LOGTAG" "pre: unlocking /etc/hosts (starting)"
|
||||
echo "$(date -Is) pre-unlock" >> /run/hosts-guard-hook.log 2>/dev/null || true
|
||||
echo "$(date -Is) pre-unlock" >> /run/hosts-guard-hook.log 2> /dev/null || true
|
||||
|
||||
# Always collapse any existing layers; we'll operate on the plain file
|
||||
cleanup_mount_stacks
|
||||
|
||||
# If someone managed a ro single-layer mount, ensure rw by remounting or collapsing again
|
||||
if is_ro_mount; then
|
||||
mount -o remount,rw "$TARGET" >/dev/null 2>&1 || cleanup_mount_stacks
|
||||
mount -o remount,rw "$TARGET" > /dev/null 2>&1 || cleanup_mount_stacks
|
||||
fi
|
||||
|
||||
logger -t "$LOGTAG" "pre: unlocking /etc/hosts (done)"
|
||||
|
||||
@ -11,36 +11,36 @@ DELAY_SECONDS=45
|
||||
|
||||
log() { printf '%s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" | tee -a "$LOG" >&2; }
|
||||
|
||||
require_root() { if [[ $EUID -ne 0 ]]; then exec sudo -E bash "$0" "$@"; fi }
|
||||
require_root() { if [[ $EUID -ne 0 ]]; then exec sudo -E bash "$0" "$@"; fi; }
|
||||
require_root "$@"
|
||||
|
||||
echo "Reason for editing /etc/hosts (will be logged):" >&2
|
||||
read -r -p "Enter reason: " REASON
|
||||
if [[ -z ${REASON// } ]]; then
|
||||
echo "Empty reason not allowed. Aborting." >&2
|
||||
exit 1
|
||||
if [[ -z ${REASON// /} ]]; then
|
||||
echo "Empty reason not allowed. Aborting." >&2
|
||||
exit 1
|
||||
fi
|
||||
log "Requested intentional /etc/hosts modification session. Reason: $REASON"
|
||||
logger -t "$SYSLOG_TAG" "session_start user=${SUDO_USER:-$USER} reason='$REASON'"
|
||||
echo "This action is logged. A cooling-off delay of $DELAY_SECONDS seconds applies." >&2
|
||||
|
||||
for s in hosts-bind-mount.service hosts-guard.path; do
|
||||
if systemctl is-active --quiet "$s"; then
|
||||
log "Stopping $s"
|
||||
systemctl stop "$s" || true
|
||||
fi
|
||||
if systemctl is-enabled --quiet "$s"; then
|
||||
log "(Will re-enable later)"
|
||||
fi
|
||||
if systemctl is-active --quiet "$s"; then
|
||||
log "Stopping $s"
|
||||
systemctl stop "$s" || true
|
||||
fi
|
||||
if systemctl is-enabled --quiet "$s"; then
|
||||
log "(Will re-enable later)"
|
||||
fi
|
||||
done
|
||||
|
||||
# Remove attributes to allow edit
|
||||
chattr -i -a "$TARGET" 2>/dev/null || true
|
||||
chattr -i -a "$TARGET" 2> /dev/null || true
|
||||
|
||||
echo "Countdown:" >&2
|
||||
for ((i=DELAY_SECONDS; i>0; i--)); do
|
||||
printf '\rEdit window opens in %2d seconds... Press Ctrl+C to abort.' "$i" >&2
|
||||
sleep 1
|
||||
for ((i = DELAY_SECONDS; i > 0; i--)); do
|
||||
printf '\rEdit window opens in %2d seconds... Press Ctrl+C to abort.' "$i" >&2
|
||||
sleep 1
|
||||
done
|
||||
echo >&2
|
||||
|
||||
@ -49,13 +49,13 @@ sha_before=$(sha256sum "$TARGET" | awk '{print $1}')
|
||||
"$EDITOR_CMD" "$TARGET"
|
||||
sha_after=$(sha256sum "$TARGET" | awk '{print $1}')
|
||||
|
||||
if [[ "$sha_before" == "$sha_after" ]]; then
|
||||
log "No changes made to $TARGET. Reason: $REASON"
|
||||
logger -t "$SYSLOG_TAG" "no_change user=${SUDO_USER:-$USER} reason='$REASON'"
|
||||
if [[ $sha_before == "$sha_after" ]]; then
|
||||
log "No changes made to $TARGET. Reason: $REASON"
|
||||
logger -t "$SYSLOG_TAG" "no_change user=${SUDO_USER:-$USER} reason='$REASON'"
|
||||
else
|
||||
log "Changes detected. Updating canonical copy and re-enforcing. Reason: $REASON"
|
||||
logger -t "$SYSLOG_TAG" "modified user=${SUDO_USER:-$USER} reason='$REASON'"
|
||||
cp "$TARGET" "$CANON"
|
||||
log "Changes detected. Updating canonical copy and re-enforcing. Reason: $REASON"
|
||||
logger -t "$SYSLOG_TAG" "modified user=${SUDO_USER:-$USER} reason='$REASON'"
|
||||
cp "$TARGET" "$CANON"
|
||||
fi
|
||||
|
||||
# Re-run enforcement
|
||||
|
||||
@ -46,10 +46,20 @@ ADD_ALIAS_STUB=1
|
||||
msg() { printf '\e[1;32m[+]\e[0m %s\n' "$*"; }
|
||||
note() { printf '\e[1;34m[i]\e[0m %s\n' "$*"; }
|
||||
warn() { printf '\e[1;33m[!]\e[0m %s\n' "$*"; }
|
||||
err() { printf '\e[1;31m[x]\e[0m %s\n' "$*" >&2; }
|
||||
run() { if [[ $DRY_RUN -eq 1 ]]; then printf 'DRY-RUN: %s\n' "$*"; else eval "$@"; fi }
|
||||
err() { printf '\e[1;31m[x]\e[0m %s\n' "$*" >&2; }
|
||||
run() {
|
||||
if [[ $DRY_RUN -eq 1 ]]; then
|
||||
printf 'DRY-RUN:'
|
||||
if [ "$#" -gt 0 ]; then
|
||||
printf ' %q' "$@"
|
||||
fi
|
||||
printf '\n'
|
||||
else
|
||||
"$@"
|
||||
fi
|
||||
}
|
||||
|
||||
require_root() { if [[ $EUID -ne 0 ]]; then exec sudo -E bash "$0" "$@"; fi }
|
||||
require_root() { if [[ $EUID -ne 0 ]]; then exec sudo -E bash "$0" "$@"; fi; }
|
||||
|
||||
usage() { sed -n '1,/^set -euo pipefail/p' "$0" | sed 's/^# \{0,1\}//'; }
|
||||
|
||||
@ -58,21 +68,71 @@ usage() { sed -n '1,/^set -euo pipefail/p' "$0" | sed 's/^# \{0,1\}//'; }
|
||||
######################################################################
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--force-snapshot) FORCE_SNAPSHOT=1 ; shift ;;
|
||||
--no-snapshot) DO_SNAPSHOT=0 ; shift ;;
|
||||
--skip-bind) ENABLE_BIND=0 ; shift ;;
|
||||
--skip-path-watch) ENABLE_PATH=0 ; shift ;;
|
||||
--delay) DELAY=${2:-} ; [[ -z ${DELAY} ]] && { err '--delay requires value'; exit 2; } ; shift 2 ;;
|
||||
--dry-run) DRY_RUN=1 ; shift ;;
|
||||
--no-shell-hooks) INSTALL_SHELL_HOOKS=0 ; shift ;;
|
||||
--shell-hooks) INSTALL_SHELL_HOOKS=1 ; shift ;;
|
||||
--no-audit) INSTALL_AUDIT_RULE=0 ; shift ;;
|
||||
--audit) INSTALL_AUDIT_RULE=1 ; shift ;;
|
||||
--no-alias-stub) ADD_ALIAS_STUB=0 ; shift ;;
|
||||
--alias-stub) ADD_ALIAS_STUB=1 ; shift ;;
|
||||
--uninstall) UNINSTALL=1 ; shift ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) err "Unknown argument: $1"; usage; exit 2 ;;
|
||||
--force-snapshot)
|
||||
FORCE_SNAPSHOT=1
|
||||
shift
|
||||
;;
|
||||
--no-snapshot)
|
||||
DO_SNAPSHOT=0
|
||||
shift
|
||||
;;
|
||||
--skip-bind)
|
||||
ENABLE_BIND=0
|
||||
shift
|
||||
;;
|
||||
--skip-path-watch)
|
||||
ENABLE_PATH=0
|
||||
shift
|
||||
;;
|
||||
--delay)
|
||||
DELAY=${2:-}
|
||||
[[ -z ${DELAY} ]] && {
|
||||
err '--delay requires value'
|
||||
exit 2
|
||||
}
|
||||
shift 2
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=1
|
||||
shift
|
||||
;;
|
||||
--no-shell-hooks)
|
||||
INSTALL_SHELL_HOOKS=0
|
||||
shift
|
||||
;;
|
||||
--shell-hooks)
|
||||
INSTALL_SHELL_HOOKS=1
|
||||
shift
|
||||
;;
|
||||
--no-audit)
|
||||
INSTALL_AUDIT_RULE=0
|
||||
shift
|
||||
;;
|
||||
--audit)
|
||||
INSTALL_AUDIT_RULE=1
|
||||
shift
|
||||
;;
|
||||
--no-alias-stub)
|
||||
ADD_ALIAS_STUB=0
|
||||
shift
|
||||
;;
|
||||
--alias-stub)
|
||||
ADD_ALIAS_STUB=1
|
||||
shift
|
||||
;;
|
||||
--uninstall)
|
||||
UNINSTALL=1
|
||||
shift
|
||||
;;
|
||||
-h | --help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
err "Unknown argument: $1"
|
||||
usage
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@ -119,7 +179,7 @@ if [[ $UNINSTALL -eq 1 ]]; then
|
||||
"$SYSTEMD_DIR/hosts-bind-mount.service" \
|
||||
"$ZSH_FILTER_SNIPPET" \
|
||||
"$BASH_FILTER_SNIPPET"; do
|
||||
if [[ -e $f ]]; then run rm -f "$f"; fi
|
||||
if [[ -e $f ]]; then run rm -f "$f"; fi
|
||||
done
|
||||
note "Leaving canonical snapshot at $CANON (remove manually if undesired)."
|
||||
if [[ $DRY_RUN -eq 0 ]]; then systemctl daemon-reload; fi
|
||||
@ -134,10 +194,13 @@ note "Script directory: $SCRIPT_DIR"
|
||||
note "Repository root: $REPO_ROOT"
|
||||
|
||||
for req in "$TEMPLATE_ENFORCE" "$TEMPLATE_UNLOCK" "$UNIT_GUARD_SERVICE"; do
|
||||
[[ -f $req ]] || { err "Missing template: $req"; exit 1; }
|
||||
[[ -f $req ]] || {
|
||||
err "Missing template: $req"
|
||||
exit 1
|
||||
}
|
||||
done
|
||||
|
||||
if [[ ! -f "$HOSTS" ]]; then
|
||||
if [[ ! -f $HOSTS ]]; then
|
||||
err "$HOSTS does not exist. Run your hosts/install.sh first."
|
||||
exit 1
|
||||
fi
|
||||
@ -146,7 +209,7 @@ fi
|
||||
# Snapshot
|
||||
######################################################################
|
||||
if [[ $DO_SNAPSHOT -eq 1 ]]; then
|
||||
if [[ -f "$CANON" && $FORCE_SNAPSHOT -eq 0 ]]; then
|
||||
if [[ -f $CANON && $FORCE_SNAPSHOT -eq 0 ]]; then
|
||||
note "Canonical snapshot exists (use --force-snapshot to overwrite)"
|
||||
else
|
||||
msg "Creating canonical snapshot at $CANON"
|
||||
@ -182,14 +245,12 @@ fi
|
||||
if [[ $INSTALL_SHELL_HOOKS -eq 1 ]]; then
|
||||
msg "Installing shell history suppression hooks for unlock command"
|
||||
# Pattern matches commands invoking unlock-hosts (with or without sudo) & setup script force snapshot
|
||||
FILTER_PATTERN='(^|;|&&|\|\|)\s*(sudo\s+)?(/usr/local/sbin/)?unlock-hosts(\s|;|$)'
|
||||
|
||||
# Zsh: use zshaddhistory function
|
||||
if command -v zsh >/dev/null 2>&1; then
|
||||
if command -v zsh > /dev/null 2>&1; then
|
||||
if [[ $DRY_RUN -eq 1 ]]; then
|
||||
echo "DRY-RUN: would create $ZSH_FILTER_SNIPPET"
|
||||
else
|
||||
cat > "$ZSH_FILTER_SNIPPET" <<'ZEOF'
|
||||
cat > "$ZSH_FILTER_SNIPPET" << 'ZEOF'
|
||||
# Added by hosts guard setup – suppress unlock-hosts commands from Zsh history
|
||||
autoload -Uz add-zsh-hook 2>/dev/null || true
|
||||
_hosts_guard_history_filter() {
|
||||
@ -213,11 +274,11 @@ ZEOF
|
||||
fi
|
||||
|
||||
# Bash: rely on HISTCONTROL and PROMPT_COMMAND filter
|
||||
if command -v bash >/dev/null 2>&1; then
|
||||
if command -v bash > /dev/null 2>&1; then
|
||||
if [[ $DRY_RUN -eq 1 ]]; then
|
||||
echo "DRY-RUN: would create $BASH_FILTER_SNIPPET"
|
||||
else
|
||||
cat > "$BASH_FILTER_SNIPPET" <<'BEOF'
|
||||
cat > "$BASH_FILTER_SNIPPET" << 'BEOF'
|
||||
# Added by hosts guard setup – suppress unlock-hosts commands from Bash history
|
||||
export HISTCONTROL=ignoredups:erasedups
|
||||
_hosts_guard_hist_filter() {
|
||||
@ -253,7 +314,7 @@ if [[ $ADD_ALIAS_STUB -eq 1 ]]; then
|
||||
if [[ $DRY_RUN -eq 1 ]]; then
|
||||
echo "DRY-RUN: would create $PROFILE_STUB"
|
||||
else
|
||||
cat > "$PROFILE_STUB" <<'ASTUB'
|
||||
cat > "$PROFILE_STUB" << 'ASTUB'
|
||||
# Added by hosts guard setup – discourages casual use of unlock-hosts name
|
||||
if command -v unlock-hosts >/dev/null 2>&1; then
|
||||
alias unlock-hosts='command_not_found_handle 2>/dev/null || echo "Use: sudo /usr/local/sbin/unlock-hosts (logged & delayed)"'
|
||||
@ -267,16 +328,17 @@ fi
|
||||
# Audit rule to record executions (requires auditd)
|
||||
######################################################################
|
||||
if [[ $INSTALL_AUDIT_RULE -eq 1 ]]; then
|
||||
if command -v auditctl >/dev/null 2>&1; then
|
||||
AUDIT_RULE="-w /usr/local/sbin/unlock-hosts -p x -k hosts_unlock"
|
||||
if auditctl -l 2>/dev/null | grep -Fq "/usr/local/sbin/unlock-hosts"; then
|
||||
if command -v auditctl > /dev/null 2>&1; then
|
||||
audit_rule_str="-w /usr/local/sbin/unlock-hosts -p x -k hosts_unlock"
|
||||
audit_rule_args=(-w /usr/local/sbin/unlock-hosts -p x -k hosts_unlock)
|
||||
if auditctl -l 2> /dev/null | grep -Fq "/usr/local/sbin/unlock-hosts"; then
|
||||
note "Audit rule already present"
|
||||
else
|
||||
run auditctl $AUDIT_RULE || warn "Failed to add audit rule (runtime)"
|
||||
run auditctl "${audit_rule_args[@]}" || warn "Failed to add audit rule (runtime)"
|
||||
if [[ $DRY_RUN -eq 1 ]]; then
|
||||
echo "DRY-RUN: would create /etc/audit/rules.d/hosts_unlock.rules"
|
||||
else
|
||||
echo "$AUDIT_RULE" > /etc/audit/rules.d/hosts_unlock.rules
|
||||
echo "$audit_rule_str" > /etc/audit/rules.d/hosts_unlock.rules
|
||||
fi
|
||||
fi
|
||||
else
|
||||
@ -323,22 +385,22 @@ fi
|
||||
######################################################################
|
||||
echo
|
||||
msg "Hosts guard setup complete"
|
||||
echo "Canonical copy: $CANON"
|
||||
echo "Enforce script: $INSTALL_ENFORCE"
|
||||
echo "Unlock command: sudo $INSTALL_UNLOCK"
|
||||
echo "Delay (seconds): $DELAY"
|
||||
echo "Auto-revert path watch: $([[ $ENABLE_PATH -eq 1 ]] && echo enabled || echo disabled)"
|
||||
echo "Read-only bind mount: $([[ $ENABLE_BIND -eq 1 ]] && echo enabled || echo disabled)"
|
||||
echo "Canonical copy: $CANON"
|
||||
echo "Enforce script: $INSTALL_ENFORCE"
|
||||
echo "Unlock command: sudo $INSTALL_UNLOCK"
|
||||
echo "Delay (seconds): $DELAY"
|
||||
echo "Auto-revert path watch: $([[ $ENABLE_PATH -eq 1 ]] && echo enabled || echo disabled)"
|
||||
echo "Read-only bind mount: $([[ $ENABLE_BIND -eq 1 ]] && echo enabled || echo disabled)"
|
||||
echo "Shell history suppression: $([[ $INSTALL_SHELL_HOOKS -eq 1 ]] && echo enabled || echo disabled)"
|
||||
echo "Audit rule: $([[ $INSTALL_AUDIT_RULE -eq 1 ]] && echo enabled || echo disabled)"
|
||||
echo "Alias stub: $([[ $ADD_ALIAS_STUB -eq 1 ]] && echo enabled || echo disabled)"
|
||||
echo
|
||||
echo "Test flow:"
|
||||
echo " sudo sed -i '1s/.*/# tamper test/' /etc/hosts # Should revert automatically"
|
||||
echo " sudo $INSTALL_UNLOCK # Intentional edit workflow"
|
||||
echo "Test flow:"
|
||||
echo " sudo sed -i '1s/.*/# tamper test/' /etc/hosts # Should revert automatically"
|
||||
echo " sudo $INSTALL_UNLOCK # Intentional edit workflow"
|
||||
echo
|
||||
echo "Uninstall:"
|
||||
echo " sudo $0 --uninstall"
|
||||
echo "(Optional) Skip shell history hooks: --no-shell-hooks"
|
||||
echo "Uninstall:"
|
||||
echo " sudo $0 --uninstall"
|
||||
echo "(Optional) Skip shell history hooks: --no-shell-hooks"
|
||||
echo
|
||||
exit 0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user