diff --git a/auditbeat/module/file_integrity/event.go b/auditbeat/module/file_integrity/event.go index d26ca24c4845..ed5511a6f88f 100644 --- a/auditbeat/module/file_integrity/event.go +++ b/auditbeat/module/file_integrity/event.go @@ -23,12 +23,15 @@ import ( "crypto/sha1" "crypto/sha256" "crypto/sha512" + "encoding/base64" + "encoding/binary" "encoding/hex" "fmt" "hash" "io" "math" "os" + "os/user" "path/filepath" "runtime" "strconv" @@ -321,6 +324,15 @@ func buildMetricbeatEvent(e *Event, existedBefore bool) mb.Event { if len(info.Origin) > 0 { file["origin"] = info.Origin } + if info.SELinux != "" { + file["selinux"] = info.SELinux + } + if info.POSIXACLAccess != "" { + a, err := aclText(info.POSIXACLAccess) + if err == nil { + file["posix_acl_access"] = a + } + } } if len(e.Hashes) > 0 { @@ -358,6 +370,80 @@ func buildMetricbeatEvent(e *Event, existedBefore bool) mb.Event { return out } +func aclText(s string) ([]string, error) { + b, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(s, "0s")) + if err != nil { + return nil, err + } + if (len(b)-4)%8 != 0 { + return nil, fmt.Errorf("unexpected ACL length: %d", len(b)) + } + var a []string + b = b[4:] + for len(b) != 0 { + tag := binary.LittleEndian.Uint16(b) + perm := binary.LittleEndian.Uint16(b[2:]) + qual := binary.LittleEndian.Uint32(b[4:]) + a = append(a, fmt.Sprintf("%s:%s:%s", tags[tag], qualString(qual, tag), modeString(perm))) + b = b[8:] + } + return a, nil +} + +var tags = map[uint16]string{ + 0x00: "undefined", + 0x01: "user", + 0x02: "user", + 0x04: "group", + 0x08: "group", + 0x10: "mask", + 0x20: "other", +} + +func qualString(qual uint32, tag uint16) string { + if qual == math.MaxUint32 { + return "" + } + const ( + tagUser = 0x02 + tagGroup = 0x08 + ) + switch tag { + case tagUser: + uid := strconv.Itoa(int(qual)) + u, err := user.LookupId(uid) + if err != nil { + // Fallback to the numeric ID if we can't get a name. + return uid + } + return u.Username + case tagGroup: + gid := strconv.Itoa(int(qual)) + g, err := user.LookupGroupId(gid) + if err != nil { + // Fallback to the numeric ID if we can't get a name. + return gid + } + return g.Name + } + return "" +} + +func modeString(perm uint16) string { + var buf [3]byte + w := 0 + const rwx = "rwx" + for i, c := range rwx { + if perm&(1<