fix(#1988): send agent username not root for vnc apple-dh auth

This commit is contained in:
damocles 2026-06-27 17:47:58 +02:00 committed by mara
commit 194da43c66

View file

@ -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/<name>/ 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