mirror of
https://github.com/Control-D-Inc/ctrld.git
synced 2026-10-24 14:08:27 +02:00
fix(windows): load WTSGetActiveConsoleSessionId from kernel32
getActiveConsoleUser looked up WTSGetActiveConsoleSessionId in wtsapi32.dll. Windows exports it from kernel32.dll, so Find failed on every host and console-session discovery always returned no user. Before #602 the registry fallbacks hid this. Daemon start now uses session-only discovery, so on Windows every managed start omitted username even with a user signed in at the console. Use windows.WTSGetActiveConsoleSessionId from golang.org/x/sys, which binds the kernel32 export. Add a Windows test that compares discoverSessionUser with the active console row of quser.
This commit is contained in:
1 parent
75165f3df0
commit
d267bb4e36
2 files changed
+55
-11
No files matched your search
@@ -14,10 +14,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
wtsapi32 = windows.NewLazySystemDLL("wtsapi32.dll")
|
||||
procWTSGetActiveConsoleSessionId = wtsapi32.NewProc("WTSGetActiveConsoleSessionId")
|
||||
procWTSQuerySessionInformation = wtsapi32.NewProc("WTSQuerySessionInformationW")
|
||||
procWTSFreeMemory = wtsapi32.NewProc("WTSFreeMemory")
|
||||
wtsapi32 = windows.NewLazySystemDLL("wtsapi32.dll")
|
||||
procWTSQuerySessionInformation = wtsapi32.NewProc("WTSQuerySessionInformationW")
|
||||
procWTSFreeMemory = wtsapi32.NewProc("WTSFreeMemory")
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -75,12 +74,8 @@ func discoverSessionUser(ctx context.Context) string {
|
||||
|
||||
// getActiveConsoleUser gets the username of the active console session
|
||||
func getActiveConsoleUser(ctx context.Context) string {
|
||||
// Guard against missing WTS procedures (e.g., Windows Server Core).
|
||||
if err := procWTSGetActiveConsoleSessionId.Find(); err != nil {
|
||||
LoggerFromCtx(ctx).Debug().Err(err).Msg("WTSGetActiveConsoleSessionId not available, skipping console session check")
|
||||
return ""
|
||||
}
|
||||
sessionId, _, _ := procWTSGetActiveConsoleSessionId.Call()
|
||||
// WTSGetActiveConsoleSessionId is exported by kernel32.dll, not wtsapi32.dll.
|
||||
sessionId := windows.WTSGetActiveConsoleSessionId()
|
||||
if sessionId == 0xFFFFFFFF { // Invalid session
|
||||
LoggerFromCtx(ctx).Debug().Msg("no active console session found")
|
||||
return ""
|
||||
@@ -95,7 +90,7 @@ func getActiveConsoleUser(ctx context.Context) string {
|
||||
}
|
||||
ret, _, _ := procWTSQuerySessionInformation.Call(
|
||||
0, // WTS_CURRENT_SERVER_HANDLE
|
||||
sessionId,
|
||||
uintptr(sessionId),
|
||||
uintptr(WTSUserName),
|
||||
uintptr(unsafe.Pointer(&buffer)),
|
||||
uintptr(unsafe.Pointer(&bytesReturned)),
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//go:build windows
|
||||
|
||||
package ctrld
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Every procedure that console-session discovery loads at runtime must exist in
|
||||
// the DLL it is loaded from. A wrong DLL makes Find fail on every host, so
|
||||
// discovery silently reports no user instead of the signed-in one.
|
||||
func TestConsoleSessionProceduresResolve(t *testing.T) {
|
||||
for _, p := range []interface {
|
||||
Find() error
|
||||
}{procWTSQuerySessionInformation, procWTSFreeMemory} {
|
||||
if err := p.Find(); err != nil {
|
||||
t.Fatalf("console session procedure does not resolve: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// discoverSessionUser must agree with Windows' own view of the console session:
|
||||
// the user shown on the active "console" row of `query user`, or no user when
|
||||
// that row is absent.
|
||||
func TestDiscoverSessionUserMatchesConsoleSession(t *testing.T) {
|
||||
quser, err := exec.LookPath("quser.exe")
|
||||
if err != nil {
|
||||
t.Skip("quser.exe not available")
|
||||
}
|
||||
// quser exits 1 when no session exists; its output still answers the question.
|
||||
out, _ := exec.Command(quser).CombinedOutput()
|
||||
want := ""
|
||||
sc := bufio.NewScanner(bytes.NewReader(out))
|
||||
for sc.Scan() {
|
||||
f := strings.Fields(strings.TrimPrefix(sc.Text(), ">"))
|
||||
if len(f) >= 4 && strings.EqualFold(f[1], "console") && strings.EqualFold(f[3], "Active") {
|
||||
want = f[0]
|
||||
}
|
||||
}
|
||||
got := discoverSessionUser(context.Background())
|
||||
if !strings.EqualFold(got, want) {
|
||||
t.Fatalf("discoverSessionUser() = %q, want %q (quser output: %q)", got, want, out)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user