93 lines
3.3 KiB
Go
93 lines
3.3 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package syspolicy
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os/user"
|
|
|
|
"tailscale.com/util/syspolicy/internal"
|
|
"tailscale.com/util/syspolicy/rsop"
|
|
"tailscale.com/util/syspolicy/setting"
|
|
"tailscale.com/util/syspolicy/source"
|
|
"tailscale.com/util/testenv"
|
|
)
|
|
|
|
func init() {
|
|
// On Windows, we should automatically register the Registry-based policy
|
|
// store for the device. If we are running in a user's security context
|
|
// (e.g., we're the GUI), we should also register the Registry policy store for
|
|
// the user. In the future, we should register (and unregister) user policy
|
|
// stores whenever a user connects to (or disconnects from) the local backend.
|
|
// This ensures the backend is aware of the user's policy settings and can send
|
|
// them to the GUI/CLI/Web clients on demand or whenever they change.
|
|
//
|
|
// Other platforms, such as macOS, iOS and Android, should register their
|
|
// platform-specific policy stores via [RegisterStore]
|
|
// (or [RegisterHandler] until they implement the [source.Store] interface).
|
|
//
|
|
// External code, such as the ipnlocal package, may choose to register
|
|
// additional policy stores, such as config files and policies received from
|
|
// the control plane.
|
|
internal.Init.MustDefer(func() error {
|
|
// Do not register or use default policy stores during tests.
|
|
// Each test should set up its own necessary configurations.
|
|
if testenv.InTest() {
|
|
return nil
|
|
}
|
|
return configureSyspolicy(nil)
|
|
})
|
|
}
|
|
|
|
// configureSyspolicy configures syspolicy for use on Windows,
|
|
// either in test or regular builds depending on whether tb has a non-nil value.
|
|
func configureSyspolicy(tb internal.TB) error {
|
|
const localSystemSID = "S-1-5-18"
|
|
// Always create and register a machine policy store that reads
|
|
// policy settings from the HKEY_LOCAL_MACHINE registry hive.
|
|
machineStore, err := source.NewMachinePlatformPolicyStore()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create the machine policy store: %v", err)
|
|
}
|
|
if tb == nil {
|
|
_, err = rsop.RegisterStore("Platform", setting.DeviceScope, machineStore)
|
|
} else {
|
|
_, err = rsop.RegisterStoreForTest(tb, "Platform", setting.DeviceScope, machineStore)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Check whether the current process is running as Local System or not.
|
|
u, err := user.Current()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if u.Uid == localSystemSID {
|
|
return nil
|
|
}
|
|
// If it's not a Local System's process (e.g., it's the GUI rather than the tailscaled service),
|
|
// we should create and use a policy store for the current user that reads
|
|
// policy settings from that user's registry hive (HKEY_CURRENT_USER).
|
|
userStore, err := source.NewUserPlatformPolicyStore(0)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create the current user's policy store: %v", err)
|
|
}
|
|
if tb == nil {
|
|
_, err = rsop.RegisterStore("Platform", setting.CurrentUserScope, userStore)
|
|
} else {
|
|
_, err = rsop.RegisterStoreForTest(tb, "Platform", setting.CurrentUserScope, userStore)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// And also set [setting.CurrentUserScope] as the [setting.DefaultScope], so [GetString],
|
|
// [GetVisibility] and similar functions would be returning a merged result
|
|
// of the machine's and user's policies.
|
|
if !setting.SetDefaultScope(setting.CurrentUserScope) {
|
|
return errors.New("current scope already set")
|
|
}
|
|
return nil
|
|
}
|