mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-27 00:59:07 +02:00
107 lines
3.3 KiB
Go
107 lines
3.3 KiB
Go
package ipcauth
|
|
|
|
import (
|
|
"google.golang.org/grpc/codes"
|
|
gstatus "google.golang.org/grpc/status"
|
|
)
|
|
|
|
// AuthzLevel is the authority a caller holds over the daemon's current state.
|
|
// The values are ordered, and each level can do everything the levles below
|
|
// it can. A MethodPolicy is satisfied when the caller's level is at least
|
|
// the level the method requires.
|
|
type AuthzLevel uint8
|
|
|
|
const (
|
|
// AuthzLevelNone is a caller whose kernel identity could not be established.
|
|
AuthzLevelNone AuthzLevel = iota
|
|
|
|
// AuthzLevelIdentified is any caller the kernel could verify.
|
|
AuthzLevelIdentified
|
|
|
|
// AuthzLevelProfileOwner is a caller being the owner of the current targeted
|
|
// profile
|
|
AuthzLevelProfileOwner
|
|
|
|
// AuthzLevelSessionHolder is a caller that owns the current active profile
|
|
// and the session is currently connected (after running UP).
|
|
AuthzLevelSessionHolder
|
|
|
|
// AuthzLevelPrivileged is root, an elevated administrator or the daemon's
|
|
// own identity (if running as less privileges than root).
|
|
AuthzLevelPrivileged
|
|
)
|
|
|
|
// String() resolves a AuthzLevel to a human readable debug string.
|
|
func (l AuthzLevel) String() string {
|
|
switch l {
|
|
case AuthzLevelIdentified:
|
|
return "identified"
|
|
case AuthzLevelProfileOwner:
|
|
return "profile owner"
|
|
case AuthzLevelSessionHolder:
|
|
return "session holder"
|
|
case AuthzLevelPrivileged:
|
|
return "privileged"
|
|
default:
|
|
return "unidentified"
|
|
}
|
|
}
|
|
|
|
// RequireLevel builds a rule from a level, for composing inside another rule.
|
|
func RequireLevel(want AuthzLevel) Rule {
|
|
return func(r Request) error {
|
|
if r.Level >= want {
|
|
return nil
|
|
}
|
|
return denyLevel(r, want)
|
|
}
|
|
}
|
|
|
|
func denyLevel(r Request, want AuthzLevel) error {
|
|
return gstatus.Errorf(codes.PermissionDenied,
|
|
"%s requires %s, caller %s is %s", r.Method, want, r.Identity, r.Level)
|
|
}
|
|
|
|
// denyPolicyLevel refuses a caller at the gate, where the policy is in hand.
|
|
//
|
|
// A privileged method that declares no action keeps the plain message. Rules
|
|
// deny through denyLevel instead: they cannot reach the policy table without an
|
|
// initialization cycle, and no rule requires privilege.
|
|
func denyPolicyLevel(r Request, p MethodPolicy, target Target) error {
|
|
switch p.Level {
|
|
case AuthzLevelPrivileged:
|
|
if p.Action != "" {
|
|
return denyPrivileged(p, target)
|
|
}
|
|
|
|
case AuthzLevelSessionHolder:
|
|
// resolveLevel stops at profile owner only when a session is running and
|
|
// somebody else holds it.
|
|
if r.Level == AuthzLevelProfileOwner {
|
|
return SessionHeldError(p.Action)
|
|
}
|
|
return denyOwnership(p.Action, r.Identity, target)
|
|
|
|
case AuthzLevelProfileOwner:
|
|
return denyOwnership(p.Action, r.Identity, target)
|
|
}
|
|
|
|
return denyLevel(r, p.Level)
|
|
}
|
|
|
|
// denyPrivileged refuses a method that needs a privileged caller.
|
|
// Claiming a profile is currently the only privileged method
|
|
func denyPrivileged(p MethodPolicy, target Target) error {
|
|
actor, command := RequiredActor(ClaimCommand(target.Handle))
|
|
return PrivilegeError(PrivilegeSummary(p.Action, actor), command)
|
|
}
|
|
|
|
// denyOwnership refuses a caller with no standing on the profile. Only a profile
|
|
// nobody has claimed is theirs to put right, so only that one carries a command.
|
|
func denyOwnership(action string, id Identity, target Target) error {
|
|
if target.UnOwned {
|
|
return UnownedError(action, target.Handle, consoleLookup(id))
|
|
}
|
|
return NotOwnerError(action)
|
|
}
|