clientupdate: manually restart Windows GUI after update (#9906)

When updating via c2n, `tailscale.exe update` runs from `tailscaled.exe`
which runs as SYSTEM. The MSI installer does not start the GUI when
running as SYSTEM. This results in Tailscale just existing on
auto-update, which is ungood.

Instead, always ask the MSI installer to not launch the GUI (via
`TS_NOLAUNCH` argument) and launch it manually with a token from the
current logged in user. The token code was borrowed from
d9081d6ba2/net/dns/wsl_windows.go (L207-L232)

Also, make some logging changes so that these issues are easier to debug
in the future.

Updates #755

Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
This commit is contained in:
Andrew Lytvynov
2023-10-23 10:24:57 -07:00
committed by GitHub
parent e9956419f6
commit e561f1ce61
2 changed files with 101 additions and 17 deletions

View File

@ -7,13 +7,20 @@
package clientupdate
import (
"os/exec"
"os/user"
"path/filepath"
"syscall"
"golang.org/x/sys/windows"
"tailscale.com/util/winutil"
"tailscale.com/util/winutil/authenticode"
)
func init() {
markTempFileFunc = markTempFileWindows
verifyAuthenticode = verifyTailscale
launchTailscaleAsWinGUIUser = launchTailscaleAsGUIUser
}
func markTempFileWindows(name string) error {
@ -26,3 +33,25 @@ const certSubjectTailscale = "Tailscale Inc."
func verifyTailscale(path string) error {
return authenticode.Verify(path, certSubjectTailscale)
}
func launchTailscaleAsGUIUser(exePath string) error {
exePath = filepath.Join(filepath.Dir(exePath), "tailscale-ipn.exe")
var token windows.Token
if u, err := user.Current(); err == nil && u.Name == "SYSTEM" {
sessionID := winutil.WTSGetActiveConsoleSessionId()
if sessionID != 0xFFFFFFFF {
if err := windows.WTSQueryUserToken(sessionID, &token); err != nil {
return err
}
defer token.Close()
}
}
cmd := exec.Command(exePath)
cmd.SysProcAttr = &syscall.SysProcAttr{
Token: syscall.Token(token),
HideWindow: true,
}
return cmd.Start()
}