2 Commits
v.0.2 ... v.0.3

Author SHA1 Message Date
yo
92ba4e4ca6 Resolve event name 2022-01-06 17:29:16 +01:00
yo
8fd6e20cbd Resolve auid 2022-01-04 18:48:18 +01:00
2 changed files with 102 additions and 89 deletions

105
libbsm.go
View File

@ -23,16 +23,20 @@ import (
"os" "os"
"fmt" "fmt"
"time" "time"
"bufio"
"bytes" "bytes"
"strings"
"strconv" "strconv"
"encoding/binary" "encoding/binary"
) )
const ( const (
// bsm/libbsm.h // bsm/libbsm.h
AUDIT_MAX_ARGS = 128 AUDIT_MAX_ARGS = 128
AUDIT_EVENT_FILE = "/etc/security/audit_event"
// sys/bsm/audit.h // sys/bsm/audit.h
MAXAUDITDATA = (0x8000 - 1) MAXAUDITDATA = (0x8000 - 1)
MAX_AUDIT_RECORD_SIZE = MAXAUDITDATA MAX_AUDIT_RECORD_SIZE = MAXAUDITDATA
// Max length for a Path (AUT_PATH) or an arg (AUT_EXEC_ARGS) // Max length for a Path (AUT_PATH) or an arg (AUT_EXEC_ARGS)
@ -119,8 +123,19 @@ var (
gUsers []user gUsers []user
// A global group/gid cache // A global group/gid cache
gGroups []group gGroups []group
// Cache of audit_event file
gEventDB []event
) )
type event struct {
Type int
Name string
Desc string
Class string
}
// Fields types, from https://github.com/freebsd/freebsd-src/blob/main/contrib/openbsm/bsm/libbsm.h // Fields types, from https://github.com/freebsd/freebsd-src/blob/main/contrib/openbsm/bsm/libbsm.h
// Abstraction of a record // Abstraction of a record
@ -394,6 +409,45 @@ func getGroupNameByGid(gid uint32) (group, error) {
return grp, nil return grp, nil
} }
func getEventName(event uint16) (string,error) {
if len(gEventDB) == 0 {
loadEventDB()
}
for _, ev := range gEventDB {
if ev.Type == int(event) {
return ev.Desc, nil
}
}
return "", fmt.Errorf("Event ID not found: %x\n", event)
}
// We load the entire file in memory
func loadEventDB() error {
file, err := os.Open(AUDIT_EVENT_FILE)
if err != nil {
return err
}
defer file.Close()
fileScan := bufio.NewScanner(file)
fileScan.Split(bufio.ScanLines)
for fileScan.Scan() {
line := fileScan.Text()
if strings.HasPrefix(line, "#") {
continue
}
eventStr := strings.Split(line, ":")
if len(eventStr) != 4 {
continue
}
t, _ := strconv.Atoi(eventStr[0])
gEventDB = append(gEventDB, event{Type: t,
Name: eventStr[1],
Desc: eventStr[2],
Class: eventStr[3],})
}
return nil
}
func PrintIpv4FromInt(ipv4int uint32) string { func PrintIpv4FromInt(ipv4int uint32) string {
return fmt.Sprintf("%d.%d.%d.%d", ipv4int & 0xFF000000 >> 24, ipv4int & 0x00FF0000 >> 16, return fmt.Sprintf("%d.%d.%d.%d", ipv4int & 0xFF000000 >> 24, ipv4int & 0x00FF0000 >> 16,
@ -460,8 +514,11 @@ func (h *Header32) LoadFromBinary(file *os.File) error {
*/ */
func (h *Header32) Print(file *os.File, delimiter string, flags int) { func (h *Header32) Print(file *os.File, delimiter string, flags int) {
t := time.Unix((int64)(h.S), 0) t := time.Unix((int64)(h.S), 0)
fmt.Fprintf(file, "header%s%v%s%v%s%v%s%v%s%v%s%v", delimiter, h.Size, delimiter, h.Version, delimiter, // We dont care for error
h.E_type, delimiter, h.E_mod, delimiter, t.Format(time.UnixDate), delimiter, h.Msec) evdesc, _ := getEventName(h.E_type)
fmt.Fprintf(file, "header%s%v%s%v%s%s%s%v%s%v%s%v", delimiter, h.Size, delimiter, h.Version, delimiter,
//h.E_type, delimiter, h.E_mod, delimiter, t.Format(time.UnixDate), delimiter, h.Msec)
evdesc, delimiter, h.E_mod, delimiter, t.Format(time.UnixDate), delimiter, h.Msec)
if 0 == (flags & PRT_ONELINE) { if 0 == (flags & PRT_ONELINE) {
fmt.Fprintf(file, "\n") fmt.Fprintf(file, "\n")
} else { } else {
@ -750,22 +807,25 @@ func (s *Subject32) LoadFromBinary(file *os.File) error {
} }
func (s *Subject32) Print(file *os.File, delimiter string, flags int) { func (s *Subject32) Print(file *os.File, delimiter string, flags int) {
var auser string
var euser string var euser string
var egroup string var egroup string
var ruser string var ruser string
var rgroup string var rgroup string
if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER { if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER {
auser = string(s.Auid)
euser = string(s.Euid) euser = string(s.Euid)
egroup = string(s.Egid) egroup = string(s.Egid)
ruser = string(s.Ruid) ruser = string(s.Ruid)
rgroup = string(s.Rgid) rgroup = string(s.Rgid)
} else { } else {
auser, _ = getUserName(s.Auid)
euser, _ = getUserName(s.Euid) euser, _ = getUserName(s.Euid)
egroup, _ = getGroupName(s.Egid) egroup, _ = getGroupName(s.Egid)
ruser, _ = getUserName(s.Ruid) ruser, _ = getUserName(s.Ruid)
rgroup, _ = getGroupName(s.Rgid) rgroup, _ = getGroupName(s.Rgid)
} }
fmt.Fprintf(file, "subject%s%v%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, s.Auid, delimiter, euser, delimiter, egroup, fmt.Fprintf(file, "subject%s%s%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, auser, delimiter, euser, delimiter, egroup,
delimiter, ruser, delimiter, rgroup, delimiter, s.Sid, delimiter, s.Tid.Port, delimiter, s.Tid.IpVers, delimiter, ruser, delimiter, rgroup, delimiter, s.Sid, delimiter, s.Tid.Port, delimiter, s.Tid.IpVers,
delimiter, PrintIpv4FromInt(s.Tid.Addr)) delimiter, PrintIpv4FromInt(s.Tid.Addr))
if 0 == (flags & PRT_ONELINE) { if 0 == (flags & PRT_ONELINE) {
@ -818,22 +878,25 @@ func (p *Process32) LoadFromBinary(file *os.File) error {
} }
func (p *Process32) Print(file *os.File, delimiter string, flags int) { func (p *Process32) Print(file *os.File, delimiter string, flags int) {
var auser string
var euser string var euser string
var egroup string var egroup string
var ruser string var ruser string
var rgroup string var rgroup string
if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER { if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER {
auser = string(p.Auid)
euser = string(p.Euid) euser = string(p.Euid)
egroup = string(p.Egid) egroup = string(p.Egid)
ruser = string(p.Ruid) ruser = string(p.Ruid)
rgroup = string(p.Rgid) rgroup = string(p.Rgid)
} else { } else {
auser, _ = getUserName(p.Auid)
euser, _ = getUserName(p.Euid) euser, _ = getUserName(p.Euid)
egroup, _ = getGroupName(p.Egid) egroup, _ = getGroupName(p.Egid)
ruser, _ = getUserName(p.Ruid) ruser, _ = getUserName(p.Ruid)
rgroup, _ = getGroupName(p.Rgid) rgroup, _ = getGroupName(p.Rgid)
} }
fmt.Fprintf(file, "process%s%v%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, p.Auid, delimiter, euser, delimiter, egroup, fmt.Fprintf(file, "process%s%s%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, auser, delimiter, euser, delimiter, egroup,
delimiter, ruser, delimiter, rgroup, delimiter, p.Sid, delimiter, p.Tid.Port, delimiter, p.Tid.IpVers, delimiter, ruser, delimiter, rgroup, delimiter, p.Sid, delimiter, p.Tid.Port, delimiter, p.Tid.IpVers,
delimiter, PrintIpv4FromInt(p.Tid.Addr)) delimiter, PrintIpv4FromInt(p.Tid.Addr))
if 0 == (flags & PRT_ONELINE) { if 0 == (flags & PRT_ONELINE) {
@ -901,17 +964,20 @@ func (s *Subject32Ex) LoadFromBinary(file *os.File) error {
} }
func (s *Subject32Ex) Print(file *os.File, delimiter string, flags int) { func (s *Subject32Ex) Print(file *os.File, delimiter string, flags int) {
var auser string
var euser string var euser string
var egroup string var egroup string
var ruser string var ruser string
var rgroup string var rgroup string
var ip string var ip string
if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER { if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER {
auser = string(s.Auid)
euser = string(s.Euid) euser = string(s.Euid)
egroup = string(s.Egid) egroup = string(s.Egid)
ruser = string(s.Ruid) ruser = string(s.Ruid)
rgroup = string(s.Rgid) rgroup = string(s.Rgid)
} else { } else {
auser, _ = getUserName(s.Auid)
euser, _ = getUserName(s.Euid) euser, _ = getUserName(s.Euid)
egroup, _ = getGroupName(s.Egid) egroup, _ = getGroupName(s.Egid)
ruser, _ = getUserName(s.Ruid) ruser, _ = getUserName(s.Ruid)
@ -922,7 +988,7 @@ func (s *Subject32Ex) Print(file *os.File, delimiter string, flags int) {
} else { } else {
ip = PrintIpv6FromInt(s.Tid.Addr6) ip = PrintIpv6FromInt(s.Tid.Addr6)
} }
fmt.Fprintf(file, "subject_ex%s%v%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, s.Auid, delimiter, euser, fmt.Fprintf(file, "subject_ex%s%s%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, auser, delimiter, euser,
delimiter, egroup, delimiter, ruser, delimiter, rgroup, delimiter, s.Sid, delimiter, s.Tid.Port, delimiter, delimiter, egroup, delimiter, ruser, delimiter, rgroup, delimiter, s.Sid, delimiter, s.Tid.Port, delimiter,
s.Tid.Ttype, delimiter, ip) s.Tid.Ttype, delimiter, ip)
@ -991,17 +1057,20 @@ func (p *Process32Ex) LoadFromBinary(file *os.File) error {
} }
func (p *Process32Ex) Print(file *os.File, delimiter string, flags int) { func (p *Process32Ex) Print(file *os.File, delimiter string, flags int) {
var auser string
var euser string var euser string
var egroup string var egroup string
var ruser string var ruser string
var rgroup string var rgroup string
var ip string var ip string
if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER { if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER {
auser = string(p.Auid)
euser = string(p.Euid) euser = string(p.Euid)
egroup = string(p.Egid) egroup = string(p.Egid)
ruser = string(p.Ruid) ruser = string(p.Ruid)
rgroup = string(p.Rgid) rgroup = string(p.Rgid)
} else { } else {
auser, _ = getUserName(p.Auid)
euser, _ = getUserName(p.Euid) euser, _ = getUserName(p.Euid)
egroup, _ = getGroupName(p.Egid) egroup, _ = getGroupName(p.Egid)
ruser, _ = getUserName(p.Ruid) ruser, _ = getUserName(p.Ruid)
@ -1014,7 +1083,7 @@ func (p *Process32Ex) Print(file *os.File, delimiter string, flags int) {
ip = PrintIpv6FromInt(p.Tid.Addr6) ip = PrintIpv6FromInt(p.Tid.Addr6)
} }
fmt.Fprintf(file, "process_ex%s%v%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, p.Auid, delimiter, euser, fmt.Fprintf(file, "process_ex%s%s%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, auser, delimiter, euser,
delimiter, egroup, delimiter, ruser, delimiter, rgroup, delimiter, p.Sid, delimiter, p.Tid.Port, delimiter, delimiter, egroup, delimiter, ruser, delimiter, rgroup, delimiter, p.Sid, delimiter, p.Tid.Port, delimiter,
p.Tid.Ttype, delimiter, ip) p.Tid.Ttype, delimiter, ip)
@ -1068,22 +1137,25 @@ func (s *Subject64) LoadFromBinary(file *os.File) error {
} }
func (s *Subject64) Print(file *os.File, delimiter string, flags int) { func (s *Subject64) Print(file *os.File, delimiter string, flags int) {
var auser string
var euser string var euser string
var egroup string var egroup string
var ruser string var ruser string
var rgroup string var rgroup string
if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER { if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER {
auser = string(s.Auid)
euser = string(s.Euid) euser = string(s.Euid)
egroup = string(s.Egid) egroup = string(s.Egid)
ruser = string(s.Ruid) ruser = string(s.Ruid)
rgroup = string(s.Rgid) rgroup = string(s.Rgid)
} else { } else {
auser, _ = getUserName(s.Auid)
euser, _ = getUserName(s.Euid) euser, _ = getUserName(s.Euid)
egroup, _ = getGroupName(s.Egid) egroup, _ = getGroupName(s.Egid)
ruser, _ = getUserName(s.Ruid) ruser, _ = getUserName(s.Ruid)
rgroup, _ = getGroupName(s.Rgid) rgroup, _ = getGroupName(s.Rgid)
} }
fmt.Fprintf(file, "subject%s%v%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, s.Auid, delimiter, euser, delimiter, egroup, fmt.Fprintf(file, "subject%s%s%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, auser, delimiter, euser, delimiter, egroup,
delimiter, ruser, delimiter, rgroup, delimiter, s.Sid, delimiter, s.Tid.Port, delimiter, s.Tid.IpVers, delimiter, ruser, delimiter, rgroup, delimiter, s.Sid, delimiter, s.Tid.Port, delimiter, s.Tid.IpVers,
delimiter, PrintIpv4FromInt(s.Tid.Addr)) delimiter, PrintIpv4FromInt(s.Tid.Addr))
if 0 == (flags & PRT_ONELINE) { if 0 == (flags & PRT_ONELINE) {
@ -1136,22 +1208,25 @@ func (p *Process64) LoadFromBinary(file *os.File) error {
} }
func (p *Process64) Print(file *os.File, delimiter string, flags int) { func (p *Process64) Print(file *os.File, delimiter string, flags int) {
var auser string
var euser string var euser string
var egroup string var egroup string
var ruser string var ruser string
var rgroup string var rgroup string
if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER { if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER {
auser = string(p.Auid)
euser = string(p.Euid) euser = string(p.Euid)
egroup = string(p.Egid) egroup = string(p.Egid)
ruser = string(p.Ruid) ruser = string(p.Ruid)
rgroup = string(p.Rgid) rgroup = string(p.Rgid)
} else { } else {
auser, _ = getUserName(p.Auid)
euser, _ = getUserName(p.Euid) euser, _ = getUserName(p.Euid)
egroup, _ = getGroupName(p.Egid) egroup, _ = getGroupName(p.Egid)
ruser, _ = getUserName(p.Ruid) ruser, _ = getUserName(p.Ruid)
rgroup, _ = getGroupName(p.Rgid) rgroup, _ = getGroupName(p.Rgid)
} }
fmt.Fprintf(file, "process%s%v%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, p.Auid, delimiter, euser, delimiter, egroup, fmt.Fprintf(file, "process%s%s%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, auser, delimiter, euser, delimiter, egroup,
delimiter, ruser, delimiter, rgroup, delimiter, p.Sid, delimiter, p.Tid.Port, delimiter, p.Tid.IpVers, delimiter, ruser, delimiter, rgroup, delimiter, p.Sid, delimiter, p.Tid.Port, delimiter, p.Tid.IpVers,
delimiter, PrintIpv4FromInt(p.Tid.Addr)) delimiter, PrintIpv4FromInt(p.Tid.Addr))
if 0 == (flags & PRT_ONELINE) { if 0 == (flags & PRT_ONELINE) {
@ -1218,17 +1293,20 @@ func (s *Subject64Ex) LoadFromBinary(file *os.File) error {
} }
func (s *Subject64Ex) Print(file *os.File, delimiter string, flags int) { func (s *Subject64Ex) Print(file *os.File, delimiter string, flags int) {
var auser string
var euser string var euser string
var egroup string var egroup string
var ruser string var ruser string
var rgroup string var rgroup string
var ip string var ip string
if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER { if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER {
auser = string(s.Auid)
euser = string(s.Euid) euser = string(s.Euid)
egroup = string(s.Egid) egroup = string(s.Egid)
ruser = string(s.Ruid) ruser = string(s.Ruid)
rgroup = string(s.Rgid) rgroup = string(s.Rgid)
} else { } else {
auser, _ = getUserName(s.Auid)
euser, _ = getUserName(s.Euid) euser, _ = getUserName(s.Euid)
egroup, _ = getGroupName(s.Egid) egroup, _ = getGroupName(s.Egid)
ruser, _ = getUserName(s.Ruid) ruser, _ = getUserName(s.Ruid)
@ -1240,7 +1318,7 @@ func (s *Subject64Ex) Print(file *os.File, delimiter string, flags int) {
ip = PrintIpv6FromInt(s.Tid.Addr6) ip = PrintIpv6FromInt(s.Tid.Addr6)
} }
fmt.Fprintf(file, "subject_ex%s%v%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, s.Auid, delimiter, euser, fmt.Fprintf(file, "subject_ex%s%s%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, auser, delimiter, euser,
delimiter, egroup, delimiter, ruser, delimiter, rgroup, delimiter, s.Sid, delimiter, s.Tid.Port, delimiter, delimiter, egroup, delimiter, ruser, delimiter, rgroup, delimiter, s.Sid, delimiter, s.Tid.Port, delimiter,
s.Tid.Ttype, delimiter, ip) s.Tid.Ttype, delimiter, ip)
@ -1308,17 +1386,20 @@ func (p *Process64Ex) LoadFromBinary(file *os.File) error {
} }
func (p *Process64Ex) Print(file *os.File, delimiter string, flags int) { func (p *Process64Ex) Print(file *os.File, delimiter string, flags int) {
var auser string
var euser string var euser string
var egroup string var egroup string
var ruser string var ruser string
var rgroup string var rgroup string
var ip string var ip string
if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER { if PRT_NORESOLVE_USER == flags & PRT_NORESOLVE_USER {
auser = string(p.Auid)
euser = string(p.Euid) euser = string(p.Euid)
egroup = string(p.Egid) egroup = string(p.Egid)
ruser = string(p.Ruid) ruser = string(p.Ruid)
rgroup = string(p.Rgid) rgroup = string(p.Rgid)
} else { } else {
auser, _ = getUserName(p.Auid)
euser, _ = getUserName(p.Euid) euser, _ = getUserName(p.Euid)
egroup, _ = getGroupName(p.Egid) egroup, _ = getGroupName(p.Egid)
ruser, _ = getUserName(p.Ruid) ruser, _ = getUserName(p.Ruid)
@ -1330,7 +1411,7 @@ func (p *Process64Ex) Print(file *os.File, delimiter string, flags int) {
ip = PrintIpv6FromInt(p.Tid.Addr6) ip = PrintIpv6FromInt(p.Tid.Addr6)
} }
fmt.Fprintf(file, "process_ex%s%v%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, p.Auid, delimiter, euser, fmt.Fprintf(file, "process_ex%s%s%s%s%s%s%s%s%s%s%s%v%s%v%s%v%s%s", delimiter, auser, delimiter, euser,
delimiter, egroup, delimiter, ruser, delimiter, rgroup, delimiter, p.Sid, delimiter, p.Tid.Port, delimiter, delimiter, egroup, delimiter, ruser, delimiter, rgroup, delimiter, p.Sid, delimiter, p.Tid.Port, delimiter,
p.Tid.Ttype, delimiter, ip) p.Tid.Ttype, delimiter, ip)

86
main.go
View File

@ -4,27 +4,26 @@
// godit is a search tool for BSM audit trails used by FreeBSD auditd // godit is a search tool for BSM audit trails used by FreeBSD auditd
// //
package main
/* /*
#cgo CFLAGS: -I /usr/lib % time ./godit 20211228134923.20211228151348 > godit.log
#cgo LDFLAGS: -L. -lbsm -lc 11.599u 38.235s 0:48.25 103.2% 1045+553k 1+2262168io 4pf+0w
#include <stdlib.h> % time praudit -l /home/yo/Dev/go/godit/20211228134923.20211228151348 > praudit.log
#include <bsm/libbsm.h> 101.728u 7.315s 1:49.09 99.9% 10+167k 0+191152io 0pf+0w
% ./godit -V
Godit v0.03
*/ */
import "C"
import "unsafe" package main
import ( import (
"io" "io"
"os" "os"
"fmt" "fmt"
// "encoding/hex"
"github.com/spf13/pflag" "github.com/spf13/pflag"
) )
const ( const (
version = "0.02" version = "0.03"
) )
var ( var (
@ -36,73 +35,6 @@ var (
) )
/*
// 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() { func main() {
var flags int var flags int
var oneLine bool var oneLine bool