#!/bin/bash # freeloader-helper.sh # Restricted privileged helper for Freeloader # Only allows specific operations on a hard-coded whitelist of directories. # N5AD / hardened - July 2026 set -euo pipefail # ============================================================ # HARD-CODED ALLOWED BASE DIRECTORIES # Must match freeloader_allowed_dirs() in freeloader_common.php # Excludes /usr/local/bin and /var/www/html/freeloader intentionally. # ============================================================ ALLOWED_DIRS=( "/my_uploads" "/etc/asterisk" "/etc/asterisk/local" "/etc/allmon3" "/var/lib/asterisk" "/var/www/html/supermon" "/usr/share/allmon3" ) is_allowed_path() { local target="$1" local resolved resolved=$(realpath -e "$target" 2>/dev/null) || return 1 local dir for dir in "${ALLOWED_DIRS[@]}"; do local basedir basedir=$(realpath -e "$dir" 2>/dev/null) || continue if [[ "$resolved" == "$basedir" || "$resolved" == "$basedir"/* ]]; then return 0 fi done return 1 } die() { echo "ERROR: $*" >&2 exit 1 } cmd="${1:-}" case "$cmd" in cat) [[ $# -eq 2 ]] || die "cat requires exactly one path" target="$2" is_allowed_path "$target" || die "Path not allowed: $target" [[ -f "$target" ]] || die "Not a regular file: $target" cat -- "$target" ;; cp) [[ $# -eq 3 ]] || die "cp requires src and dst" src="$2" dst="$3" [[ -f "$src" ]] || die "Source not found or not a file: $src" dstdir=$(dirname -- "$dst") is_allowed_path "$dstdir" || die "Destination directory not allowed: $dstdir" real_dst_dir=$(realpath -e "$dstdir") base_name=$(basename -- "$dst") [[ "$base_name" != *..* && "$base_name" != */* ]] || die "Invalid destination filename" # Block executable / webshell extensions at the helper boundary case "${base_name,,}" in *.php|*.phtml|*.php3|*.php4|*.php5|*.php7|*.php8|*.phar|*.exe|*.cgi|*.asp|*.aspx|*.jsp|.htaccess|htaccess|.htpasswd) die "Refusing to write dangerous filename: $base_name" ;; esac cp -- "$src" "$real_dst_dir/$base_name" chmod 644 "$real_dst_dir/$base_name" 2>/dev/null || true ;; rm) [[ $# -eq 2 ]] || die "rm requires exactly one path" target="$2" is_allowed_path "$target" || die "Path not allowed: $target" [[ -f "$target" ]] || die "Not a regular file (or does not exist): $target" rm -f -- "$target" ;; restart_asterisk) [[ $# -eq 1 ]] || die "restart_asterisk takes no arguments" systemctl restart asterisk ;; *) die "Unknown or missing command. Allowed: cat, cp, rm, restart_asterisk" ;; esac exit 0