diff --git a/cmd/tailscaled/tailscaled_windows.go b/cmd/tailscaled/tailscaled_windows.go index b886343c3..9a59725b1 100644 --- a/cmd/tailscaled/tailscaled_windows.go +++ b/cmd/tailscaled/tailscaled_windows.go @@ -74,7 +74,7 @@ func (service *ipnService) Execute(args []string, r <-chan svc.ChangeRequest, ch changes <- svc.Status{State: svc.StartPending} svcAccepts := svc.AcceptStop - if winutil.GetRegInteger("FlushDNSOnSessionUnlock", 0) != 0 { + if winutil.GetPolicyInteger("FlushDNSOnSessionUnlock", 0) != 0 { svcAccepts |= svc.AcceptSessionChange } diff --git a/util/winutil/winutil.go b/util/winutil/winutil.go index ebf053173..0103598aa 100644 --- a/util/winutil/winutil.go +++ b/util/winutil/winutil.go @@ -9,7 +9,31 @@ package winutil // are stored. This constant is a non-empty string only when GOOS=windows. const RegBase = regBase -// GetRegString looks up a registry path in our local machine path, or returns +// GetPolicyString looks up a registry value in the local machine's path for +// system policies, or returns the given default if it can't. +// Use this function to read values that may be set by sysadmins via the MSI +// installer or via GPO. For registry settings that you do *not* want to be +// visible to sysadmin tools, use GetRegString instead. +// +// This function will only work on GOOS=windows. Trying to run it on any other +// OS will always return the default value. +func GetPolicyString(name, defval string) string { + return getPolicyString(name, defval) +} + +// GetPolicyInteger looks up a registry value in the local machine's path for +// system policies, or returns the given default if it can't. +// Use this function to read values that may be set by sysadmins via the MSI +// installer or via GPO. For registry settings that you do *not* want to be +// visible to sysadmin tools, use GetRegInteger instead. +// +// This function will only work on GOOS=windows. Trying to run it on any other +// OS will always return the default value. +func GetPolicyInteger(name string, defval uint64) uint64 { + return getPolicyInteger(name, defval) +} + +// GetRegString looks up a registry path in the local machine path, or returns // the given default if it can't. // // This function will only work on GOOS=windows. Trying to run it on any other @@ -18,7 +42,7 @@ func GetRegString(name, defval string) string { return getRegString(name, defval) } -// GetRegInteger looks up a registry path in our local machine path, or returns +// GetRegInteger looks up a registry path in the local machine path, or returns // the given default if it can't. // // This function will only work on GOOS=windows. Trying to run it on any other diff --git a/util/winutil/winutil_notwindows.go b/util/winutil/winutil_notwindows.go index 8fb6da3e6..64bdfec47 100644 --- a/util/winutil/winutil_notwindows.go +++ b/util/winutil/winutil_notwindows.go @@ -9,6 +9,10 @@ package winutil const regBase = `` +func getPolicyString(name, defval string) string { return defval } + +func getPolicyInteger(name string, defval uint64) uint64 { return defval } + func getRegString(name, defval string) string { return defval } func getRegInteger(name string, defval uint64) uint64 { return defval } diff --git a/util/winutil/winutil_windows.go b/util/winutil/winutil_windows.go index 447d0e926..cc0d065b1 100644 --- a/util/winutil/winutil_windows.go +++ b/util/winutil/winutil_windows.go @@ -12,7 +12,10 @@ import ( "golang.org/x/sys/windows/registry" ) -const regBase = `SOFTWARE\Tailscale IPN` +const ( + regBase = `SOFTWARE\Tailscale IPN` + regPolicyBase = `SOFTWARE\Policies\Tailscale` +) // GetDesktopPID searches the PID of the process that's running the // currently active desktop and whether it was found. @@ -26,12 +29,46 @@ func GetDesktopPID() (pid uint32, ok bool) { return pid, pid != 0 } -func getRegString(name, defval string) string { - key, err := registry.OpenKey(registry.LOCAL_MACHINE, RegBase, registry.READ) +func getPolicyString(name, defval string) string { + s, err := getRegStringInternal(regPolicyBase, name) + if err != nil { + // Fall back to the legacy path + return getRegString(name, defval) + } + return s +} + +func getPolicyInteger(name string, defval uint64) uint64 { + i, err := getRegIntegerInternal(regPolicyBase, name) + if err != nil { + // Fall back to the legacy path + return getRegInteger(name, defval) + } + return i +} + +func getRegString(name, defval string) string { + s, err := getRegStringInternal(regBase, name) if err != nil { - log.Printf("registry.OpenKey(%v): %v", RegBase, err) return defval } + return s +} + +func getRegInteger(name string, defval uint64) uint64 { + i, err := getRegIntegerInternal(regBase, name) + if err != nil { + return defval + } + return i +} + +func getRegStringInternal(subKey, name string) (string, error) { + key, err := registry.OpenKey(registry.LOCAL_MACHINE, subKey, registry.READ) + if err != nil { + log.Printf("registry.OpenKey(%v): %v", subKey, err) + return "", err + } defer key.Close() val, _, err := key.GetStringValue(name) @@ -39,16 +76,16 @@ func getRegString(name, defval string) string { if err != registry.ErrNotExist { log.Printf("registry.GetStringValue(%v): %v", name, err) } - return defval + return "", err } - return val + return val, nil } -func getRegInteger(name string, defval uint64) uint64 { - key, err := registry.OpenKey(registry.LOCAL_MACHINE, RegBase, registry.READ) +func getRegIntegerInternal(subKey, name string) (uint64, error) { + key, err := registry.OpenKey(registry.LOCAL_MACHINE, subKey, registry.READ) if err != nil { - log.Printf("registry.OpenKey(%v): %v", RegBase, err) - return defval + log.Printf("registry.OpenKey(%v): %v", subKey, err) + return 0, err } defer key.Close() @@ -57,9 +94,9 @@ func getRegInteger(name string, defval uint64) uint64 { if err != registry.ErrNotExist { log.Printf("registry.GetIntegerValue(%v): %v", name, err) } - return defval + return 0, err } - return val + return val, nil } var (