forked from elastic/go-libaudit
-
Notifications
You must be signed in to change notification settings - Fork 5
/
id_lookup.go
119 lines (100 loc) · 2.82 KB
/
id_lookup.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
package aucoalesce
import (
"math"
"os/user"
"strings"
"time"
)
const cacheTimeout = 0
var (
userLookup = NewUserCache()
groupLookup = NewGroupCache()
)
type stringItem struct {
timeout time.Time
value string
}
func (i *stringItem) isExpired() bool {
return time.Now().After(i.timeout)
}
// UserCache is a cache of UID to username.
type UserCache map[string]stringItem
// NewUserCache returns a new UserCache.
func NewUserCache() UserCache {
return map[string]stringItem{
"0": {timeout: time.Unix(math.MaxInt64, 0), value: "root"},
}
}
// LookupUID looks up a UID and returns the username associated with it. If
// no username could be found an empty string is returned. The value will be
// cached for a minute. This requires cgo on Linux.
func (c UserCache) LookupUID(uid string) string {
if uid == "" || uid == "unset" {
return ""
}
if item, found := c[uid]; found && !item.isExpired() {
return item.value
}
// Cache the value (even on error).
user, err := user.LookupId(uid)
if err != nil {
c[uid] = stringItem{timeout: time.Now().Add(cacheTimeout), value: ""}
return ""
}
c[uid] = stringItem{timeout: time.Now().Add(cacheTimeout), value: user.Username}
return user.Username
}
// GroupCache is a cache of GID to group name.
type GroupCache map[string]stringItem
// NewGroupCache returns a new GroupCache.
func NewGroupCache() GroupCache {
return map[string]stringItem{
"0": {timeout: time.Unix(math.MaxInt64, 0), value: "root"},
}
}
// LookupGID looks up a GID and returns the group associated with it. If
// no group could be found an empty string is returned. The value will be
// cached for a minute. This requires cgo on Linux.
func (c GroupCache) LookupGID(gid string) string {
if gid == "" || gid == "unset" {
return ""
}
if item, found := c[gid]; found && !item.isExpired() {
return item.value
}
// Cache the value (even on error).
group, err := user.LookupGroupId(gid)
if err != nil {
c[gid] = stringItem{timeout: time.Now().Add(cacheTimeout), value: ""}
return ""
}
c[gid] = stringItem{timeout: time.Now().Add(cacheTimeout), value: group.Name}
return group.Name
}
// ResolveIDs translates all uid and gid values to their associated names.
// This requires cgo on Linux.
func ResolveIDs(event *Event) {
if v := userLookup.LookupUID(event.Subject.Primary); v != "" {
event.Subject.Primary = v
}
if v := userLookup.LookupUID(event.Subject.Secondary); v != "" {
event.Subject.Secondary = v
}
processMap := func(m map[string]string) {
for key, id := range m {
if strings.HasSuffix(key, "uid") {
if v := userLookup.LookupUID(id); v != "" {
m[key] = v
}
} else if strings.HasSuffix(key, "gid") {
if v := groupLookup.LookupGID(id); v != "" {
m[key] = v
}
}
}
}
processMap(event.Subject.Attributes)
for _, path := range event.Paths {
processMap(path)
}
}