// Copyright 2021, johan@nosd.in // +build freebsd // // godit is a search tool for BSM audit trails used by FreeBSD auditd // package main /* #cgo CFLAGS: -I /usr/lib #cgo LDFLAGS: -L. -lbsm -lc #include #include */ import "C" import "unsafe" import ( "io" "os" "fmt" // "encoding/hex" "github.com/spf13/pflag" ) const ( version = "0.01" ) var ( randFlag bool showVersion bool // Default delimiter delimiter = "," ) /* // This function only work on full file for the moment // It is essentially a rip of praudit:print_tokens function It is SLOW: yo@martine:~/Dev/go/godit % time praudit -l /home/yo/Dev/go/godit/20211228134923.20211228151348 > praudit.log 102.428u 8.496s 1:50.98 99.9% 10+167k 0+191152io 0pf+0w yo@martine:~/Dev/go/godit % time ./godit 20211228134923.20211228151348 > godit.log 232.573u 56.834s 5:12.00 92.7% 859+553k 0+381988io 0pf+0w */ func print_tokens(filename string) error { var buf *C.u_char var recLen C.int var bytesRead C.int var tok C.tokenstr_t var del *C.char var fp *C.FILE var cFilename *C.char var r *C.char del = C.CString(delimiter) r = C.CString("r") cFilename = C.CString(filename) fp = C.fopen(cFilename, r) if fp == nil { return fmt.Errorf("Error opening file %s\n", filename) } for recLen != -1 { recLen = C.au_read_rec(fp, &buf) if recLen == -1 { break } bytesRead = 0 for bytesRead < recLen { newstart := unsafe.Add(unsafe.Pointer(buf), bytesRead) if( -1 == C.au_fetch_tok(&tok, (*C.u_char)(newstart), recLen - bytesRead)) { break } C.au_print_flags_tok((*C.FILE)(C.stdout), &tok, del, C.AU_OFLAG_NONE) bytesRead += (C.int)(tok.len) // fmt.Printf is buffered, its use cause a time glitch on display C.putchar((C.int)(*del)) } fmt.Printf("\n") C.fflush((*C.FILE)(C.stdout)) // buf was allocated by au_read_rec(), we need to free it C.free(unsafe.Pointer(buf)) } C.fclose(fp) C.free(unsafe.Pointer(cFilename)) C.free(unsafe.Pointer(del)) C.free(unsafe.Pointer(r)) return nil } func main() { var flags int var oneLine bool var noUserResolve bool 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(&showVersion, "version", "V", false, "Show version then exit") pflag.Parse() if showVersion { fmt.Printf("Godit v%s\n", version) return } if oneLine { flags = flags + PRT_ONELINE } if noUserResolve { flags = flags + PRT_NORESOLVE_USER } args := os.Args filename := args[len(args)-1] /* fmt.Printf("Args: %s\n", args) fmt.Printf("Filename: %s\n", filename) */ if len(filename) > 0 { /* err := print_tokens(filename) if err != nil { :q fmt.Printf("Erreur dans print_tokens: %s\n", err.Error()) return } } */ f, err := os.Open(filename) if err != nil { fmt.Printf("Impossible d'ouvrir le fichier %s\n", filename) return } //for i := 0 ; i < 20 ; i++ { for { rec, err := readRecordToStruct(f) if err != nil { if err != io.EOF { fmt.Printf("Erreur : %v\n", err) } return } rec.Print(os.Stdout, ",", flags) } } }