actor.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package ipnauth
  4. import (
  5. "context"
  6. "encoding/json"
  7. "fmt"
  8. "tailscale.com/client/tailscale/apitype"
  9. "tailscale.com/ipn"
  10. "tailscale.com/tailcfg"
  11. )
  12. // AuditLogFunc is any function that can be used to log audit actions performed by an [Actor].
  13. type AuditLogFunc func(action tailcfg.ClientAuditAction, details string) error
  14. // Actor is any actor using the [ipnlocal.LocalBackend].
  15. //
  16. // It typically represents a specific OS user, indicating that an operation
  17. // is performed on behalf of this user, should be evaluated against their
  18. // access rights, and performed in their security context when applicable.
  19. type Actor interface {
  20. // UserID returns an OS-specific UID of the user represented by the receiver,
  21. // or "" if the actor does not represent a specific user on a multi-user system.
  22. // As of 2024-08-27, it is only used on Windows.
  23. UserID() ipn.WindowsUserID
  24. // Username returns the user name associated with the receiver,
  25. // or "" if the actor does not represent a specific user.
  26. Username() (string, error)
  27. // ClientID returns a non-zero ClientID and true if the actor represents
  28. // a connected LocalAPI client. Otherwise, it returns a zero value and false.
  29. ClientID() (_ ClientID, ok bool)
  30. // Context returns the context associated with the actor.
  31. // It carries additional information about the actor
  32. // and is canceled when the actor is done.
  33. Context() context.Context
  34. // CheckProfileAccess checks whether the actor has the necessary access rights
  35. // to perform a given action on the specified Tailscale profile.
  36. // It returns an error if access is denied.
  37. //
  38. // If the auditLogger is non-nil, it is used to write details about the action
  39. // to the audit log when required by the policy.
  40. CheckProfileAccess(profile ipn.LoginProfileView, requestedAccess ProfileAccess, auditLogFn AuditLogFunc) error
  41. // IsLocalSystem reports whether the actor is the Windows' Local System account.
  42. //
  43. // Deprecated: this method exists for compatibility with the current (as of 2024-08-27)
  44. // permission model and will be removed as we progress on tailscale/corp#18342.
  45. IsLocalSystem() bool
  46. // IsLocalAdmin reports whether the actor has administrative access to the
  47. // local machine, for whatever that means with respect to the current OS.
  48. //
  49. // The operatorUID is only used on Unix-like platforms and specifies the ID
  50. // of a local user (in the os/user.User.Uid string form) who is allowed to
  51. // operate tailscaled without being root or using sudo.
  52. //
  53. // Deprecated: this method exists for compatibility with the current (as of 2024-08-27)
  54. // permission model and will be removed as we progress on tailscale/corp#18342.
  55. IsLocalAdmin(operatorUID string) bool
  56. }
  57. // ActorCloser is an optional interface that might be implemented by an [Actor]
  58. // that must be closed when done to release the resources.
  59. type ActorCloser interface {
  60. // Close releases resources associated with the receiver.
  61. Close() error
  62. }
  63. // ClientID is an opaque, comparable value used to identify a connected LocalAPI
  64. // client, such as a connected Tailscale GUI or CLI. It does not necessarily
  65. // correspond to the same [net.Conn] or any physical session.
  66. //
  67. // Its zero value is valid, but does not represent a specific connected client.
  68. type ClientID struct {
  69. v any
  70. }
  71. // NoClientID is the zero value of [ClientID].
  72. var NoClientID ClientID
  73. // ClientIDFrom returns a new [ClientID] derived from the specified value.
  74. // ClientIDs derived from equal values are equal.
  75. func ClientIDFrom[T comparable](v T) ClientID {
  76. return ClientID{v}
  77. }
  78. // String implements [fmt.Stringer].
  79. func (id ClientID) String() string {
  80. if id.v == nil {
  81. return "(none)"
  82. }
  83. return fmt.Sprint(id.v)
  84. }
  85. // MarshalJSON implements [json.Marshaler].
  86. // It is primarily used for testing.
  87. func (id ClientID) MarshalJSON() ([]byte, error) {
  88. return json.Marshal(id.v)
  89. }
  90. // UnmarshalJSON implements [json.Unmarshaler].
  91. // It is primarily used for testing.
  92. func (id *ClientID) UnmarshalJSON(b []byte) error {
  93. return json.Unmarshal(b, &id.v)
  94. }
  95. type actorWithRequestReason struct {
  96. Actor
  97. ctx context.Context
  98. }
  99. // WithRequestReason returns an [Actor] that wraps the given actor and
  100. // carries the specified request reason in its context.
  101. func WithRequestReason(actor Actor, requestReason string) Actor {
  102. ctx := apitype.RequestReasonKey.WithValue(actor.Context(), requestReason)
  103. return &actorWithRequestReason{Actor: actor, ctx: ctx}
  104. }
  105. // Context implements [Actor].
  106. func (a *actorWithRequestReason) Context() context.Context { return a.ctx }
  107. type withoutCloseActor struct{ Actor }
  108. // WithoutClose returns an [Actor] that does not expose the [ActorCloser] interface.
  109. // In other words, _, ok := WithoutClose(actor).(ActorCloser) will always be false,
  110. // even if the original actor implements [ActorCloser].
  111. func WithoutClose(actor Actor) Actor {
  112. return withoutCloseActor{actor}
  113. }