Decline VNC approval early when no console user is logged in

This commit is contained in:
Viktor Liu
2026-05-23 19:15:01 +02:00
parent 1f912be673
commit 7cb6388349
4 changed files with 44 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
package server
import "errors"
// consoleHasInteractiveUser returns true when a user is logged into the
// console (i.e. an Aqua session is active). At the loginwindow there is
// nobody to display an approval prompt to, so callers can decline
// without waiting on the broker.
func consoleHasInteractiveUser() bool {
if _, err := consoleUserID(); err != nil {
if errors.Is(err, errNoConsoleUser) {
return false
}
// Unknown error: fail closed so a probe-time glitch does not
// silently let an unattended console accept VNC sessions.
return false
}
return true
}

View File

@@ -0,0 +1,7 @@
//go:build !darwin && !windows
package server
// consoleHasInteractiveUser is unused outside service mode (darwin/windows)
// but the symbol must exist so gateApproval compiles on all platforms.
func consoleHasInteractiveUser() bool { return true }

View File

@@ -0,0 +1,13 @@
package server
// consoleHasInteractiveUser returns true when there is a logged-in user
// session on the box. At the lock/login screen WTSQueryUserName is empty,
// which means there is nobody to display an approval prompt to. Callers
// should decline without waiting on the broker in that case.
func consoleHasInteractiveUser() bool {
sid := getActiveSessionID()
if sid == 0 {
return false
}
return wtsSessionHasUser(sid)
}

View File

@@ -431,6 +431,11 @@ func (s *Server) gateApproval(conn net.Conn, header *connectionHeader, connLog *
connLog.Warn("VNC connection rejected: approval required but no approver")
return false, ApprovalDecision{}
}
if s.serviceMode && !consoleHasInteractiveUser() {
rejectConnection(conn, codeMessage(RejectCodeNoConsoleUser, "no interactive user session"))
connLog.Info("VNC connection rejected: no interactive user session to approve")
return false, ApprovalDecision{}
}
info := ApprovalInfo{
SourceIP: sourceIPString(conn.RemoteAddr()),
Mode: modeString(header.mode),