24 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
yo
2f1fc7e526 Merge branch 'json' 2023-09-10 15:19:33 +02:00
yo
079361c8cd Add support for zone name 2023-09-10 09:32:45 +02:00
yo
811d2c40d4 temporary work dir 2023-09-10 09:32:29 +02:00
yo
85844065e9 Merge branch 'json' of https://git.nosd.in/yo/libbsm into json 2023-09-06 21:35:04 +02:00
yo
85c1aff8ab Return -1 when input file not available 2023-09-06 21:33:44 +02:00
yo
9eb1d557b6 json support 2023-09-06 21:19:32 +02:00
yo
9716e6ed15 json support 2023-09-06 21:18:42 +02:00
yo
4b06c3064b Manual merge 2023-01-18 17:19:39 +01:00
yo
65afab1eec WIP: json output option 2023-01-17 11:17:01 +01:00
6 changed files with 2833 additions and 938 deletions

2
.gitignore vendored
View File

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

View File

@ -4,3 +4,9 @@ Golang implementation of openBSM library
BSM is the audit format used by Darwin/FreeBSD
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
go 1.17
go 1.18
require github.com/spf13/pflag v1.0.5

2139
libbsm.go

File diff suppressed because it is too large Load Diff

114
main.go
View File

@ -1,5 +1,7 @@
// Copyright 2021, johan@nosd.in
//go:build freebsd
// +build freebsd
//
// godit is a search tool for BSM audit trails used by FreeBSD auditd
//
@ -25,13 +27,16 @@ import (
"io"
"os"
"fmt"
"sync"
"bufio"
"strings"
"syscall"
"os/signal"
"github.com/spf13/pflag"
)
const (
version = "0.5.1"
version = "0.6.2"
)
var (
@ -40,19 +45,51 @@ var (
// Default 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() {
var flags int
var oneLine bool
var noUserResolve bool
var timestamp bool
var syslog23 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(&noUserResolve, "numeric", "n", false, "Do not convert user and group IDs to their names but leave in their numeric forms.")
pflag.BoolVarP(&timestamp, "timestamp", "t", false, "Print unix timestamp instead of formatted date/time.")
pflag.BoolVarP(&showVersion, "version", "V", false, "Show version then exit")
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(&json, "json", "j", false, "Print compact json")
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()
@ -60,29 +97,55 @@ func main() {
fmt.Printf("Godit v%s\n", version)
return
}
if oneLine {
flags = flags + PRT_ONELINE
}
if noUserResolve {
flags = flags + PRT_NORESOLVE_USER
}
if timestamp {
flags = flags + PRT_TIMESTAMP
if syslog23 {
flags = flags + PRT_TIMESYSLOG23
}
if json {
flags |= PRT_JSON
}
args := os.Args
if len(os.Args) < 2 {
pflag.Usage()
os.Exit(1)
}
filename := args[len(args)-1]
/* fmt.Printf("Args: %s\n", args)
fmt.Printf("Filename: %s\n", filename)
*/
// 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 r *bufio.Reader
var err error
if len(filename) > 0 {
// If arg is "-", open stdin to read content
if true == strings.EqualFold(filename, "-") {
@ -90,13 +153,12 @@ func main() {
} else {
f, err = os.Open(filename)
if err != nil {
fmt.Printf("Impossible d'ouvrir le fichier %s\n", filename)
return
fmt.Fprintf(os.Stderr, "Impossible d'ouvrir le fichier %s\n", filename)
os.Exit(-1)
}
r = bufio.NewReader(f)
}
//for i := 0 ; i < 20 ; i++ {
for {
rec, err := readRecordToStruct(r)
if err != nil {
@ -106,9 +168,21 @@ func main() {
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()
}
}