From d7c0d12314cb4c6e67035a1fef8f0af1cb821a03 Mon Sep 17 00:00:00 2001 From: librelad Date: Sat, 23 May 2026 23:46:58 +0100 Subject: [PATCH] harden(desudo): funnel firewall/ssh/socket/systemd system ops through runSystem firewall_initial_setup + firewall_clear_rules (ufw/ufw-docker), host_access.sh (sshd/-T/-t, /etc/ssh, authorized_keys, systemctl reload), set_socket_permissions (docker socket test/chmod), and webui_install_systemd (systemd unit tee + systemctl) -> runSystem. These stay real-root in both modes and define part of the eventual scoped allowlist. Left the 'sudo -u crontab' run-as-manager lines for a dedicated pass. Co-Authored-By: Claude Opus 4.7 Signed-off-by: librelad --- .../type_switcher/set_socket_permissions.sh | 16 +++---- .../firewall/firewall_initial_setup.sh | 14 +++--- .../firewall/rules/firewall_clear_rules.sh | 8 ++-- scripts/ssh/host_access.sh | 46 +++++++++---------- scripts/webui/webui_install_systemd.sh | 8 ++-- 5 files changed, 46 insertions(+), 46 deletions(-) diff --git a/scripts/docker/type_switcher/set_socket_permissions.sh b/scripts/docker/type_switcher/set_socket_permissions.sh index d6b7577..710db7d 100755 --- a/scripts/docker/type_switcher/set_socket_permissions.sh +++ b/scripts/docker/type_switcher/set_socket_permissions.sh @@ -16,8 +16,8 @@ dockerSwitcherSetSocketPermissions() if [[ $CFG_DOCKER_INSTALL_TYPE == "rooted" ]]; then if [[ $docker_rootless_exist == "false" ]]; then # if File exists - if sudo test -e "$docker_rootless_socket"; then - local result=$(sudo chmod o-r "$docker_rootless_socket") + if runSystem test -e "$docker_rootless_socket"; then + local result=$(runSystem chmod o-r "$docker_rootless_socket") checkSuccess "Removing read permissions from Rootless docker socket." docker_rootless_found="true" else @@ -27,8 +27,8 @@ dockerSwitcherSetSocketPermissions() fi # if File exists - if sudo test -e "$docker_rooted_socket"; then - local result=$(sudo chmod +r "$docker_rooted_socket") + if runSystem test -e "$docker_rooted_socket"; then + local result=$(runSystem chmod +r "$docker_rooted_socket") checkSuccess "Adding read permissions to Rooted docker socket." docker_rooted_found="true" else @@ -39,8 +39,8 @@ dockerSwitcherSetSocketPermissions() if [[ $CFG_DOCKER_INSTALL_TYPE == "rootless" ]]; then # if File exists - if sudo test -e "$docker_rooted_socket"; then - local result=$(sudo chmod o-r "$docker_rooted_socket") + if runSystem test -e "$docker_rooted_socket"; then + local result=$(runSystem chmod o-r "$docker_rooted_socket") checkSuccess "Removing read permissions from Rooted docker socket." docker_rooted_found="true" else @@ -49,8 +49,8 @@ dockerSwitcherSetSocketPermissions() fi # if File exists - if sudo test -e "$docker_rootless_socket"; then - local result=$(sudo chmod +r "$docker_rootless_socket") + if runSystem test -e "$docker_rootless_socket"; then + local result=$(runSystem chmod +r "$docker_rootless_socket") checkSuccess "Adding read permissions to Rootless docker socket." docker_rootless_found="true" else diff --git a/scripts/network/firewall/firewall_initial_setup.sh b/scripts/network/firewall/firewall_initial_setup.sh index da3ad8b..7895e25 100755 --- a/scripts/network/firewall/firewall_initial_setup.sh +++ b/scripts/network/firewall/firewall_initial_setup.sh @@ -15,7 +15,7 @@ firewallInitialSetup() break fi if [[ "$firewallallowport_port" =~ ^[0-9]+$ && $firewallallowport_port -ge 1 && $firewallallowport_port -le 65535 ]]; then - local result=$(sudo ufw allow "$firewallallowport_port") + local result=$(runSystem ufw allow "$firewallallowport_port") checkSuccess "Opening port $firewallallowport_port in the UFW Firewall" break fi @@ -36,7 +36,7 @@ firewallInitialSetup() break fi if [[ "$firewallblockport_port" =~ ^[0-9]+$ && $firewallblockport_port -ge 1 && $firewallblockport_port -le 65535 ]]; then - local result=$(sudo ufw deny "$firewallblockport_port") + local result=$(runSystem ufw deny "$firewallblockport_port") checkSuccess "Blocking port $firewallblockport_port in the UFW Firewall" break fi @@ -49,9 +49,9 @@ firewallInitialSetup() echo "" echo "---- Block port 22 (SSH) :" echo "" - local result=$(sudo ufw deny 22) + local result=$(runSystem ufw deny 22) checkSuccess "Disabling Port 22 through the firewall" - local result=$(sudo ufw deny ssh) + local result=$(runSystem ufw deny ssh) checkSuccess "Disabling SSH through the firewall" fi @@ -60,9 +60,9 @@ firewallInitialSetup() echo "" echo "---- Allow port 22 (SSH) :" echo "" - local result=$(sudo ufw allow 22) + local result=$(runSystem ufw allow 22) checkSuccess "Allowing Port 22 through the firewall" - local result=$(sudo ufw allow ssh) + local result=$(runSystem ufw allow ssh) checkSuccess "Allowing SSH through the firewall" fi @@ -75,7 +75,7 @@ firewallInitialSetup() case "$CFG_UFW_LOGGING" in on|off|low|medium|high|full) # Valid logging type - local result=$(yes | sudo ufw logging $CFG_UFW_LOGGING) + local result=$(yes | runSystem ufw logging $CFG_UFW_LOGGING) checkSuccess "Updating UFW Firewall Logging to $CFG_UFW_LOGGING" ;; *) diff --git a/scripts/network/firewall/rules/firewall_clear_rules.sh b/scripts/network/firewall/rules/firewall_clear_rules.sh index eb97e89..d2bb5cc 100755 --- a/scripts/network/firewall/rules/firewall_clear_rules.sh +++ b/scripts/network/firewall/rules/firewall_clear_rules.sh @@ -6,7 +6,7 @@ firewallClearLibrePortalRules() local total_cleared=0 if [[ $EUID -eq 0 ]] && command -v ufw-docker &> /dev/null; then - local libreportal_rules=$(sudo ufw-docker list 2>/dev/null | grep -E "(allow|deny)" || echo "") + local libreportal_rules=$(runSystem ufw-docker list 2>/dev/null | grep -E "(allow|deny)" || echo "") if [[ -n "$libreportal_rules" ]]; then echo "$libreportal_rules" | while read -r rule_line; do if [[ $rule_line =~ (allow|deny)\ ([^[:space:]]+)\ ([^[:space:]]+) ]]; then @@ -16,7 +16,7 @@ firewallClearLibrePortalRules() # Only clear LibrePortal app rules (not system rules) if [[ -d "$containers_dir/$container" ]]; then - local result=$(sudo ufw-docker delete "$action" "$container" "$port_spec" 2>&1) + local result=$(runSystem ufw-docker delete "$action" "$container" "$port_spec" 2>&1) if [[ $? -eq 0 ]]; then ((total_cleared++)) isSuccessful "Cleared: $action $container $port_spec" @@ -31,7 +31,7 @@ firewallClearLibrePortalRules() fi elif command -v ufw &> /dev/null; then - local libreportal_rules=$(sudo ufw status numbered 2>/dev/null | grep -E "ALLOW.*LibrePortal" || echo "") + local libreportal_rules=$(runSystem ufw status numbered 2>/dev/null | grep -E "ALLOW.*LibrePortal" || echo "") if [[ -n "$libreportal_rules" ]]; then echo "$libreportal_rules" | while read -r rule_line; do @@ -40,7 +40,7 @@ firewallClearLibrePortalRules() local action="${BASH_REMATCH[2]}" local port_spec="${BASH_REMATCH[3]}" - local result=$(sudo ufw --force delete "$rule_num" 2>&1) + local result=$(runSystem ufw --force delete "$rule_num" 2>&1) if [[ $? -eq 0 ]]; then ((total_cleared++)) isNotice "Cleared rule #$rule_num: $action $port_spec" diff --git a/scripts/ssh/host_access.sh b/scripts/ssh/host_access.sh index 1f43641..340b417 100644 --- a/scripts/ssh/host_access.sh +++ b/scripts/ssh/host_access.sh @@ -37,26 +37,26 @@ hostSshEnsureDir() u=$(hostSshUser) sshdir="$(hostSshHome)/.ssh" akf=$(hostSshAuthKeysFile) - sudo mkdir -p "$sshdir" - sudo touch "$akf" - sudo chmod 700 "$sshdir" - sudo chmod 600 "$akf" - sudo chown -R "$u":"$u" "$sshdir" + runSystem mkdir -p "$sshdir" + runSystem touch "$akf" + runSystem chmod 700 "$sshdir" + runSystem chmod 600 "$akf" + runSystem chown -R "$u":"$u" "$sshdir" } # Count valid authorized public keys. hostSshKeyCount() { local akf; akf=$(hostSshAuthKeysFile) - sudo test -f "$akf" || { echo 0; return; } - sudo grep -cvE '^[[:space:]]*($|#)' "$akf" 2>/dev/null || echo 0 + runSystem test -f "$akf" || { echo 0; return; } + runSystem grep -cvE '^[[:space:]]*($|#)' "$akf" 2>/dev/null || echo 0 } # True when sshd currently allows password authentication. hostSshPasswordAuthEnabled() { local v - v=$(sudo sshd -T 2>/dev/null | awk '/^passwordauthentication/ {print $2}') + v=$(runSystem sshd -T 2>/dev/null | awk '/^passwordauthentication/ {print $2}') [[ -z "$v" ]] && v=$(grep -iE '^[[:space:]]*PasswordAuthentication' "$sshd_config" 2>/dev/null | tail -1 | awk '{print tolower($2)}') [[ "$v" == "no" ]] && return 1 return 0 # default-on when unspecified @@ -81,14 +81,14 @@ hostSshKeyAdd() local akf body akf=$(hostSshAuthKeysFile) body=$(awk '{print $2}' <<< "$pub") - if sudo grep -qF "$body" "$akf" 2>/dev/null; then + if runSystem grep -qF "$body" "$akf" 2>/dev/null; then isNotice "That key is already authorized." else - printf '%s\n' "$pub" | sudo tee -a "$akf" >/dev/null + printf '%s\n' "$pub" | runSystem tee -a "$akf" >/dev/null isSuccessful "SSH key authorized for $(hostSshUser)" fi - sudo chown "$(hostSshUser)":"$(hostSshUser)" "$akf" - sudo chmod 600 "$akf" + runSystem chown "$(hostSshUser)":"$(hostSshUser)" "$akf" + runSystem chmod 600 "$akf" hostSshRefreshUi } @@ -99,7 +99,7 @@ hostSshKeyRemove() local fp="$1" [[ -z "$fp" ]] && { isError "hostSshKeyRemove requires "; return 1; } local akf; akf=$(hostSshAuthKeysFile) - sudo test -f "$akf" || { isError "No authorized_keys file"; return 1; } + runSystem test -f "$akf" || { isError "No authorized_keys file"; return 1; } if ! hostSshPasswordAuthEnabled && [[ "$(hostSshKeyCount)" -le 1 ]]; then isError "Refusing to remove the last key while password login is disabled — you'd be locked out. Re-enable password login first." @@ -117,12 +117,12 @@ hostSshKeyRemove() removed=1; continue fi printf '%s\n' "$line" >> "$tmp" - done < <(sudo cat "$akf") + done < <(runSystem cat "$akf") if [[ "$removed" -eq 1 ]]; then - sudo cp "$tmp" "$akf" - sudo chown "$(hostSshUser)":"$(hostSshUser)" "$akf" - sudo chmod 600 "$akf" + runSystem cp "$tmp" "$akf" + runSystem chown "$(hostSshUser)":"$(hostSshUser)" "$akf" + runSystem chmod 600 "$akf" isSuccessful "Removed SSH key $fp" else isNotice "No key matched fingerprint $fp" @@ -148,16 +148,16 @@ hostSshSetPasswordAuth() local value="yes"; [[ "$want" == "off" ]] && value="no" local backup="${sshd_config}.libreportal.$(date +%s)" - sudo cp "$sshd_config" "$backup" - sudo sed -i '/^[[:space:]]*#\?[[:space:]]*PasswordAuthentication\b/d' "$sshd_config" - echo "PasswordAuthentication $value" | sudo tee -a "$sshd_config" >/dev/null + runSystem cp "$sshd_config" "$backup" + runSystem sed -i '/^[[:space:]]*#\?[[:space:]]*PasswordAuthentication\b/d' "$sshd_config" + echo "PasswordAuthentication $value" | runSystem tee -a "$sshd_config" >/dev/null - if ! sudo sshd -t 2>/dev/null; then + if ! runSystem sshd -t 2>/dev/null; then isError "sshd config test failed — restoring backup, no change made." - sudo cp "$backup" "$sshd_config" + runSystem cp "$backup" "$sshd_config" return 1 fi - sudo systemctl reload ssh 2>/dev/null || sudo systemctl reload sshd 2>/dev/null + runSystem systemctl reload ssh 2>/dev/null || runSystem systemctl reload sshd 2>/dev/null isSuccessful "Password login ${want} (sshd reloaded; backup at $backup)" hostSshRefreshUi } diff --git a/scripts/webui/webui_install_systemd.sh b/scripts/webui/webui_install_systemd.sh index 3420881..9f812d6 100755 --- a/scripts/webui/webui_install_systemd.sh +++ b/scripts/webui/webui_install_systemd.sh @@ -33,7 +33,7 @@ Environment=XDG_RUNTIME_DIR=/run/user/${libreportal_uid}" fi # Create systemd service file - sudo tee "$service_file" > /dev/null < /dev/null </dev/null 2>&1 - sudo systemctl start libreportal.service + runSystem systemctl daemon-reload + runSystem systemctl enable libreportal.service >/dev/null 2>&1 + runSystem systemctl start libreportal.service isSuccessful "LibrePortal task processor service setup." fi