@ -7,13 +7,15 @@
package clientupdate
package clientupdate
import (
import (
"errors"
"fmt"
"os/exec"
"os/exec"
"os/user"
"os/user"
"path/filepath"
"path/filepath"
"syscall"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows"
"tailscale.com/util/winutil"
"tailscale.com/util/winutil/authenticode"
"tailscale.com/util/winutil/authenticode"
)
)
@ -39,14 +41,15 @@ func launchTailscaleAsGUIUser(exePath string) error {
var token windows . Token
var token windows . Token
if u , err := user . Current ( ) ; err == nil && u . Name == "SYSTEM" {
if u , err := user . Current ( ) ; err == nil && u . Name == "SYSTEM" {
sessionID := winutil . WTSGetActiveConsoleSessionId ( )
sessionID , err := wtsGetActiveSessionID ( )
if sessionID != 0xFFFFFFFF {
if err != nil {
return fmt . Errorf ( "wtsGetActiveSessionID(): %w" , err )
}
if err := windows . WTSQueryUserToken ( sessionID , & token ) ; err != nil {
if err := windows . WTSQueryUserToken ( sessionID , & token ) ; err != nil {
return err
return fmt. Errorf ( "WTSQu eryUse rToken (0x%x): %w", sessionID , err )
}
}
defer token . Close ( )
defer token . Close ( )
}
}
}
cmd := exec . Command ( exePath )
cmd := exec . Command ( exePath )
cmd . SysProcAttr = & syscall . SysProcAttr {
cmd . SysProcAttr = & syscall . SysProcAttr {
@ -55,3 +58,27 @@ func launchTailscaleAsGUIUser(exePath string) error {
}
}
return cmd . Start ( )
return cmd . Start ( )
}
}
func wtsGetActiveSessionID ( ) ( uint32 , error ) {
var (
sessionInfo * windows . WTS_SESSION_INFO
count uint32 = 0
)
const WTS_CURRENT_SERVER_HANDLE = 0
if err := windows . WTSEnumerateSessions ( WTS_CURRENT_SERVER_HANDLE , 0 , 1 , & sessionInfo , & count ) ; err != nil {
return 0 , fmt . Errorf ( "WTSEnumerateSessions: %w" , err )
}
defer windows . WTSFreeMemory ( uintptr ( unsafe . Pointer ( sessionInfo ) ) )
current := unsafe . Pointer ( sessionInfo )
for i := uint32 ( 0 ) ; i < count ; i ++ {
session := ( * windows . WTS_SESSION_INFO ) ( current )
if session . State == windows . WTSActive {
return session . SessionID , nil
}
current = unsafe . Add ( current , unsafe . Sizeof ( windows . WTS_SESSION_INFO { } ) )
}
return 0 , errors . New ( "no active desktop sessions found" )
}