From 194da43c66a1271350fe821b71a27a555625ab5b Mon Sep 17 00:00:00 2001 From: damocles Date: Sat, 27 Jun 2026 17:47:58 +0200 Subject: [PATCH] fix(#1988): send agent username not root for vnc apple-dh auth --- frontend/packages/agent/src/screen.html | 26 ++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/frontend/packages/agent/src/screen.html b/frontend/packages/agent/src/screen.html index 56e58f43..393f0398 100644 --- a/frontend/packages/agent/src/screen.html +++ b/frontend/packages/agent/src/screen.html @@ -128,6 +128,21 @@ setTimeout(() => { msg.style.opacity = '0'; }, 2500); } + // --- Agent username (for Apple-DH auth) --- + // weston runs the VNC backend as the agent's own non-root unix user + // (weston-vnc.nix: `User = userName`), and neatvnc's Apple-DH path + // does getpwnam(username) + requires pw_uid == weston's uid before PAM + // is ever consulted — so the auth username MUST be that agent's name, + // not a hardcoded "root". `/api/state` exposes it as `label` (same + // path-relative `document.baseURI` trick as the WS below, so it works + // under the nginx /agent// prefix too). Kicked off here so it + // resolves concurrently with the RFB handshake; the Apple-DH step + // awaits it. + const agentLabelPromise = fetch(new URL('api/state', document.baseURI)) + .then((r) => (r.ok ? r.json() : null)) + .then((s) => (s && s.label) || null) + .catch(() => null); + // --- WebSocket connection --- // Path-relative URL — `document.baseURI` resolves against the // page's URL so the agent page mounted under a nginx prefix @@ -436,11 +451,16 @@ // weston's vnc_handle_auth (libweston/backend-vnc/vnc.c) does // getpwnam(username) and requires pw_uid == weston's own uid // BEFORE PAM is ever consulted — an empty/garbage username is - // rejected outright. weston runs as root, so the username must - // be "root". The password stays empty; pam_permit.so on the + // rejected outright. Our weston runs as the agent's own + // non-root user (weston-vnc.nix forbids root), so the username + // must be that agent's name — resolved from /api/dashboard-state + // above. The password stays empty; pam_permit.so on the // weston-remote-access PAM service accepts it. + const username = (await agentLabelPromise) || 'root'; + dbg('Apple-DH: auth username=' + username + + (username === 'root' ? ' (label unresolved — falling back)' : '')); const creds = new Uint8Array(128); - creds.set(new TextEncoder().encode('root'), 0); + creds.set(new TextEncoder().encode(username), 0); const encCreds = await aes128ecb(aesKey, creds); // Send: encrypted_creds + client_pub