]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
ask-password: do not reuse flags across Varlink calls
authorLuca Boccassi <luca.boccassi@gmail.com>
Thu, 11 Jun 2026 15:13:11 +0000 (16:13 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Sat, 13 Jun 2026 08:39:28 +0000 (09:39 +0100)
The flags parameter is parsed into a global variable, which means
when there are multiple consecutive calls it is reused. Switch to
a local copy.

Follow-up for 066f6bfb6278962e288cce2ba522a2e400980e7c

Assisted-by: kres (claude-opus-4-7)
Co-developed-by: Claude Opus 4.8 <noreply@anthropic.com>
src/ask-password/ask-password.c
test/units/TEST-74-AUX-UTILS.ask-password.sh

index 6a1abf5f999a1093fed90922cf476361076742c9..17d839e98dd489800253b47a49d4999e47e460e6 100644 (file)
@@ -250,6 +250,8 @@ static int vl_method_ask(sd_varlink *link, sd_json_variant *parameters, sd_varli
                 .push_cache = -1,
                 .echo_mode = _ECHO_MODE_INVALID,
         };
+        /* Local copy so that parameters passed are per-invocation */
+        AskPasswordFlags ask_flags = arg_flags;
         int r;
 
         assert(link);
@@ -285,21 +287,21 @@ static int vl_method_ask(sd_varlink *link, sd_json_variant *parameters, sd_varli
                 req.until = MIN(usec_add(now(CLOCK_MONOTONIC), p.timeout_usec), p.until_usec);
 
         /* If the timeout is set to zero, don't ask agents, just stick to cache */
-        SET_FLAG(arg_flags, ASK_PASSWORD_NO_AGENT, req.until == 0);
+        SET_FLAG(ask_flags, ASK_PASSWORD_NO_AGENT, req.until == 0);
 
         if (p.accept_cached >= 0)
-                SET_FLAG(arg_flags, ASK_PASSWORD_ACCEPT_CACHED, p.accept_cached);
+                SET_FLAG(ask_flags, ASK_PASSWORD_ACCEPT_CACHED, p.accept_cached);
 
         if (p.push_cache >= 0)
-                SET_FLAG(arg_flags, ASK_PASSWORD_PUSH_CACHE, p.push_cache);
+                SET_FLAG(ask_flags, ASK_PASSWORD_PUSH_CACHE, p.push_cache);
 
         if (p.echo_mode >= 0) {
-                SET_FLAG(arg_flags, ASK_PASSWORD_ECHO, p.echo_mode == ECHO_ON);
-                SET_FLAG(arg_flags, ASK_PASSWORD_SILENT, p.echo_mode == ECHO_OFF);
+                SET_FLAG(ask_flags, ASK_PASSWORD_ECHO, p.echo_mode == ECHO_ON);
+                SET_FLAG(ask_flags, ASK_PASSWORD_SILENT, p.echo_mode == ECHO_OFF);
         }
 
         _cleanup_strv_free_erase_ char **l = NULL;
-        r = ask_password_auto(&req, arg_flags, &l);
+        r = ask_password_auto(&req, ask_flags, &l);
         if (r == -EUNATCH)
                 return sd_varlink_error(link, "io.systemd.AskPassword.NoPasswordAvailable", NULL);
         if (r == -ETIME)
index 421ebb74b784114cddcde33cbbfb52c504892746..ef0c1aa9e7da80397bd3918f3a89a6cb31b997ac 100755 (executable)
@@ -6,9 +6,15 @@ set -o pipefail
 # shellcheck source=test/units/util.sh
 . "$(dirname "$0")"/util.sh
 
+KEY=""
+SOCKET_DIR=""
+
 at_exit() {
     set +e
     systemctl stop waldo-ask-pw-agent.service
+    systemctl stop test-askpw.service
+    [[ -n "$KEY" ]] && keyctl unlink "$KEY" @u
+    rm -rf "$SOCKET_DIR"
 }
 
 trap at_exit EXIT
@@ -22,3 +28,23 @@ varlinkctl introspect /run/systemd/io.systemd.AskPassword
 systemd-run -u waldo-ask-pw-agent.service -p Environment=SYSTEMD_ASK_PASSWORD_AGENT_PASSWORD=waldo -p Type=notify systemd-tty-ask-password-agent --watch --console=/dev/console
 assert_eq "$(systemd-ask-password --no-tty)" "waldo"
 assert_eq "$(varlinkctl call /usr/bin/systemd-ask-password io.systemd.AskPassword.Ask '{"message":"foobar"}' | jq '.passwords[0]')" "\"waldo\""
+
+# Per-request Varlink Ask flags must not leak across calls sharing one connection
+SOCKET_DIR="$(mktemp -d)"
+sock="$SOCKET_DIR/ask.sock"
+KEY="$(keyctl add user test-askpw hunter2 @u)"
+
+systemd-run --unit=test-askpw.service -p Type=notify -p KeyringMode=shared \
+    systemd-socket-activate --accept --fdname=varlink -l "$sock" -- \
+        systemd-ask-password
+
+# timeoutUSec:0 disables the agent, so the keyring cache is the only source.
+req_cached='{"method":"io.systemd.AskPassword.Ask","parameters":{"keyname":"test-askpw","timeoutUSec":0,"acceptCached":true}}'
+req_plain='{"method":"io.systemd.AskPassword.Ask","parameters":{"keyname":"test-askpw","timeoutUSec":0}}'
+printf '%s\0%s\0' "$req_cached" "$req_plain" | socat -t20 - "UNIX-CONNECT:$sock" >"$SOCKET_DIR/replies"
+mapfile -d '' -t replies <"$SOCKET_DIR/replies"
+
+assert_eq "${#replies[@]}" "2"
+assert_in "hunter2" "${replies[0]}"
+assert_not_in "hunter2" "${replies[1]}"
+assert_in "NoPasswordAvailable" "${replies[1]}"