fix(config): updateConfigOption uses the right de-sudo helper for the file's tree

Symptom (reported on adguard install):
  sed: couldn't open temporary file /libreportal-containers/adguard/sedZaGX2H:
       Permission denied
  ✗ Error Updated CFG_ADGUARD_BACKUP to true
  ! Notice Non-interactive mode: aborting on error.

Root cause: updateConfigOption ran a raw `sed -i` regardless of which tree
the config file sits in. Works fine for /libreportal-system/configs/*
(manager-owned) but breaks on /libreportal-containers/<app>/<app>.config
(dockerinstall-owned in rootless mode) — sed -i writes its temp file next
to the target, inheriting the directory's perms, and the manager can't
write inside dockerinstall dirs. EVERY app installer that mutates a
CFG_<APP>_* value (the autogenerated random password, BACKUP toggle,
PORT override, etc.) goes through this function, so this was a latent
ticking bomb across all containers.

Fix: pick the helper based on path —
  -  under $containers_dir  → runFileOp  (escalates to
    dockerinstall in rootless, runs as manager in rooted)
  - otherwise                            → runInstallOp (always manager)
Read paths (grep / source) stay unwrapped — both dirs are world-readable;
only the write needs the privilege swap.

Net: no more 'Permission denied' on app installs; the de-sudo pattern is
now respected end-to-end for CFG writes.

Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
librelad 2026-05-27 01:16:02 +01:00
parent 3d7f5fbdeb
commit 56d2f8105c

View File

@ -28,7 +28,22 @@ updateConfigOption()
local escaped_value
escaped_value=$(printf '%s' "$config_value" | sed -e 's/[\\&"]/\\&/g')
# Check if config option exists in the file
# Pick the right de-sudo helper based on which tree the config lives in.
# Manager (libreportal) owns /libreportal-system/configs/* and runs the
# CLI; dockerinstall owns /libreportal-containers/<app>/* in rootless mode.
# Without this, `sed -i` on a containers-owned <app>.config fails with
# sed: couldn't open temporary file /libreportal-containers/<app>/sedXXXX: Permission denied
# (sed -i writes its temp next to the target, so it inherits the dir's
# write perms — and the manager can't write inside dockerinstall dirs).
# runFileOp routes the write through the right user.
local _write_op="runInstallOp"
if [[ -n "${containers_dir:-}" && "$config_file" == "${containers_dir%/}/"* ]]; then
_write_op="runFileOp"
fi
# Check if config option exists in the file. grep + read can use the
# current user — both dirs are world-readable; only the write needs
# escalation.
if grep -q "^$config_option=" "$config_file"; then
# Extract the comment part first (everything after the first #)
local original_line=$(grep "^$config_option=" "$config_file")
@ -36,9 +51,9 @@ updateConfigOption()
# Replace the value, preserving comment if it existed. Always quoted.
if [[ -n "$comment_part" ]]; then
sed -i "s${DELIM}^${config_option}=.*${DELIM}${config_option}=\"${escaped_value}\" ${comment_part}${DELIM}" "$config_file"
$_write_op sed -i "s${DELIM}^${config_option}=.*${DELIM}${config_option}=\"${escaped_value}\" ${comment_part}${DELIM}" "$config_file"
else
sed -i "s${DELIM}^${config_option}=.*${DELIM}${config_option}=\"${escaped_value}\"${DELIM}" "$config_file"
$_write_op sed -i "s${DELIM}^${config_option}=.*${DELIM}${config_option}=\"${escaped_value}\"${DELIM}" "$config_file"
fi
checkSuccess "Updated $config_option to $config_value"
source "$config_file"