//go:build windows package control import ( "context" "fmt" "log/slog" "os" "unsafe" "golang.org/x/sys/windows" ) // pipePath is a kernel-local named pipe: no TCP, no firewall prompt. const pipePath = `\\.\pipe\gpu-turnstile` // sddlPipe grants full access to Administrators, SYSTEM and the pipe owner, // and read+write to authenticated users — except network logons, so the // pipe cannot be reached from another machine over SMB. const sddlPipe = "D:(D;;GRGW;;;NU)(A;;GA;;;BA)(A;;GA;;;SY)(A;;GA;;;OW)(A;;GRGW;;;AU)" var ( procConvertSDDL = windows.NewLazySystemDLL("advapi32.dll"). NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW") procWaitNamedPipe = windows.NewLazySystemDLL("kernel32.dll"). NewProc("WaitNamedPipeW") ) func waitNamedPipe(name *uint16, timeout uint32) error { r, _, err := procWaitNamedPipe.Call(uintptr(unsafe.Pointer(name)), uintptr(timeout)) if r == 0 { return err } return nil } func securityAttributesFromSDDL(sddl string) (*windows.SecurityAttributes, error) { s, err := windows.UTF16PtrFromString(sddl) if err != nil { return nil, err } var sd *uint16 // SECURITY_DESCRIPTOR*, kept for the process lifetime r, _, callErr := procConvertSDDL.Call( uintptr(unsafe.Pointer(s)), 1, /* SDDL_REVISION_1 */ uintptr(unsafe.Pointer(&sd)), 0) if r == 0 { return nil, fmt.Errorf("invalid SDDL: %w", callErr) } sa := &windows.SecurityAttributes{ Length: uint32(unsafe.Sizeof(windows.SecurityAttributes{})), SecurityDescriptor: (*windows.SECURITY_DESCRIPTOR)(unsafe.Pointer(sd)), } return sa, nil } // Serve starts the pipe listener in the background and returns; only a // setup failure is reported. Each client connection is answered in its own // goroutine. On shutdown the process exit reaps everything. func Serve(ctx context.Context, h Handler, log *slog.Logger) error { sa, err := securityAttributesFromSDDL(sddlPipe) if err != nil { return err } name, err := windows.UTF16PtrFromString(pipePath) if err != nil { return err } go func() { for ctx.Err() == nil { pipe, err := windows.CreateNamedPipe(name, windows.PIPE_ACCESS_DUPLEX, windows.PIPE_TYPE_BYTE|windows.PIPE_READMODE_BYTE|windows.PIPE_WAIT, 16, 4096, 4096, 0, sa) if err != nil { log.Warn("control channel stopped", "err", err) return } go func() { // Blocks until a client connects; on process exit the // handle goes away with everything else. if err := windows.ConnectNamedPipe(pipe, nil); err != nil { windows.CloseHandle(pipe) return } f := os.NewFile(uintptr(pipe), pipePath) serveConn(f, h) // closes f, and with it the pipe handle }() } }() return nil } // Ask sends one command to the running service and returns its reply. func Ask(cmd string) (string, error) { name, err := windows.UTF16PtrFromString(pipePath) if err != nil { return "", err } if err := waitNamedPipe(name, 2000); err != nil { return "", ErrUnavailable } handle, err := windows.CreateFile(name, windows.GENERIC_READ|windows.GENERIC_WRITE, 0, nil, windows.OPEN_EXISTING, 0, 0) if err != nil { return "", ErrUnavailable } f := os.NewFile(uintptr(handle), pipePath) defer f.Close() return readReply(f, cmd) }