feat: release 2.1.8-SAC — security phase 1 and SAC-first update hardening
Updater applies chmod/chown on config, spool and state paths on every run. SAC is the primary update path; optional cron uses the same behavior. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
#!/bin/bash
|
||||
# Path permission helpers for ssh-monitor, sac-client, watchdog, updater.
|
||||
# shellcheck shell=bash
|
||||
|
||||
ssh_monitor_config_peek() {
|
||||
local key="$1" file="$2" default="${3:-}"
|
||||
local line val
|
||||
[ -f "$file" ] || {
|
||||
printf '%s\n' "$default"
|
||||
return 0
|
||||
}
|
||||
line="$(grep -E "^[[:space:]]*${key}=" "$file" 2>/dev/null | tail -1)" || {
|
||||
printf '%s\n' "$default"
|
||||
return 0
|
||||
}
|
||||
val="${line#*=}"
|
||||
val="${val#"${val%%[![:space:]]*}"}"
|
||||
val="${val%"${val##*[![:space:]]}"}"
|
||||
val="${val#\"}"
|
||||
val="${val%\"}"
|
||||
val="${val#\'}"
|
||||
val="${val%\'}"
|
||||
printf '%s\n' "$val"
|
||||
}
|
||||
|
||||
ssh_monitor_truthy() {
|
||||
case "${1,,}" in
|
||||
1 | yes | true | on) return 0 ;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
ssh_monitor_path_mode() {
|
||||
local path="$1"
|
||||
[ -e "$path" ] || return 1
|
||||
stat -c '%a' "$path" 2>/dev/null || stat -f '%OLp' "$path" 2>/dev/null
|
||||
}
|
||||
|
||||
ssh_monitor_path_owner() {
|
||||
local path="$1"
|
||||
[ -e "$path" ] || return 1
|
||||
stat -c '%U:%G' "$path" 2>/dev/null
|
||||
}
|
||||
|
||||
ssh_monitor_is_root_owned() {
|
||||
local path="$1" own
|
||||
[ -e "$path" ] || return 0
|
||||
own="$(ssh_monitor_path_owner "$path" 2>/dev/null || true)"
|
||||
[ "$own" = "root:root" ]
|
||||
}
|
||||
|
||||
ssh_monitor_secure_dir() {
|
||||
local dir="$1"
|
||||
[ -n "$dir" ] || return 1
|
||||
mkdir -p "$dir" 2>/dev/null || return 1
|
||||
chmod 700 "$dir" 2>/dev/null || true
|
||||
chown root:root "$dir" 2>/dev/null || true
|
||||
}
|
||||
|
||||
ssh_monitor_secure_file() {
|
||||
local file="$1"
|
||||
local dir
|
||||
[ -n "$file" ] || return 1
|
||||
dir="$(dirname "$file")"
|
||||
ssh_monitor_secure_dir "$dir" || true
|
||||
if [ ! -f "$file" ]; then
|
||||
: >"$file" 2>/dev/null || touch "$file" 2>/dev/null || return 1
|
||||
fi
|
||||
chmod 600 "$file" 2>/dev/null || true
|
||||
chown root:root "$file" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Существующий файл или каталог: 600/700 root:root; для отсутствующего пути — только родительский каталог.
|
||||
ssh_monitor_harden_path() {
|
||||
local path="$1"
|
||||
[ -n "$path" ] || return 0
|
||||
if [ -d "$path" ]; then
|
||||
ssh_monitor_secure_dir "$path"
|
||||
elif [ -f "$path" ] || [ -L "$path" ]; then
|
||||
ssh_monitor_secure_file "$path"
|
||||
else
|
||||
local parent
|
||||
parent="$(dirname "$path")"
|
||||
[ -n "$parent" ] && [ "$parent" != "." ] && ssh_monitor_secure_dir "$parent"
|
||||
fi
|
||||
}
|
||||
|
||||
ssh_monitor_warn_path_perms() {
|
||||
local path="$1" kind="$2" max_mode="${3:-600}"
|
||||
local mode own msg
|
||||
[ -e "$path" ] || return 0
|
||||
if ! ssh_monitor_is_root_owned "$path"; then
|
||||
own="$(ssh_monitor_path_owner "$path" 2>/dev/null || echo '?')"
|
||||
msg="WARN: ${kind} ${path}: владелец ${own}, ожидается root:root"
|
||||
printf '%s\n' "$msg" >&2
|
||||
[ -n "${write_log:-}" ] && write_log "$msg" || true
|
||||
fi
|
||||
mode="$(ssh_monitor_path_mode "$path" 2>/dev/null || echo "")"
|
||||
if [ -n "$mode" ] && [ "$((10#$mode))" -gt "$((10#$max_mode))" ]; then
|
||||
msg="WARN: ${kind} ${path}: mode ${mode}, рекомендуется не шире ${max_mode}"
|
||||
printf '%s\n' "$msg" >&2
|
||||
[ -n "${write_log:-}" ] && write_log "$msg" || true
|
||||
fi
|
||||
}
|
||||
|
||||
ssh_monitor_check_config_file_perms() {
|
||||
local file="${1:-/etc/ssh-monitor.conf}"
|
||||
local strict="${2:-0}"
|
||||
local mode msg
|
||||
[ -f "$file" ] || return 0
|
||||
if ! ssh_monitor_is_root_owned "$file"; then
|
||||
msg="WARN: конфиг ${file}: владелец $(ssh_monitor_path_owner "$file" 2>/dev/null || echo '?'), ожидается root:root"
|
||||
printf '%s\n' "$msg" >&2
|
||||
[ -n "${write_log:-}" ] && write_log "$msg" || true
|
||||
if ssh_monitor_truthy "$strict"; then
|
||||
printf '%s\n' "CONFIG_STRICT_PERMS=1: исправьте владельца конфига (chown root:root ${file})" >&2
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
mode="$(ssh_monitor_path_mode "$file" 2>/dev/null || echo "")"
|
||||
case "$mode" in
|
||||
600 | 400) ;;
|
||||
*)
|
||||
msg="WARN: конфиг ${file}: mode ${mode:-?}, рекомендуется 600 или 400 (chmod 600 ${file})"
|
||||
printf '%s\n' "$msg" >&2
|
||||
[ -n "${write_log:-}" ] && write_log "$msg" || true
|
||||
if ssh_monitor_truthy "$strict"; then
|
||||
printf '%s\n' "CONFIG_STRICT_PERMS=1: ослабленные права конфига недопустимы" >&2
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
Reference in New Issue
Block a user