15 Commits

Author SHA1 Message Date
yo
3e4cdd6f35 Update readme 2023-12-18 14:00:28 +01:00
yo
f4314a8940 go version bump to 1.18 2023-12-18 13:13:51 +01:00
yo
30ea998620 v0.6.2 : Write to output file, SIGUSR1 will reopen output file so we can newsyslog 2023-12-18 11:55:23 +01:00
yo
e028ca7ee2 Write output to *bufio.Writer 2023-12-18 11:53:12 +01:00
yo
a1892cbe37 Bugfix when no input file specified 2023-09-11 16:14:33 +02:00
yo
9b849fad3a v0.6 2023-09-11 16:09:21 +02:00
yo
e9c7c7b744 Revert "v0.6"
This reverts commit 74ad307bd1.
2023-09-11 16:08:20 +02:00
yo
74ad307bd1 v0.6 2023-09-11 16:05:39 +02:00
yo
d1aedbb521 Fix version 2023-09-11 16:04:31 +02:00
yo
2a101d89d0 Add godit binary to gitignore 2023-09-11 14:54:07 +02:00
yo
e801a48c7c Add FreeBSD capabilities defines 2023-09-11 14:47:45 +02:00
yo
58ba24444d Readme update 2023-09-11 14:42:47 +02:00
yo
23441feaae Add AUT_RIGHTS (capabilities) 2023-09-11 14:41:10 +02:00
yo
ad4a46104c README update 2023-09-10 16:37:57 +02:00
yo
99bf812571 Add RSYSLOG_SyslogProtocol23Format timestamp format, bugfix zone name was printed in base64 2023-09-10 16:32:05 +02:00
6 changed files with 546 additions and 60 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
./20211228134923.20211228151348 ./20211228134923.20211228151348
tmpwrk tmpwrk
godit

View File

@ -4,3 +4,9 @@ Golang implementation of openBSM library
BSM is the audit format used by Darwin/FreeBSD BSM is the audit format used by Darwin/FreeBSD
See http://www.trustedbsd.org/openbsm.html See http://www.trustedbsd.org/openbsm.html
Include a binary "godit" which print audit logs in text or json format
Godit can read log files, /dev/auditpipe, or stdin with "-"
godit can be run as a service with included rc file. It needs audit to be configured to output to /dev/auditpipe.

242
capsicum.go Normal file
View File

@ -0,0 +1,242 @@
// This is an implementation of libbsm
// Copyright johan@nosd.in 2023
//
//go:build freebsd
// +build freebsd
//
package main
const (
// From freeebsd-src/sys/sys/caprights.h :
/*
* The top two bits in the first element of the cr_rights[] array contain
* total number of elements in the array - 2. This means if those two bits are
* equal to 0, we have 2 array elements.
* The top two bits in all remaining array elements should be 0.
* The next five bits contain array index. Only one bit is used and bit position
* in this five-bits range defines array index. This means there can be at most
* five array elements.
*/
// So, I lazily chose to include index bit in following values
/* INDEX 0 */
/*
* General file I/O.
*/
/* Allows for openat(O_RDONLY), read(2), readv(2). */
CAP_READ = 0x0200000000000001
/* Allows for openat(O_WRONLY | O_APPEND), write(2), writev(2). */
CAP_WRITE = 0x0200000000000002
/* Allows for lseek(fd, 0, SEEK_CUR). */
CAP_SEEK_TELL = 0x0200000000000004
/* Allows for lseek(2). */
CAP_SEEK = CAP_SEEK_TELL | 0x0200000000000008
/* Allows for aio_read(2), pread(2), preadv(2). */
CAP_PREAD = (CAP_SEEK | CAP_READ)
/*
* Allows for aio_write(2), openat(O_WRONLY) (without O_APPEND), pwrite(2),
* pwritev(2).
*/
CAP_PWRITE = (CAP_SEEK | CAP_WRITE)
/* Allows for mmap(PROT_NONE). */
CAP_MMAP = 0x0200000000000010
/* Allows for mmap(PROT_READ). */
CAP_MMAP_R = (CAP_MMAP | CAP_SEEK | CAP_READ)
/* Allows for mmap(PROT_WRITE). */
CAP_MMAP_W = (CAP_MMAP | CAP_SEEK | CAP_WRITE)
/* Allows for mmap(PROT_EXEC). */
CAP_MMAP_X = (CAP_MMAP | CAP_SEEK | 0x0200000000000020)
/* Allows for mmap(PROT_READ | PROT_WRITE). */
CAP_MMAP_RW = (CAP_MMAP_R | CAP_MMAP_W)
/* Allows for mmap(PROT_READ | PROT_EXEC). */
CAP_MMAP_RX = (CAP_MMAP_R | CAP_MMAP_X)
/* Allows for mmap(PROT_WRITE | PROT_EXEC). */
CAP_MMAP_WX = (CAP_MMAP_W | CAP_MMAP_X)
/* Allows for mmap(PROT_READ | PROT_WRITE | PROT_EXEC). */
CAP_MMAP_RWX = (CAP_MMAP_R | CAP_MMAP_W | CAP_MMAP_X)
/* Allows for openat(O_CREAT). */
CAP_CREATE = 0x0200000000000040
/* Allows for openat(O_EXEC) and fexecve(2) in turn. */
CAP_FEXECVE = 0x0200000000000080
/* Allows for openat(O_SYNC), openat(O_FSYNC), fsync(2), aio_fsync(2). */
CAP_FSYNC = 0x0200000000000100
/* Allows for openat(O_TRUNC), ftruncate(2). */
CAP_FTRUNCATE = 0x0200000000000200
/* Lookups - used to constrain *at() calls. */
CAP_LOOKUP = 0x0200000000000400
/* VFS methods. */
/* Allows for fchdir(2). */
CAP_FCHDIR = 0x0200000000000800
/* Allows for fchflags(2). */
CAP_FCHFLAGS = 0x0200000000001000
/* Allows for fchflags(2) and chflagsat(2). */
CAP_CHFLAGSAT = (CAP_FCHFLAGS | CAP_LOOKUP)
/* Allows for fchmod(2). */
CAP_FCHMOD = 0x0200000000002000
/* Allows for fchmod(2) and fchmodat(2). */
CAP_FCHMODAT = (CAP_FCHMOD | CAP_LOOKUP)
/* Allows for fchown(2). */
CAP_FCHOWN = 0x0200000000004000
/* Allows for fchown(2) and fchownat(2). */
CAP_FCHOWNAT = (CAP_FCHOWN | CAP_LOOKUP)
/* Allows for fcntl(2). */
CAP_FCNTL = 0x0200000000008000
/*
* Allows for flock(2), openat(O_SHLOCK), openat(O_EXLOCK),
* fcntl(F_SETLK_REMOTE), fcntl(F_SETLKW), fcntl(F_SETLK), fcntl(F_GETLK).
*/
CAP_FLOCK = 0x0200000000010000
/* Allows for fpathconf(2). */
CAP_FPATHCONF = 0x0200000000020000
/* Allows for UFS background-fsck operations. */
CAP_FSCK = 0x0200000000040000
/* Allows for fstat(2). */
CAP_FSTAT = 0x0200000000080000
/* Allows for fstat(2), fstatat(2) and faccessat(2). */
CAP_FSTATAT = (CAP_FSTAT | CAP_LOOKUP)
/* Allows for fstatfs(2). */
CAP_FSTATFS = 0x0200000000100000
/* Allows for futimens(2) and futimes(2). */
CAP_FUTIMES = 0x0200000000200000
/* Allows for futimens(2), futimes(2), futimesat(2) and utimensat(2). */
CAP_FUTIMESAT = (CAP_FUTIMES | CAP_LOOKUP)
/* Allows for linkat(2) (target directory descriptor). */
CAP_LINKAT_TARGET = (CAP_LOOKUP | 0x0200000000400000)
/* Allows for mkdirat(2). */
CAP_MKDIRAT = (CAP_LOOKUP | 0x0200000000800000)
/* Allows for mkfifoat(2). */
CAP_MKFIFOAT = (CAP_LOOKUP | 0x0200000001000000)
/* Allows for mknodat(2). */
CAP_MKNODAT = (CAP_LOOKUP | 0x0200000002000000)
/* Allows for renameat(2) (source directory descriptor). */
CAP_RENAMEAT_SOURCE = (CAP_LOOKUP | 0x0200000004000000)
/* Allows for symlinkat(2). */
CAP_SYMLINKAT = (CAP_LOOKUP | 0x0200000008000000)
/*
* Allows for unlinkat(2) and renameat(2) if destination object exists and
* will be removed.
*/
CAP_UNLINKAT = (CAP_LOOKUP | 0x0200000010000000)
/* Socket operations. */
/* Allows for accept(2) and accept4(2). */
CAP_ACCEPT = 0x0200000020000000
/* Allows for bind(2). */
CAP_BIND = 0x0200000040000000
/* Allows for connect(2). */
CAP_CONNECT = 0x0200000080000000
/* Allows for getpeername(2). */
CAP_GETPEERNAME = 0x0200000100000000
/* Allows for getsockname(2). */
CAP_GETSOCKNAME = 0x0200000200000000
/* Allows for getsockopt(2). */
CAP_GETSOCKOPT = 0x0200000400000000
/* Allows for listen(2). */
CAP_LISTEN = 0x0200000800000000
/* Allows for sctp_peeloff(2). */
CAP_PEELOFF = 0x0300001000000000
CAP_RECV = CAP_READ
CAP_SEND = CAP_WRITE
/* Allows for setsockopt(2). */
CAP_SETSOCKOPT = 0x0200002000000000
/* Allows for shutdown(2). */
CAP_SHUTDOWN = 0x0200004000000000
/* Allows for bindat(2) on a directory descriptor. */
CAP_BINDAT = (CAP_LOOKUP | 0x0200008000000000)
/* Allows for connectat(2) on a directory descriptor. */
CAP_CONNECTAT = (CAP_LOOKUP | 0x0200010000000000)
/* Allows for linkat(2) (source directory descriptor). */
CAP_LINKAT_SOURCE = (CAP_LOOKUP | 0x0200020000000000)
/* Allows for renameat(2) (target directory descriptor). */
CAP_RENAMEAT_TARGET = (CAP_LOOKUP | 0x0200040000000000)
CAP_SOCK_CLIENT = (CAP_CONNECT | CAP_GETPEERNAME | CAP_GETSOCKNAME | CAP_GETSOCKOPT |
CAP_PEELOFF | CAP_RECV | CAP_SEND | CAP_SETSOCKOPT | CAP_SHUTDOWN)
CAP_SOCK_SERVER = (CAP_ACCEPT | CAP_BIND | CAP_GETPEERNAME | CAP_GETSOCKNAME |
CAP_GETSOCKOPT | CAP_LISTEN | CAP_PEELOFF | CAP_RECV | CAP_SEND |
CAP_SETSOCKOPT | CAP_SHUTDOWN)
/* All used bits for index 0. */
CAP_ALL0 = 0x020007FFFFFFFFFF
/* Available bits for index 0. */
CAP_UNUSED0_44 = 0x0200080000000000
/* ... */
CAP_UNUSED0_57 = 0x0300000000000000
/* INDEX 1 */
/* Mandatory Access Control. */
/* Allows for mac_get_fd(3). */
CAP_MAC_GET = 0x0400000000000001
/* Allows for mac_set_fd(3). */
CAP_MAC_SET = 0x0400000000000002
/* Methods on semaphores. */
CAP_SEM_GETVALUE = 0x0400000000000004
CAP_SEM_POST = 0x0400000000000008
CAP_SEM_WAIT = 0x0400000000000010
/* Allows select(2) and poll(2) on descriptor. */
CAP_EVENT = 0x0400000000000020
/* Allows for kevent(2) on kqueue descriptor with eventlist != NULL. */
CAP_KQUEUE_EVENT = 0x0400000000000040
/* Strange and powerful rights that should not be given lightly. */
/* Allows for ioctl(2). */
CAP_IOCTL = 0x0400000000000080
CAP_TTYHOOK = 0x0400000000000100
/* Process management via process descriptors. */
/* Allows for pdgetpid(2). */
CAP_PDGETPID = 0x0400000000000200
/*
* Allows for pdwait4(2).
*
* XXX: this constant was imported unused, but is targeted to be implemented
* in the future (bug 235871).
*/
CAP_PDWAIT = 0x0400000000000400
/* Allows for pdkill(2). */
CAP_PDKILL = 0x0400000000000800
/* Extended attributes. */
/* Allows for extattr_delete_fd(2). */
CAP_EXTATTR_DELETE = 0x0400000000001000
/* Allows for extattr_get_fd(2). */
CAP_EXTATTR_GET = 0x0400000000002000
/* Allows for extattr_list_fd(2). */
CAP_EXTATTR_LIST = 0x0400000000004000
/* Allows for extattr_set_fd(2). */
CAP_EXTATTR_SET = 0x0400000000008000
/* Access Control Lists. */
/* Allows for acl_valid_fd_np(3). */
CAP_ACL_CHECK = 0x0400000000010000
/* Allows for acl_delete_fd_np(3). */
CAP_ACL_DELETE = 0x0400000000020000
/* Allows for acl_get_fd(3) and acl_get_fd_np(3). */
CAP_ACL_GET = 0x0400000000040000
/* Allows for acl_set_fd(3) and acl_set_fd_np(3). */
CAP_ACL_SET = 0x0400000000080000
/* Allows for kevent(2) on kqueue descriptor with changelist != NULL. */
CAP_KQUEUE_CHANGE = 0x0400000000100000
CAP_KQUEUE = (CAP_KQUEUE_EVENT | CAP_KQUEUE_CHANGE)
/* All used bits for index 1. */
CAP_ALL1 = 0x04000000001FFFFF
/* Available bits for index 1. */
CAP_UNUSED1_22 = 0x0400000000200000
/* ... */
CAP_UNUSED1_57 = 0x0500000000000000
)

2
go.mod
View File

@ -1,5 +1,5 @@
module godit module godit
go 1.17 go 1.18
require github.com/spf13/pflag v1.0.5 require github.com/spf13/pflag v1.0.5

219
libbsm.go
View File

@ -120,14 +120,16 @@ const (
AUT_PROCESS64_EX = 0x7d AUT_PROCESS64_EX = 0x7d
AUT_IN_ADDR_EX = 0x7e AUT_IN_ADDR_EX = 0x7e
AUT_SOCKET_EX = 0x7f AUT_SOCKET_EX = 0x7f
// From sys/bsm/audit_record.h
AUT_SOCKINET32 = 0x80 AUT_SOCKINET32 = 0x80
AUT_SOCKINET128 = 0x81 AUT_SOCKINET128 = 0x81
AUT_SOCKUNIX = 0x82 AUT_SOCKUNIX = 0x82
AUT_RIGHTS = 0x83
// Display control // Display control
PRT_ONELINE = 1 PRT_ONELINE = 1
PRT_NORESOLVE_USER = 2 PRT_NORESOLVE_USER = 2
PRT_TIMESTAMP = 4 PRT_TIMESYSLOG23 = 4
PRT_JSON = 8 PRT_JSON = 8
) )
@ -154,7 +156,7 @@ type Record interface {
GetType() uint8 GetType() uint8
// Length() // Length()
LoadFromBinary(rdr *bufio.Reader) error LoadFromBinary(rdr *bufio.Reader) error
Print(*os.File, string, int) Print(*bufio.Writer, string, int)
} }
type Header32 struct { type Header32 struct {
@ -373,6 +375,17 @@ type ZoneName struct {
Zone []byte `json:"zone"` Zone []byte `json:"zone"`
} }
type Capabilities struct {
Index uint8 `json:"index"`
Value uint64 `json:"value"`
}
type Rights struct {
Length uint8 `json:"length"` // Should it be nr of indices, or nr of capabilities? (in which case it should be calculated)
// Let it be nr of indices for now, we'll see when we will decode rights
Rights []Capabilities `json:"rights"`
}
/* Utilities */ /* Utilities */
// users ID for resolution // users ID for resolution
type user struct { type user struct {
@ -592,10 +605,10 @@ func (h *Header32) LoadFromBinary(rdr *bufio.Reader) error {
static void static void
print_header32_tok(FILE *fp, tokenstr_t *tok, char *del, int oflags) print_header32_tok(FILE *fp, tokenstr_t *tok, char *del, int oflags)
*/ */
func (h *Header32) Print(file *os.File, delimiter string, flags int) { func (h *Header32) Print(file *bufio.Writer, delimiter string, flags int) {
var timeval string var timeval string
if PRT_TIMESTAMP == flags&PRT_TIMESTAMP { if PRT_TIMESYSLOG23 == flags&PRT_TIMESYSLOG23 {
timeval = strconv.Itoa(int(h.S)) timeval = time.Unix((int64)(h.S), 0).Add(time.Millisecond * (time.Duration)(h.Msec)).Format("2006-01-02T15:04:05.000Z07:00")
} else { } else {
t := time.Unix((int64)(h.S), 0) t := time.Unix((int64)(h.S), 0)
timeval = t.Format(time.UnixDate) timeval = t.Format(time.UnixDate)
@ -607,7 +620,23 @@ func (h *Header32) Print(file *os.File, delimiter string, flags int) {
} }
if flags&PRT_JSON == PRT_JSON { if flags&PRT_JSON == PRT_JSON {
printable := struct { var printable interface{}
if PRT_TIMESYSLOG23 == flags&PRT_TIMESYSLOG23 {
printable = struct {
Size uint32 `json:"size"` // Record byte count
Version uint8 `json:"version"` // version # (uchar)
E_type string `json:"event_type"` // Event type
E_mod uint16 `json:"event_modifier"` // Event modifier
Ts string `json:"timestamp"` // Seconds of time converted to RSYSLOG_SyslogProtocol23Format
}{
Size: h.Size,
Version: h.Version,
E_type: evdesc,
E_mod: h.E_mod,
Ts: timeval,
}
} else {
printable = struct {
Size uint32 `json:"size"` // Record byte count Size uint32 `json:"size"` // Record byte count
Version uint8 `json:"version"` // version # (uchar) Version uint8 `json:"version"` // version # (uchar)
E_type string `json:"event_type"` // Event type E_type string `json:"event_type"` // Event type
@ -622,6 +651,7 @@ func (h *Header32) Print(file *os.File, delimiter string, flags int) {
Ts: timeval, Ts: timeval,
Msec: h.Msec, Msec: h.Msec,
} }
}
j, err := json.Marshal(printable) j, err := json.Marshal(printable)
if err != nil { if err != nil {
@ -674,7 +704,7 @@ func (e *ExecArg) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (e *ExecArg) Print(file *os.File, delimiter string, flags int) { func (e *ExecArg) Print(file *bufio.Writer, delimiter string, flags int) {
if flags&PRT_JSON == PRT_JSON { if flags&PRT_JSON == PRT_JSON {
// We don't need no count, bc we reconstiture command line // We don't need no count, bc we reconstiture command line
printable := struct { printable := struct {
@ -740,7 +770,7 @@ func (p *Path) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (p *Path) Print(file *os.File, delimiter string, flags int) { func (p *Path) Print(file *bufio.Writer, delimiter string, flags int) {
if flags&PRT_JSON == PRT_JSON { if flags&PRT_JSON == PRT_JSON {
// We don't need no length // We don't need no length
printable := struct { printable := struct {
@ -817,7 +847,7 @@ func (a *Attribute32) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (a *Attribute32) Print(file *os.File, delimiter string, flags int) { func (a *Attribute32) Print(file *bufio.Writer, delimiter string, flags int) {
var user string var user string
var group string var group string
@ -922,7 +952,7 @@ func (a *Attribute64) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (a *Attribute64) Print(file *os.File, delimiter string, flags int) { func (a *Attribute64) Print(file *bufio.Writer, delimiter string, flags int) {
var user string var user string
var group string var group string
// TODO : resolve Uid and Gid (also support domain accounts) // TODO : resolve Uid and Gid (also support domain accounts)
@ -1052,7 +1082,7 @@ func (s *Subject32) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (s *Subject32) Print(file *os.File, delimiter string, flags int) { func (s *Subject32) Print(file *bufio.Writer, delimiter string, flags int) {
var auser string var auser string
var euser string var euser string
var egroup string var egroup string
@ -1195,7 +1225,7 @@ func (p *Process32) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (p *Process32) Print(file *os.File, delimiter string, flags int) { func (p *Process32) Print(file *bufio.Writer, delimiter string, flags int) {
var auser string var auser string
var euser string var euser string
var egroup string var egroup string
@ -1356,7 +1386,7 @@ func (s *Subject32Ex) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (s *Subject32Ex) Print(file *os.File, delimiter string, flags int) { func (s *Subject32Ex) Print(file *bufio.Writer, delimiter string, flags int) {
var auser string var auser string
var euser string var euser string
var egroup string var egroup string
@ -1528,7 +1558,7 @@ func (p *Process32Ex) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (p *Process32Ex) Print(file *os.File, delimiter string, flags int) { func (p *Process32Ex) Print(file *bufio.Writer, delimiter string, flags int) {
var auser string var auser string
var euser string var euser string
var egroup string var egroup string
@ -1684,7 +1714,7 @@ func (s *Subject64) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (s *Subject64) Print(file *os.File, delimiter string, flags int) { func (s *Subject64) Print(file *bufio.Writer, delimiter string, flags int) {
var auser string var auser string
var euser string var euser string
var egroup string var egroup string
@ -1827,7 +1857,7 @@ func (p *Process64) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (p *Process64) Print(file *os.File, delimiter string, flags int) { func (p *Process64) Print(file *bufio.Writer, delimiter string, flags int) {
var auser string var auser string
var euser string var euser string
var egroup string var egroup string
@ -1987,7 +2017,7 @@ func (s *Subject64Ex) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (s *Subject64Ex) Print(file *os.File, delimiter string, flags int) { func (s *Subject64Ex) Print(file *bufio.Writer, delimiter string, flags int) {
var auser string var auser string
var euser string var euser string
var egroup string var egroup string
@ -2159,7 +2189,7 @@ func (p *Process64Ex) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (p *Process64Ex) Print(file *os.File, delimiter string, flags int) { func (p *Process64Ex) Print(file *bufio.Writer, delimiter string, flags int) {
var auser string var auser string
var euser string var euser string
var egroup string var egroup string
@ -2278,7 +2308,7 @@ func (r *Return32) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (r *Return32) Print(file *os.File, delimiter string, flags int) { func (r *Return32) Print(file *bufio.Writer, delimiter string, flags int) {
var errMsg string var errMsg string
errNo, err := lookupErrno(r.Status) errNo, err := lookupErrno(r.Status)
if err == nil { if err == nil {
@ -2339,7 +2369,7 @@ func (r *Return64) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (r *Return64) Print(file *os.File, delimiter string, flags int) { func (r *Return64) Print(file *bufio.Writer, delimiter string, flags int) {
var errMsg string var errMsg string
errNo, err := lookupErrno(r.Status) errNo, err := lookupErrno(r.Status)
if err == nil { if err == nil {
@ -2400,7 +2430,7 @@ func (t *Trailer) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (t *Trailer) Print(file *os.File, delimiter string, flags int) { func (t *Trailer) Print(file *bufio.Writer, delimiter string, flags int) {
if flags&PRT_JSON == PRT_JSON { if flags&PRT_JSON == PRT_JSON {
printable := struct { printable := struct {
Count uint32 `json:"length"` // Effective user ID Count uint32 `json:"length"` // Effective user ID
@ -2463,7 +2493,7 @@ func (a *Arg32) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (a *Arg32) Print(file *os.File, delimiter string, flags int) { func (a *Arg32) Print(file *bufio.Writer, delimiter string, flags int) {
if flags&PRT_JSON == PRT_JSON { if flags&PRT_JSON == PRT_JSON {
printable := struct { printable := struct {
Count uint32 `json:"count"` // Effective user ID Count uint32 `json:"count"` // Effective user ID
@ -2533,7 +2563,7 @@ func (a *Arg64) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (a *Arg64) Print(file *os.File, delimiter string, flags int) { func (a *Arg64) Print(file *bufio.Writer, delimiter string, flags int) {
if flags&PRT_JSON == PRT_JSON { if flags&PRT_JSON == PRT_JSON {
printable := struct { printable := struct {
Count uint32 `json:"count"` // Effective user ID Count uint32 `json:"count"` // Effective user ID
@ -2637,7 +2667,7 @@ func (s *SocketEx) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (s *SocketEx) Print(file *os.File, delimiter string, flags int) { func (s *SocketEx) Print(file *bufio.Writer, delimiter string, flags int) {
var lip string var lip string
var rip string var rip string
if s.AddrType == ISIPV4 { if s.AddrType == ISIPV4 {
@ -2702,7 +2732,7 @@ func (s *SockInet32) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (s *SockInet32) Print(file *os.File, delimiter string, flags int) { func (s *SockInet32) Print(file *bufio.Writer, delimiter string, flags int) {
if flags&PRT_JSON == PRT_JSON { if flags&PRT_JSON == PRT_JSON {
printable := struct { printable := struct {
Family uint16 `json:"family"` Family uint16 `json:"family"`
@ -2764,7 +2794,7 @@ func (s *SockInet128) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (s *SockInet128) Print(file *os.File, delimiter string, flags int) { func (s *SockInet128) Print(file *bufio.Writer, delimiter string, flags int) {
if flags&PRT_JSON == PRT_JSON { if flags&PRT_JSON == PRT_JSON {
printable := struct { printable := struct {
Family uint16 `json:"family"` Family uint16 `json:"family"`
@ -2822,7 +2852,7 @@ func (s *SockUnix) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (s *SockUnix) Print(file *os.File, delimiter string, flags int) { func (s *SockUnix) Print(file *bufio.Writer, delimiter string, flags int) {
if flags&PRT_JSON == PRT_JSON { if flags&PRT_JSON == PRT_JSON {
printable := struct { printable := struct {
Family uint16 `json:"family"` Family uint16 `json:"family"`
@ -2875,7 +2905,7 @@ func (e *Exit) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (e *Exit) Print(file *os.File, delimiter string, flags int) { func (e *Exit) Print(file *bufio.Writer, delimiter string, flags int) {
if flags&PRT_JSON == PRT_JSON { if flags&PRT_JSON == PRT_JSON {
j, err := json.Marshal(e) j, err := json.Marshal(e)
if err != nil { if err != nil {
@ -2923,7 +2953,7 @@ func (t *Text) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (t *Text) Print(file *os.File, delimiter string, flags int) { func (t *Text) Print(file *bufio.Writer, delimiter string, flags int) {
if flags&PRT_JSON == PRT_JSON { if flags&PRT_JSON == PRT_JSON {
j, err := json.Marshal(t) j, err := json.Marshal(t)
if err != nil { if err != nil {
@ -2971,15 +3001,137 @@ func (z *ZoneName) LoadFromBinary(rdr *bufio.Reader) error {
return nil return nil
} }
func (z *ZoneName) Print(file *os.File, delimiter string, flags int) { func (z *ZoneName) Print(file *bufio.Writer, delimiter string, flags int) {
if flags&PRT_JSON == PRT_JSON {
printable := struct {
Name string `json:"name"`
}{
Name: string(z.Zone),
}
j, err := json.Marshal(printable)
if err != nil {
// TODO
return
}
fmt.Fprintf(file, "\"zone\":")
fmt.Fprintf(file, "%s", j)
// ZoneName is always followed by something
fmt.Fprintf(file, ",")
} else {
fmt.Fprintf(file, "zone%s%s", delimiter, z.Zone) fmt.Fprintf(file, "zone%s%s", delimiter, z.Zone)
if 0 == (flags & PRT_ONELINE) { if 0 == (flags & PRT_ONELINE) {
fmt.Fprintf(file, "\n") fmt.Fprintf(file, "\n")
} else { } else {
fmt.Fprintf(file, "%s", delimiter) fmt.Fprintf(file, "%s", delimiter)
} }
}
} }
func NewRights(r Rights) *Rights {
return &Rights{
Length: r.Length,
Rights: r.Rights,
}
}
func (r *Rights) GetType() uint8 {
return AUT_RIGHTS
}
func (r *Rights) getIndex(value uint64) uint8 {
var index uint8
idx := (value >> 57) & 0b11111
switch idx {
case 1: index = 0
case 2: index = 1
case 4: index = 2
case 8: index = 3
case 16: index = 4
}
return index
}
func (r *Rights) LoadFromBinary(rdr *bufio.Reader) error {
var firstVal uint64
var nextVal uint64
err := binary.Read(rdr, binary.BigEndian, &firstVal)
if err != nil {
return fmt.Errorf("Unable to read Rights.Length: %v", err)
}
/* The top two bits in the first element of the cr_rights[] array contain
* total number of elements in the array - 2 */
r.Length = uint8((firstVal >> 62) + 2)
rights := make([]Capabilities, r.Length)
capab := &Capabilities{
Index: r.getIndex(firstVal),
Value: firstVal,
}
rights[0] = *capab
for i := 1; i < int(r.Length); i++ {
err = binary.Read(rdr, binary.BigEndian, &nextVal)
if err != nil {
return fmt.Errorf("Unable to read Rights.Rights: %v", err)
} else {
capab := &Capabilities{
Index: r.getIndex(nextVal),
Value: nextVal,
}
rights[i] = *capab
}
}
r.Rights = rights[:r.Length]
return nil
}
// Override Capabilities Marshaling so we can print as hex
func (c *Capabilities) MarshalJSON() ([]byte, error) {
val := fmt.Sprintf("%0.16x", c.Value)
type CapabilitiesJSON Capabilities
cJSON := struct {
Capabilities
Value string `json:"value"`
}{
Capabilities: Capabilities(*c),
Value: val,
}
return json.Marshal(cJSON)
}
func (r *Rights) Print(file *bufio.Writer, delimiter string, flags int) {
if flags&PRT_JSON == PRT_JSON {
// Do not print Rights.Length, only capabilities array
j, err := json.Marshal(r.Rights)
if err != nil {
// TODO
return
}
fmt.Fprintf(file, "\"rights\":")
fmt.Fprintf(file, "%s", j)
// Rights is always followed by something
fmt.Fprintf(file, ",")
} else {
fmt.Fprintf(file, "rights%s%d", delimiter, r.Length)
for i:=0; i < int(r.Length); i++ {
if i < int(r.Length) {
fmt.Fprintf(file, "%s", delimiter)
}
fmt.Fprintf(file, "%d%s%0.16x", r.Rights[i].Index, delimiter, r.Rights[i].Value)
}
if 0 == (flags & PRT_ONELINE) {
fmt.Fprintf(file, "\n")
} else {
fmt.Fprintf(file, "%s", delimiter)
}
}
}
// From sys/bsm/audit_record.h // From sys/bsm/audit_record.h
func readRecordToStruct(reader *bufio.Reader) (Record, error) { func readRecordToStruct(reader *bufio.Reader) (Record, error) {
@ -3149,6 +3301,13 @@ func readRecordToStruct(reader *bufio.Reader) (Record, error) {
return rec, fmt.Errorf("Unable to read: %v", err) return rec, fmt.Errorf("Unable to read: %v", err)
} }
return NewZoneName(z), nil return NewZoneName(z), nil
case AUT_RIGHTS:
var r Rights
err := r.LoadFromBinary(reader)
if err != nil {
return rec, fmt.Errorf("Unable to read: %v", err)
}
return NewRights(r), nil
} }
return rec, fmt.Errorf("Event type not supported: 0x%x", hdr[0]) return rec, fmt.Errorf("Event type not supported: 0x%x", hdr[0])

100
main.go
View File

@ -27,13 +27,16 @@ import (
"io" "io"
"os" "os"
"fmt" "fmt"
"sync"
"bufio" "bufio"
"strings" "strings"
"syscall"
"os/signal"
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
const ( const (
version = "5.9.9a" version = "0.6.2"
) )
var ( var (
@ -42,19 +45,51 @@ var (
// Default delimiter // Default delimiter
delimiter = "," delimiter = ","
Writer *bufio.Writer
) )
func NewWriter(file string) (*bufio.Writer, *os.File, error) {
if len(file) > 0 {
var f *os.File
var err error
f, err = os.OpenFile(file, os.O_CREATE|os.O_WRONLY, 0640)
if err != nil {
return nil, nil, err
}
Writer = bufio.NewWriter(f)
return Writer, f, nil
} else {
Writer = bufio.NewWriter(os.Stdout)
return Writer, nil, nil
}
}
func main() { func main() {
var flags int var flags int
var oneLine bool var oneLine bool
var noUserResolve bool var noUserResolve bool
var timestamp bool var syslog23 bool
var json bool var json bool
var outputFile string
// Output file mutex
var outfMtx sync.Mutex
var outFile *os.File
pflag.BoolVarP(&oneLine, "oneline", "l", false, "Prints the entire record on the same line. If this option is not specified, every token is displayed on a different line.") pflag.BoolVarP(&oneLine, "oneline", "l", false, "Prints the entire record on the same line")
pflag.BoolVarP(&noUserResolve, "numeric", "n", false, "Do not convert user and group IDs to their names but leave in their numeric forms.") pflag.BoolVarP(&noUserResolve, "numeric", "n", false, "Do not convert user and group IDs to their names but leave in their numeric forms")
pflag.BoolVarP(&json, "json", "j", false, "Print compact json") pflag.BoolVarP(&json, "json", "j", false, "Print compact json")
pflag.BoolVarP(&showVersion, "version", "V", false, "Show version then exit") pflag.BoolVarP(&syslog23, "syslog23", "s", false, "Print time as \"2006-01-02T15:04:05.000Z07:00\", RFC339 with ms, also used on RSYSLOG_SyslogProtocol23Format. \"msec\" field will not be print in json output")
pflag.StringVarP(&outputFile, "out", "o", "", "Output to file, overwrite existing. File will be re-opened receiving SIGUSR1.")
pflag.BoolVarP(&showVersion, "version", "V", false, "Show version and exit")
var Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of \"%s [opts] auditfile\":\n", os.Args[0])
pflag.PrintDefaults()
fmt.Fprintf(os.Stderr, "Set auditfile to \"-\" to read stdin\n")
}
pflag.Usage = Usage
pflag.Parse() pflag.Parse()
@ -68,19 +103,49 @@ func main() {
if noUserResolve { if noUserResolve {
flags = flags + PRT_NORESOLVE_USER flags = flags + PRT_NORESOLVE_USER
} }
if timestamp { if syslog23 {
flags = flags + PRT_TIMESTAMP flags = flags + PRT_TIMESYSLOG23
} }
if json { if json {
flags |= PRT_JSON flags |= PRT_JSON
} }
args := os.Args args := os.Args
if len(os.Args) < 2 {
pflag.Usage()
os.Exit(1)
}
filename := args[len(args)-1] filename := args[len(args)-1]
// Get a writer, file or stdout
_, outFile, err := NewWriter(outputFile)
if err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
if len(outputFile) > 0 {
// Manage output file rotation when receiving SIGUSR1
sig := make(chan os.Signal)
signal.Notify(sig, syscall.SIGUSR1)
go func() {
for {
<-sig
outfMtx.Lock()
fmt.Println("SIGUSR1 received, recreating output file")
outFile.Close()
_, outFile, err = NewWriter(outputFile)
if err != nil {
outfMtx.Unlock()
fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1)
}
outfMtx.Unlock()
}
}()
}
var f *os.File var f *os.File
var r *bufio.Reader var r *bufio.Reader
var err error
if len(filename) > 0 { if len(filename) > 0 {
// If arg is "-", open stdin to read content // If arg is "-", open stdin to read content
if true == strings.EqualFold(filename, "-") { if true == strings.EqualFold(filename, "-") {
@ -88,13 +153,12 @@ func main() {
} else { } else {
f, err = os.Open(filename) f, err = os.Open(filename)
if err != nil { if err != nil {
fmt.Printf("Impossible d'ouvrir le fichier %s\n", filename) fmt.Fprintf(os.Stderr, "Impossible d'ouvrir le fichier %s\n", filename)
os.Exit(-1) os.Exit(-1)
} }
r = bufio.NewReader(f) r = bufio.NewReader(f)
} }
//for i := 0 ; i < 20 ; i++ {
for { for {
rec, err := readRecordToStruct(r) rec, err := readRecordToStruct(r)
if err != nil { if err != nil {
@ -104,7 +168,21 @@ func main() {
return return
} }
} }
rec.Print(os.Stdout, ",", flags) if len(outputFile) > 0 {
outfMtx.Lock()
rec.Print(Writer, ",", flags)
Writer.Flush() // Performance ?
outfMtx.Unlock()
} else {
// No need for mutex with stdout
rec.Print(Writer, ",", flags)
} }
} }
}
if len(outputFile) > 0 && outFile != nil {
outfMtx.Lock()
outFile.Close()
outfMtx.Unlock()
}
} }