handler.go 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package syspolicy
  4. import (
  5. "errors"
  6. "sync/atomic"
  7. )
  8. var (
  9. handlerUsed atomic.Bool
  10. handler Handler = defaultHandler{}
  11. )
  12. // Handler reads system policies from OS-specific storage.
  13. type Handler interface {
  14. // ReadString reads the policy setting's string value for the given key.
  15. // It should return ErrNoSuchKey if the key does not have a value set.
  16. ReadString(key string) (string, error)
  17. // ReadUInt64 reads the policy setting's uint64 value for the given key.
  18. // It should return ErrNoSuchKey if the key does not have a value set.
  19. ReadUInt64(key string) (uint64, error)
  20. // ReadBool reads the policy setting's boolean value for the given key.
  21. // It should return ErrNoSuchKey if the key does not have a value set.
  22. ReadBoolean(key string) (bool, error)
  23. // ReadStringArray reads the policy setting's string array value for the given key.
  24. // It should return ErrNoSuchKey if the key does not have a value set.
  25. ReadStringArray(key string) ([]string, error)
  26. }
  27. // ErrNoSuchKey is returned by a Handler when the specified key does not have a
  28. // value set.
  29. var ErrNoSuchKey = errors.New("no such key")
  30. // defaultHandler is the catch all syspolicy type for anything that isn't windows or apple.
  31. type defaultHandler struct{}
  32. func (defaultHandler) ReadString(_ string) (string, error) {
  33. return "", ErrNoSuchKey
  34. }
  35. func (defaultHandler) ReadUInt64(_ string) (uint64, error) {
  36. return 0, ErrNoSuchKey
  37. }
  38. func (defaultHandler) ReadBoolean(_ string) (bool, error) {
  39. return false, ErrNoSuchKey
  40. }
  41. func (defaultHandler) ReadStringArray(_ string) ([]string, error) {
  42. return nil, ErrNoSuchKey
  43. }
  44. // markHandlerInUse is called before handler methods are called.
  45. func markHandlerInUse() {
  46. handlerUsed.Store(true)
  47. }
  48. // RegisterHandler initializes the policy handler and ensures registration will happen once.
  49. func RegisterHandler(h Handler) {
  50. // Technically this assignment is not concurrency safe, but in the
  51. // event that there was any risk of a data race, we will panic due to
  52. // the CompareAndSwap failing.
  53. handler = h
  54. if !handlerUsed.CompareAndSwap(false, true) {
  55. panic("handler was already used before registration")
  56. }
  57. }
  58. // TB is a subset of testing.TB that we use to set up test helpers.
  59. // It's defined here to avoid pulling in the testing package.
  60. type TB interface {
  61. Helper()
  62. Cleanup(func())
  63. }
  64. func SetHandlerForTest(tb TB, h Handler) {
  65. tb.Helper()
  66. oldHandler := handler
  67. handler = h
  68. tb.Cleanup(func() { handler = oldHandler })
  69. }