From 3a74f2d2d74bf9bd989252612c82df9eed2b8a5a Mon Sep 17 00:00:00 2001 From: Aaron Klotz Date: Mon, 10 Jan 2022 13:10:02 -0700 Subject: [PATCH] cmd/tailscaled, util/winutil: add accessor functions for Windows system policies. This patch adds new functions to be used when accessing system policies, and revises callers to use the new functions. They first attempt the new registry path for policies, and if that fails, attempt to fall back to the legacy path. We keep non-policy variants of these functions because we should be able to retain the ability to read settings from locations that are not exposed to sysadmins for group policy edits. The remaining changes will be done in corp. Updates https://github.com/tailscale/tailscale/issues/3584 Signed-off-by: Aaron Klotz --- cmd/tailscaled/tailscaled_windows.go | 2 +- util/winutil/winutil.go | 28 ++++++++++++- util/winutil/winutil_notwindows.go | 4 ++ util/winutil/winutil_windows.go | 61 ++++++++++++++++++++++------ 4 files changed, 80 insertions(+), 15 deletions(-) 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 (