forked from Velocidex/velociraptor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathacls.go
135 lines (110 loc) · 3.57 KB
/
acls.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package vql
import (
"fmt"
"github.com/sirupsen/logrus"
"www.velocidex.com/golang/velociraptor/acls"
acl_proto "www.velocidex.com/golang/velociraptor/acls/proto"
config_proto "www.velocidex.com/golang/velociraptor/config/proto"
"www.velocidex.com/golang/velociraptor/logging"
"www.velocidex.com/golang/vfilter"
)
const (
ACL_MANAGER_VAR = "$acl"
)
type ACLManager interface {
CheckAccess(permission ...acls.ACL_PERMISSION) (bool, error)
}
// NullACLManager is an acl manager which allows everything. This is
// currently used on the client and on the command line where there is
// no clear principal or ACL controls.
type NullACLManager struct{}
func (self NullACLManager) CheckAccess(
permission ...acls.ACL_PERMISSION) (bool, error) {
return true, nil
}
// ServerACLManager is used when running server side VQL to control
// ACLs on various VQL plugins.
type ServerACLManager struct {
principal string
Token *acl_proto.ApiClientACL
}
// Token must have *ALL* the specified permissions.
func (self *ServerACLManager) CheckAccess(
permissions ...acls.ACL_PERMISSION) (bool, error) {
for _, permission := range permissions {
ok, err := acls.CheckAccessWithToken(self.Token, permission)
if !ok || err != nil {
return ok, err
}
}
return true, nil
}
// NewRoleACLManager creates an ACL manager with only the assigned
// roles. This is useful for creating limited VQL permissions
// internally.
func NewRoleACLManager(role string) ACLManager {
policy := &acl_proto.ApiClientACL{}
// If we fail just return an empty policy
_ = acls.GetRolePermissions(nil, []string{role}, policy)
return &ServerACLManager{Token: policy}
}
func NewServerACLManager(
config_obj *config_proto.Config,
principal string) ACLManager {
policy, err := acls.GetEffectivePolicy(config_obj, principal)
if err != nil {
logger := logging.GetLogger(config_obj, &logging.FrontendComponent)
logger.WithFields(logrus.Fields{
"user": principal,
"error": err,
}).Error("Unable to get policy")
policy = &acl_proto.ApiClientACL{}
}
return &ServerACLManager{principal: principal, Token: policy}
}
// Check access through the ACL manager in the scope. NOTE: This
// assumes it is not possible for a user to mask the ACL manager in
// the scope! There is currently no way to create an acl manager type
// from within VQL so this is a safe assumption - if a user was to
// override the ACL_MANAGER_VAR with something else this will lock
// down the entire VQL ACL system and deny all permissions.
func CheckAccess(scope vfilter.Scope, permissions ...acls.ACL_PERMISSION) error {
manager_any, pres := scope.Resolve(ACL_MANAGER_VAR)
if !pres {
return fmt.Errorf("Permission denied: %v", permissions)
}
manager, ok := manager_any.(ACLManager)
if !ok {
return fmt.Errorf("Permission denied: %v", permissions)
}
perm, err := manager.CheckAccess(permissions...)
if !perm || err != nil {
return fmt.Errorf("Permission denied: %v", permissions)
}
return nil
}
func CheckFilesystemAccess(scope vfilter.Scope, accessor string) error {
switch accessor {
// These accessor are OK to use at any time.
case "data":
return nil
// Direct filestore access only allowed for server
// admins.
case "filestore", "fs":
return CheckAccess(scope, acls.SERVER_ADMIN)
default:
return CheckAccess(scope, acls.FILESYSTEM_READ)
}
}
// Get the principal that is running the query if possible.
func GetPrincipal(scope vfilter.Scope) string {
manager_any, pres := scope.Resolve(ACL_MANAGER_VAR)
if !pres {
return ""
}
manager, ok := manager_any.(*ServerACLManager)
if !ok {
return ""
}
return manager.principal
}