diff --git a/libbsm.go b/libbsm.go index 0475c21..cd3e818 100644 --- a/libbsm.go +++ b/libbsm.go @@ -4,6 +4,9 @@ //go:build freebsd // +build freebsd +// +// update 23/01/2023 +// // // Use libc to get pw name from uid @@ -21,15 +24,16 @@ package main import "C" import ( - "bufio" - "bytes" - "encoding/binary" - "fmt" "io" "os" + "fmt" + "time" + "bufio" + "bytes" "strconv" "strings" - "time" + "encoding/binary" + "encoding/json" ) const ( @@ -124,6 +128,7 @@ const ( PRT_ONELINE = 1 PRT_NORESOLVE_USER = 2 PRT_TIMESTAMP = 4 + PRT_JSON = 8 ) var ( @@ -153,60 +158,60 @@ type Record interface { } type Header32 struct { - Size uint32 // Record byte count - Version uint8 // version # (uchar) - E_type uint16 // Event type - E_mod uint16 // Event modifier - S uint32 // Seconds of time - Msec uint32 // Milliseconds of time + Size uint32 `json:"size"` // Record byte count + Version uint8 `json:"version"` // version # (uchar) + E_type uint16 `json:"event_type"` // Event type + E_mod uint16 `json:"event_modifier"` // Event modifier + S uint32 `json:"timestamp"` // Seconds of time + Msec uint32 `json:"msec"` // Milliseconds of time } type Header32Ex struct { - Size uint32 // Record byte count - Version uint8 // version # (uchar) - E_type uint16 // Event type - E_mod uint16 // Event modifier - Ad_type uint32 // Address type/Length - Addr [4]uint32 // Ipv4 or IPv6 - S uint32 // Seconds of time - Msec uint32 // Milliseconds of time + Size uint32 `json:"size"` // Record byte count + Version uint8 `json:"version"` // version # (uchar) + E_type uint16 `json:"event_type"` // Event type + E_mod uint16 `json:"event_modifier"` // Event modifier + Ad_type uint32 `json:"address_type"` // Address type/Length + Addr [4]uint32 `json:"address"` // Ipv4 or IPv6 + S uint32 `json:"timestamp"` // Seconds of time + Msec uint32 `json:"msec"` // Milliseconds of time } type Trailer struct { - Magic uint16 - Count uint32 + Magic uint16 `json:"magic"` + Count uint32 `json:"size"` } type Arg32 struct { - No byte // Argument # - Val uint32 // Argument value - Length uint16 // Text length - Text []byte // Text + No byte `json:"count"` // Argument # + Val uint32 `json:"value"` // Argument value + Length uint16 `json:"length"` // Text length + Text []byte `json:"text"` // Text } type Arg64 struct { - No byte // Argument # - Val uint64 // Argument value - Length uint16 // Text length - Text []byte // Text + No byte `json:"count"` // Argument # + Val uint64 `json:"value"` // Argument value + Length uint16 `json:"length"` // Text length + Text []byte `json:"text"` // Text } type Attribute32 struct { - Mode uint32 // file access mode - Uid uint32 // Owner user ID - Gid uint32 // Owner group ID - Fsid uint32 // File system ID - Nid uint64 // Node ID - Dev uint32 // Device + Mode uint32 `json:"mode"` // file access mode + Uid uint32 `json:"user_id"` // Owner user ID + Gid uint32 `json:"group_id"` // Owner group ID + Fsid uint32 `json:"filesystem_id"` // File system ID + Nid uint64 `json:"node_id"` // Node ID + Dev uint32 `json:"device"` // Device } type Attribute64 struct { - Mode uint32 // file access mode - Uid uint32 // Owner user ID - Gid uint32 // Owner group ID - Fsid uint32 // File system ID - Nid uint64 // Node ID - Dev uint64 // Device + Mode uint32 `json:"mode"` // file access mode + Uid uint32 `json:"user_id"` // Owner user ID + Gid uint32 `json:"group_id"` // Owner group ID + Fsid uint32 `json:"filesystem_id"` // File system ID + Nid uint64 `json:"node_id"` // Node ID + Dev uint64 `json:"device"` // Device } /* @@ -214,104 +219,100 @@ type Attribute64 struct { * text count null-terminated string(s) */ type ExecArg struct { - Count uint32 - //Text [AUDIT_MAX_ARGS][]byte - Text [][]byte + Count uint32 `json:"count"` + //Text [AUDIT_MAX_ARGS][]byte + Text [][]byte `json:"text"` } type Path struct { - Length uint16 // path length - Path []byte + Length uint16 `json:"length"` // path length + Path []byte `json:"path"` } type Return32 struct { - Status byte // Error status - Ret uint32 // Return code + Status byte `json:"status"` // Error status + Ret uint32 `json:"code"` // Return code } type Return64 struct { - Status byte // Error status - Ret uint64 // Return code + Status byte `json:"status"` // Error status + Ret uint64 `json:"code"` // Return code } type Subject32 struct { - Auid uint32 // Audit ID - Euid uint32 // Effective user ID - Egid uint32 // Effective Group ID - Ruid uint32 // Real User ID - Rgid uint32 // Real Group ID - Pid uint32 // Process ID - Sid uint32 // Session ID - Tid Tid32 + Auid uint32 `json:"audit_id"` // Audit ID + Euid uint32 `json:"effective_user_id"` // Effective user ID + Egid uint32 `json:"effective_group_id"` // Effective Group ID + Ruid uint32 `json:"real_user_id"` // Real User ID + Rgid uint32 `json:"real_group_id"` // Real Group ID + Pid uint32 `json:"process_id"` // Process ID + Sid uint32 `json:"session_id"` // Session ID + Tid Tid32 `json:"terminal_id"` } type Process32 Subject32 type Subject32Ex struct { - Auid uint32 // Audit ID - Euid uint32 // Effective user ID - Egid uint32 // Effective Group ID - Ruid uint32 // Real User ID - Rgid uint32 // Real Group ID - Pid uint32 // Process ID - Sid uint32 // Session ID - Tid Tid32Ex + Auid uint32 `json:"audit_id"` // Audit ID + Euid uint32 `json:"effective_user_id"` // Effective user ID + Egid uint32 `json:"effective_group_id"` // Effective Group ID + Ruid uint32 `json:"real_user_id"` // Real User ID + Rgid uint32 `json:"real_group_id"` // Real Group ID + Pid uint32 `json:"process_id"` // Process ID + Sid uint32 `json:"session_id"` // Session ID + Tid Tid32Ex `json:"terminal_id_ex"` } type Process32Ex Subject32Ex type Tid32 struct { - Port uint32 - IpVers uint32 // 0x10 = IPv6 - Addr uint32 + Port uint32 `json:"port"` + Addr uint32 `json:"ip4"` } type Tid32Ex struct { - Port uint32 - Ttype uint32 - IpVers uint32 // 0x10 = IPv6, 0x04 = IPv4 - Addr4 uint32 // 4 bytes long if IpVers == 0x04 - Addr6 [4]uint32 // 4x4 bytes long if IpVers == 0x10 + Port uint32 `json:"port"` + IpVers uint32 `json:"ip_version"` // 0x10 = IPv6, 0x04 = IPv4 + Addr4 uint32 `json:"ip4,omitempty"` // 4 bytes long if IpVers == 0x04 + Addr6 [4]uint32 `json:"ip6,omitempty"` // 4x4 bytes long if IpVers == 0x10 } type Subject64 struct { - Auid uint32 // Audit ID - Euid uint32 // Effective user ID - Egid uint32 // Effective Group ID - Ruid uint32 // Real User ID - Rgid uint32 // Real Group ID - Pid uint32 // Process ID - Sid uint32 // Session ID - Tid Tid64 + Auid uint32 `json:"audit_id"` // Audit ID + Euid uint32 `json:"effective_user_id"` // Effective user ID + Egid uint32 `json:"effective_group_id"` // Effective Group ID + Ruid uint32 `json:"real_user_id"` // Real User ID + Rgid uint32 `json:"real_group_id"` // Real Group ID + Pid uint32 `json:"process_id"` // Process ID + Sid uint32 `json:"session_id"` // Session ID + Tid Tid64 `json:"terminal_id"` } type Process64 Subject64 type Subject64Ex struct { - Auid uint32 // Audit ID - Euid uint32 // Effective user ID - Egid uint32 // Effective Group ID - Ruid uint32 // Real User ID - Rgid uint32 // Real Group ID - Pid uint32 // Process ID - Sid uint32 // Session ID - Tid Tid64Ex + Auid uint32 `json:"audit_id"` // Audit ID + Euid uint32 `json:"effective_user_id"` // Effective user ID + Egid uint32 `json:"effective_group_id"` // Effective Group ID + Ruid uint32 `json:"real_user_id"` // Real User ID + Rgid uint32 `json:"real_group_id"` // Real Group ID + Pid uint32 `json:"process_id"` // Process ID + Sid uint32 `json:"session_id"` // Session ID + Tid Tid64Ex `json:"terminal_id_ex"` } type Process64Ex Subject64Ex type Tid64 struct { - Port uint64 - IpVers uint32 - Addr uint32 + Port uint64 `json:"port"` + Addr uint32 `json:"ip4"` } type Tid64Ex struct { - Port uint64 - Ttype uint32 - IpVers uint32 // 0x10 = IPv6, 0x04 = IPv4 - Addr4 uint32 - Addr6 [4]uint32 + Port uint64 `json:"port"` + IpVers uint32 `json:"ip_version"` // 0x10 = IPv6, 0x04 = IPv4 + Addr4 uint32 `json:"ip4,omitempty"` + Addr6 [4]uint32 `json:"ip6,omitempty"` } /* @@ -324,27 +325,27 @@ type Tid64Ex struct { * remote Internet address 4/16 bytes */ type SocketEx struct { - Domain uint16 - SockType uint16 - AddrType uint16 - LocalPort uint16 - LocalAddr4 uint32 - LocalAddr6 [4]uint32 - RemotePort uint16 - RemoteAddr4 uint32 - RemoteAddr6 [4]uint32 + Domain uint16 `json:"domain"` + SockType uint16 `json:"type"` + AddrType uint16 `json:"ip_version"` + LocalPort uint16 `json:"local_port"` + LocalAddr4 uint32 `json:"local_ip4",omitempty` + LocalAddr6 [4]uint32 `json:"local_ip6",omitempty` + RemotePort uint16 `json:"remote_port"` + RemoteAddr4 uint32 `json:"remote_ip4",omitempty` + RemoteAddr6 [4]uint32 `json:"remote_ip6",omitempty` } type SockInet32 struct { - Family uint16 - Lport uint16 - Addr4 uint32 + Family uint16 `json:"family"` + Port uint16 `json:"port"` + Addr4 uint32 `json:"ip4"` } type SockInet128 struct { - Family uint16 - Lport uint16 - Addr6 [4]uint32 + Family uint16 `json:"family"` + Port uint16 `json:"port"` + Addr6 [4]uint32 `json:"ip6"` } /* @@ -358,13 +359,13 @@ type SockUnix struct { } type Exit struct { - Status uint32 - Ret uint32 + Status uint32 `json:"status"` + Ret uint32 `json:"code"` } type Text struct { - Length uint16 - Text []byte + Length uint16 `json:"length"` + Text []byte `json:"text"` } /* Utilities */ @@ -599,13 +600,43 @@ func (h *Header32) Print(file *os.File, delimiter string, flags int) { fmt.Printf("%v\n", err) return } - fmt.Fprintf(file, "header%s%d%s%d%s%s%s%v%s%s%s%d", 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, timeval, delimiter, h.Msec) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + + if flags&PRT_JSON == PRT_JSON { + 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 data/hour/DST + Msec uint32 `json:"msec"` // Milliseconds of time + }{ + Size: h.Size, + Version: h.Version, + E_type: evdesc, + E_mod: h.E_mod, + Ts: timeval, + Msec: h.Msec, + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + // Header start the json object + fmt.Fprintf(file, "{\"header32\":") + fmt.Fprintf(file, "%s", j) + // and header is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + fmt.Fprintf(file, "header%s%d%s%d%s%s%s%v%s%s%s%d", 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, timeval, delimiter, h.Msec) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -639,18 +670,42 @@ func (e *ExecArg) LoadFromBinary(rdr *bufio.Reader) error { } func (e *ExecArg) Print(file *os.File, delimiter string, flags int) { - fmt.Fprintf(file, "exec arg%s", delimiter) - for i := uint32(0); i < e.Count; i++ { - if i < e.Count-1 { - fmt.Fprintf(file, "%s%s", string(e.Text[i]), delimiter) - } else { - fmt.Fprintf(file, "%s", string(e.Text[i])) + if flags&PRT_JSON == PRT_JSON { + // We don't need no count, bc we reconstiture command line + printable := struct { + Text string `json:"text"` + }{} + for i, b := range e.Text { + /*printable.Text = append(printable.Text, b...) + printable.Text = append(printable.Text, []byte(" ")...)*/ + printable.Text = fmt.Sprintf("%s%s", printable.Text, b) + if i < (len(e.Text) - 1) { + printable.Text += " " + } } - } - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"execarg\":") + fmt.Fprintf(file, "%s", j) + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + fmt.Fprintf(file, "exec arg%s", delimiter) + for i := uint32(0); i < e.Count; i++ { + if i < e.Count-1 { + fmt.Fprintf(file, "%s%s", string(e.Text[i]), delimiter) + } else { + fmt.Fprintf(file, "%s", string(e.Text[i])) + } + } + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -681,11 +736,30 @@ func (p *Path) LoadFromBinary(rdr *bufio.Reader) error { } func (p *Path) Print(file *os.File, delimiter string, flags int) { - fmt.Fprintf(file, "path%s%s", delimiter, string(p.Path)) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + if flags&PRT_JSON == PRT_JSON { + // We don't need no length + printable := struct { + Path string `json:"path"` + }{ + Path: fmt.Sprintf("%s", p.Path), + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"path\":") + fmt.Fprintf(file, "%s", j) + // path is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + fmt.Fprintf(file, "path%s%s", delimiter, string(p.Path)) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -750,13 +824,47 @@ func (a *Attribute32) Print(file *os.File, delimiter string, flags int) { group, _ = getGroupName(a.Gid) } - fmt.Fprintf(file, "attribute%s%o%s%s%s%s%s%v%s%v%s%v", delimiter, a.Mode, delimiter, user, delimiter, - group, delimiter, a.Fsid, delimiter, a.Nid, delimiter, a.Dev) + if flags&PRT_JSON == PRT_JSON { + printable := struct { + Mode uint32 `json:"mode"` // file access mode + Uid uint32 `json:"user_id",omitempty` // Owner user ID + User string `json:"username",omitempty` // Owner username + Gid uint32 `json:"group_id",omitempty` // Owner group ID + Group string `json:"group",omitempty` // Owner group name + Fsid uint32 `json:"filesystem_id"` // File system ID + Nid uint64 `json:"node_id"` // Node ID + Dev uint32 `json:"device"` // Device + }{ + Mode: a.Mode, + Uid: a.Uid, + Gid: a.Gid, + Fsid: a.Fsid, + Nid: a.Nid, + Dev: a.Dev, + } + if PRT_NORESOLVE_USER != flags&PRT_NORESOLVE_USER { + printable.User = fmt.Sprintf("%s", user) + printable.Group = fmt.Sprintf("%s", group) + } - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"attribute32\":") + fmt.Fprintf(file, "%s", j) + // attribute32 is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + fmt.Fprintf(file, "attribute%s%o%s%s%s%s%s%v%s%v%s%v", delimiter, a.Mode, delimiter, user, delimiter, + group, delimiter, a.Fsid, delimiter, a.Nid, delimiter, a.Dev) + + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -820,12 +928,47 @@ func (a *Attribute64) Print(file *os.File, delimiter string, flags int) { user, _ = getUserName(a.Uid) group, _ = getGroupName(a.Gid) } - fmt.Fprintf(file, "attribute%s%o%s%v%s%v%s%v%s%v%s%v", delimiter, a.Mode, delimiter, user, delimiter, - group, delimiter, a.Fsid, delimiter, a.Nid, delimiter, a.Dev) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + + if flags&PRT_JSON == PRT_JSON { + printable := struct { + Mode uint32 `json:"mode"` // file access mode + Uid uint32 `json:"user_id",omitempty` // Owner user ID + User string `json:"username",omitempty` // Owner username + Gid uint32 `json:"group_id",omitempty` // Owner group ID + Group string `json:"group",omitempty` // Owner group name + Fsid uint32 `json:"filesystem_id"` // File system ID + Nid uint64 `json:"node_id"` // Node ID + Dev uint64 `json:"device"` // Device + }{ + Mode: a.Mode, + Uid: a.Uid, + Gid: a.Gid, + Fsid: a.Fsid, + Nid: a.Nid, + Dev: a.Dev, + } + if PRT_NORESOLVE_USER != flags&PRT_NORESOLVE_USER { + printable.User = fmt.Sprintf("%s", user) + printable.Group = fmt.Sprintf("%s", group) + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"attribute64\":") + fmt.Fprintf(file, "%s", j) + // attribute64 is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + fmt.Fprintf(file, "attribute%s%o%s%v%s%v%s%v%s%v%s%v", delimiter, a.Mode, delimiter, user, delimiter, + group, delimiter, a.Fsid, delimiter, a.Nid, delimiter, a.Dev) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -847,6 +990,20 @@ func (s *Subject32) GetType() uint8 { } func (s *Subject32) LoadFromBinary(rdr *bufio.Reader) error { + + /* + type Subject32 struct { + Auid uint32 `json:"audit_id"` // Audit ID + Euid uint32 `json:"effective_user_id"` // Effective user ID + Egid uint32 `json:"effective_group_id"` // Effective Group ID + Ruid uint32 `json:"real_user_id"` // Real User ID + Rgid uint32 `json:"real_group_id"` // Real Group ID + Pid uint32 `json:"process_id"` // Process ID + Sid uint32 `json:"session_id"` // Session ID + Tid Tid32 `json:"terminal_id"` + } + */ + err := binary.Read(rdr, binary.BigEndian, &s.Auid) if err != nil { return fmt.Errorf("Unable to read Sibject32.Auid: %v", err) @@ -872,6 +1029,11 @@ func (s *Subject32) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read Subject32.Rgid: %v", err) } + err = binary.Read(rdr, binary.BigEndian, &s.Pid) + if err != nil { + return fmt.Errorf("Unable to read Subject32.Pid: %v", err) + } + err = binary.Read(rdr, binary.BigEndian, &s.Sid) if err != nil { return fmt.Errorf("Unable to read Subject32.Sid: %v", err) @@ -879,7 +1041,7 @@ func (s *Subject32) LoadFromBinary(rdr *bufio.Reader) error { err = binary.Read(rdr, binary.BigEndian, &s.Tid) if err != nil { - return fmt.Errorf("Unable to read Subject32.Tid: %v", err) + return fmt.Errorf("Unable to read Subject32.Tid.Port: %v", err) } return nil @@ -904,13 +1066,66 @@ func (s *Subject32) Print(file *os.File, delimiter string, flags int) { ruser, _ = getUserName(s.Ruid) rgroup, _ = getGroupName(s.Rgid) } - 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, PrintIpv4FromInt(s.Tid.Addr)) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + + if flags&PRT_JSON == PRT_JSON { + type ttid struct { + Port uint32 `json:"port"` + Addr string `json:"ip4"` + } + tid := ttid{ + Port: s.Tid.Port, + Addr: PrintIpv4FromInt(s.Tid.Addr), + } + printable := struct { + Auid uint32 `json:"audit_id"` // Audit ID + Auser string `json:"audit_username",omitempty` + Euid uint32 `json:"effective_user_id"` // Effective user ID + Euser string `json:"effective_username",omitempty` + Egid uint32 `json:"effective_group_id"` // Effective Group ID + Egroup string `json:"effective_group",omitempty` + Ruid uint32 `json:"real_user_id"` // Real User ID + Ruser string `json:"real_username",omitempty` + Rgid uint32 `json:"real_group_id"` // Real Group ID + Rgroup string `json:"real_group",omitempty` + Pid uint32 `json:"process_id"` // Process ID + Sid uint32 `json:"session_id"` // Session ID + Tid ttid `json:"terminal"` + }{ + Auid: s.Auid, + Euid: s.Euid, + Egid: s.Egid, + Ruid: s.Ruid, + Rgid: s.Rgid, + Pid: s.Pid, + Sid: s.Sid, + Tid: tid, + } + if PRT_NORESOLVE_USER != flags&PRT_NORESOLVE_USER { + printable.Auser = auser + printable.Euser = euser + printable.Egroup = egroup + printable.Ruser = ruser + printable.Rgroup = rgroup + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"subject32\":") + fmt.Fprintf(file, "%s", j) + // subject32 is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + 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.Pid, delimiter, s.Sid, delimiter, s.Tid.Port, + delimiter, PrintIpv4FromInt(s.Tid.Addr)) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -957,6 +1172,11 @@ func (p *Process32) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read Process32.Rgid: %v", err) } + err = binary.Read(rdr, binary.BigEndian, &p.Pid) + if err != nil { + return fmt.Errorf("Unable to read Process32.Pid: %v", err) + } + err = binary.Read(rdr, binary.BigEndian, &p.Sid) if err != nil { return fmt.Errorf("Unable to read Process32.Sid: %v", err) @@ -989,13 +1209,66 @@ func (p *Process32) Print(file *os.File, delimiter string, flags int) { ruser, _ = getUserName(p.Ruid) rgroup, _ = getGroupName(p.Rgid) } - 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, PrintIpv4FromInt(p.Tid.Addr)) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + + if flags&PRT_JSON == PRT_JSON { + type ttid struct { + Port uint32 `json:"port"` + Addr string `json:"ip"` + } + tid := ttid{ + Port: p.Tid.Port, + Addr: PrintIpv4FromInt(p.Tid.Addr), + } + printable := struct { + Auid uint32 `json:"audit_id"` // Audit ID + Auser string `json:"audit_username",omitempty` + Euid uint32 `json:"effective_user_id"` // Effective user ID + Euser string `json:"effective_username",omitempty` + Egid uint32 `json:"effective_group_id"` // Effective Group ID + Egroup string `json:"effective_group",omitempty` + Ruid uint32 `json:"real_user_id"` // Real User ID + Ruser string `json:"real_username",omitempty` + Rgid uint32 `json:"real_group_id"` // Real Group ID + Rgroup string `json:"real_group",omitempty` + Pid uint32 `json:"process_id"` // Process ID + Sid uint32 `json:"session_id"` // Session ID + Tid ttid `json:"terminal"` + }{ + Auid: p.Auid, + Euid: p.Euid, + Egid: p.Egid, + Ruid: p.Ruid, + Rgid: p.Rgid, + Pid: p.Pid, + Sid: p.Sid, + Tid: tid, + } + if PRT_NORESOLVE_USER != flags&PRT_NORESOLVE_USER { + printable.Auser = auser + printable.Euser = euser + printable.Egroup = egroup + printable.Ruser = ruser + printable.Rgroup = rgroup + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"process32\":") + fmt.Fprintf(file, "%s", j) + // process32 is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + 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.Pid, delimiter, p.Sid, delimiter, p.Tid.Port, + delimiter, PrintIpv4FromInt(p.Tid.Addr)) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -1043,6 +1316,11 @@ func (s *Subject32Ex) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read Subject32Ex.Rgid: %v", err) } + err = binary.Read(rdr, binary.BigEndian, &s.Pid) + if err != nil { + return fmt.Errorf("Unable to read Subject32Ex.Pid: %v", err) + } + err = binary.Read(rdr, binary.BigEndian, &s.Sid) if err != nil { return fmt.Errorf("Unable to read Subject32Ex.Sid: %v", err) @@ -1053,11 +1331,6 @@ func (s *Subject32Ex) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read Subject32Ex.Tid.Port: %v", err) } - err = binary.Read(rdr, binary.BigEndian, &s.Tid.Ttype) - if err != nil { - return fmt.Errorf("Unable to read Subject32Ex.Tid.Ttype: %v", err) - } - err = binary.Read(rdr, binary.BigEndian, &s.Tid.IpVers) if err != nil { return fmt.Errorf("Unable to read Subject32Ex.Tid.IpVers: %v", err) @@ -1103,14 +1376,71 @@ func (s *Subject32Ex) Print(file *os.File, delimiter string, flags int) { } else { ip = PrintIpv6FromInt(s.Tid.Addr6) } - 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, - s.Tid.Ttype, delimiter, ip) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + if flags&PRT_JSON == PRT_JSON { + type ttid struct { + Port uint32 `json:"port"` + Addr4 string `json:"ip4,omitempty"` + Addr6 string `json:"ip6,omitempty"` + } + tid := ttid{ + Port: s.Tid.Port, + } + if s.Tid.IpVers == 0x04 { + tid.Addr4 = ip + } else { + tid.Addr6 = ip + } + printable := struct { + Auid uint32 `json:"audit_id"` // Audit ID + Auser string `json:"audit_username",omitempty` + Euid uint32 `json:"effective_user_id"` // Effective user ID + Euser string `json:"effective_username",omitempty` + Egid uint32 `json:"effective_group_id"` // Effective Group ID + Egroup string `json:"effective_group",omitempty` + Ruid uint32 `json:"real_user_id"` // Real User ID + Ruser string `json:"real_username",omitempty` + Rgid uint32 `json:"real_group_id"` // Real Group ID + Rgroup string `json:"real_group",omitempty` + Pid uint32 `json:"process_id"` // Process ID + Sid uint32 `json:"session_id"` // Session ID + Tid ttid `json:"terminal"` + }{ + Auid: s.Auid, + Euid: s.Euid, + Egid: s.Egid, + Ruid: s.Ruid, + Rgid: s.Rgid, + Pid: s.Pid, + Sid: s.Sid, + Tid: tid, + } + if PRT_NORESOLVE_USER != flags&PRT_NORESOLVE_USER { + printable.Auser = auser + printable.Euser = euser + printable.Egroup = egroup + printable.Ruser = ruser + printable.Rgroup = rgroup + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"subject32ex\":") + fmt.Fprintf(file, "%s", j) + // subject32ex is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + 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.Pid, delimiter, s.Sid, delimiter, + s.Tid.Port, delimiter, ip) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -1158,6 +1488,11 @@ func (p *Process32Ex) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read Process32Ex.Rgid: %v", err) } + err = binary.Read(rdr, binary.BigEndian, &p.Pid) + if err != nil { + return fmt.Errorf("Unable to read Process32Ex.Pid: %v", err) + } + err = binary.Read(rdr, binary.BigEndian, &p.Sid) if err != nil { return fmt.Errorf("Unable to read Process32Ex.Sid: %v", err) @@ -1168,11 +1503,6 @@ func (p *Process32Ex) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read Process32Ex.Tid.Port: %v", err) } - err = binary.Read(rdr, binary.BigEndian, &p.Tid.Ttype) - if err != nil { - return fmt.Errorf("Unable to read Process32Ex.Tid.Ttype: %v", err) - } - err = binary.Read(rdr, binary.BigEndian, &p.Tid.IpVers) if err != nil { return fmt.Errorf("Unable to read Process32Ex.Tid.IpVers: %v", err) @@ -1220,14 +1550,71 @@ func (p *Process32Ex) Print(file *os.File, delimiter string, flags int) { ip = PrintIpv6FromInt(p.Tid.Addr6) } - 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, - p.Tid.Ttype, delimiter, ip) + if flags&PRT_JSON == PRT_JSON { + type ttid struct { + Port uint32 `json:"port"` + Addr4 string `json:"ip4,omitempty"` + Addr6 string `json:"ip6,omitempty"` + } + tid := ttid{ + Port: p.Tid.Port, + } + if p.Tid.IpVers == 0x04 { + tid.Addr4 = ip + } else { + tid.Addr6 = ip + } + printable := struct { + Auid uint32 `json:"audit_id"` // Audit ID + Auser string `json:"audit_username",omitempty` + Euid uint32 `json:"effective_user_id"` // Effective user ID + Euser string `json:"effective_username",omitempty` + Egid uint32 `json:"effective_group_id"` // Effective Group ID + Egroup string `json:"effective_group",omitempty` + Ruid uint32 `json:"real_user_id"` // Real User ID + Ruser string `json:"real_username",omitempty` + Rgid uint32 `json:"real_group_id"` // Real Group ID + Rgroup string `json:"real_group",omitempty` + Pid uint32 `json:"process_id"` // Process ID + Sid uint32 `json:"session_id"` // Session ID + Tid ttid `json:"terminal"` + }{ + Auid: p.Auid, + Euid: p.Euid, + Egid: p.Egid, + Ruid: p.Ruid, + Rgid: p.Rgid, + Pid: p.Pid, + Sid: p.Sid, + Tid: tid, + } + if PRT_NORESOLVE_USER != flags&PRT_NORESOLVE_USER { + printable.Auser = auser + printable.Euser = euser + printable.Egroup = egroup + printable.Ruser = ruser + printable.Rgroup = rgroup + } - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"process32ex\":") + fmt.Fprintf(file, "%s", j) + // process32ex is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + 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.Pid, delimiter, p.Sid, delimiter, + p.Tid.Port, delimiter, ip) + + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -1274,6 +1661,11 @@ func (s *Subject64) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read Subject64.Rgid: %v", err) } + err = binary.Read(rdr, binary.BigEndian, &s.Pid) + if err != nil { + return fmt.Errorf("Unable to read Subject64.Pid: %v", err) + } + err = binary.Read(rdr, binary.BigEndian, &s.Sid) if err != nil { return fmt.Errorf("Unable to read Subject64.Sid: %v", err) @@ -1306,13 +1698,66 @@ func (s *Subject64) Print(file *os.File, delimiter string, flags int) { ruser, _ = getUserName(s.Ruid) rgroup, _ = getGroupName(s.Rgid) } - 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, PrintIpv4FromInt(s.Tid.Addr)) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + + if flags&PRT_JSON == PRT_JSON { + type ttid struct { + Port uint64 `json:"port"` + Addr string `json:"ip4"` + } + tid := ttid{ + Port: s.Tid.Port, + Addr: PrintIpv4FromInt(s.Tid.Addr), + } + printable := struct { + Auid uint32 `json:"audit_id"` // Audit ID + Auser string `json:"audit_username",omitempty` + Euid uint32 `json:"effective_user_id"` // Effective user ID + Euser string `json:"effective_username",omitempty` + Egid uint32 `json:"effective_group_id"` // Effective Group ID + Egroup string `json:"effective_group",omitempty` + Ruid uint32 `json:"real_user_id"` // Real User ID + Ruser string `json:"real_username",omitempty` + Rgid uint32 `json:"real_group_id"` // Real Group ID + Rgroup string `json:"real_group",omitempty` + Pid uint32 `json:"process_id"` // Process ID + Sid uint32 `json:"session_id"` // Session ID + Tid ttid `json:"terminal"` + }{ + Auid: s.Auid, + Euid: s.Euid, + Egid: s.Egid, + Ruid: s.Ruid, + Rgid: s.Rgid, + Pid: s.Pid, + Sid: s.Sid, + Tid: tid, + } + if PRT_NORESOLVE_USER != flags&PRT_NORESOLVE_USER { + printable.Auser = auser + printable.Euser = euser + printable.Egroup = egroup + printable.Ruser = ruser + printable.Rgroup = rgroup + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"subject64\":") + fmt.Fprintf(file, "%s", j) + // subject64 is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + 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.Pid, delimiter, s.Sid, delimiter, s.Tid.Port, + delimiter, PrintIpv4FromInt(s.Tid.Addr)) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -1359,6 +1804,11 @@ func (p *Process64) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read Process64.Rgid: %v", err) } + err = binary.Read(rdr, binary.BigEndian, &p.Pid) + if err != nil { + return fmt.Errorf("Unable to read Process64.Pid: %v", err) + } + err = binary.Read(rdr, binary.BigEndian, &p.Sid) if err != nil { return fmt.Errorf("Unable to read Process64.Sid: %v", err) @@ -1391,13 +1841,66 @@ func (p *Process64) Print(file *os.File, delimiter string, flags int) { ruser, _ = getUserName(p.Ruid) rgroup, _ = getGroupName(p.Rgid) } - 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, PrintIpv4FromInt(p.Tid.Addr)) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + + if flags&PRT_JSON == PRT_JSON { + type ttid struct { + Port uint64 `json:"port"` + Addr string `json:"ip4"` + } + tid := ttid{ + Port: p.Tid.Port, + Addr: PrintIpv4FromInt(p.Tid.Addr), + } + printable := struct { + Auid uint32 `json:"audit_id"` // Audit ID + Auser string `json:"audit_username",omitempty` + Euid uint32 `json:"effective_user_id"` // Effective user ID + Euser string `json:"effective_username",omitempty` + Egid uint32 `json:"effective_group_id"` // Effective Group ID + Egroup string `json:"effective_group",omitempty` + Ruid uint32 `json:"real_user_id"` // Real User ID + Ruser string `json:"real_username",omitempty` + Rgid uint32 `json:"real_group_id"` // Real Group ID + Rgroup string `json:"real_group",omitempty` + Pid uint32 `json:"process_id"` // Process ID + Sid uint32 `json:"session_id"` // Session ID + Tid ttid `json:"terminal"` + }{ + Auid: p.Auid, + Euid: p.Euid, + Egid: p.Egid, + Ruid: p.Ruid, + Rgid: p.Rgid, + Pid: p.Pid, + Sid: p.Sid, + Tid: tid, + } + if PRT_NORESOLVE_USER != flags&PRT_NORESOLVE_USER { + printable.Auser = auser + printable.Euser = euser + printable.Egroup = egroup + printable.Ruser = ruser + printable.Rgroup = rgroup + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"process64\":") + fmt.Fprintf(file, "%s", j) + // process64 is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + 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.Pid, delimiter, p.Sid, delimiter, p.Tid.Port, + delimiter, PrintIpv4FromInt(p.Tid.Addr)) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -1444,6 +1947,11 @@ func (s *Subject64Ex) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read Subject64Ex.Rgid: %v", err) } + err = binary.Read(rdr, binary.BigEndian, &s.Pid) + if err != nil { + return fmt.Errorf("Unable to read Subject64Ex.Pid: %v", err) + } + err = binary.Read(rdr, binary.BigEndian, &s.Sid) if err != nil { return fmt.Errorf("Unable to read Subject64Ex.Sid: %v", err) @@ -1454,11 +1962,6 @@ func (s *Subject64Ex) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read Subject64Ex.Tid.Port: %v", err) } - err = binary.Read(rdr, binary.BigEndian, &s.Tid.Ttype) - if err != nil { - return fmt.Errorf("Unable to read Subject64Ex.Tid.Ttype: %v", err) - } - err = binary.Read(rdr, binary.BigEndian, &s.Tid.IpVers) if err != nil { return fmt.Errorf("Unable to read Subject64Ex.Tid.IpVers: %v", err) @@ -1505,14 +2008,71 @@ func (s *Subject64Ex) Print(file *os.File, delimiter string, flags int) { ip = PrintIpv6FromInt(s.Tid.Addr6) } - 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, - s.Tid.Ttype, delimiter, ip) + if flags&PRT_JSON == PRT_JSON { + type ttid struct { + Port uint64 `json:"port"` + Addr4 string `json:"ip4,omitempty"` + Addr6 string `json:"ip6,omitempty"` + } + tid := ttid{ + Port: s.Tid.Port, + } + if s.Tid.IpVers == ISIPV4 { + tid.Addr4 = ip + } else { + tid.Addr6 = ip + } + printable := struct { + Auid uint32 `json:"audit_id"` // Audit ID + Auser string `json:"audit_username",omitempty` + Euid uint32 `json:"effective_user_id"` // Effective user ID + Euser string `json:"effective_username",omitempty` + Egid uint32 `json:"effective_group_id"` // Effective Group ID + Egroup string `json:"effective_group",omitempty` + Ruid uint32 `json:"real_user_id"` // Real User ID + Ruser string `json:"real_username",omitempty` + Rgid uint32 `json:"real_group_id"` // Real Group ID + Rgroup string `json:"real_group",omitempty` + Pid uint32 `json:"process_id"` // Process ID + Sid uint32 `json:"session_id"` // Session ID + Tid ttid `json:"terminal"` + }{ + Auid: s.Auid, + Euid: s.Euid, + Egid: s.Egid, + Ruid: s.Ruid, + Rgid: s.Rgid, + Pid: s.Pid, + Sid: s.Sid, + Tid: tid, + } + if PRT_NORESOLVE_USER != flags&PRT_NORESOLVE_USER { + printable.Auser = auser + printable.Euser = euser + printable.Egroup = egroup + printable.Ruser = ruser + printable.Rgroup = rgroup + } - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"subject64\":") + fmt.Fprintf(file, "%s", j) + // subject64 is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + 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.Pid, delimiter, s.Sid, delimiter, + s.Tid.Port, delimiter, ip) + + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -1559,6 +2119,11 @@ func (p *Process64Ex) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read Process64Ex.Rgid: %v", err) } + err = binary.Read(rdr, binary.BigEndian, &p.Pid) + if err != nil { + return fmt.Errorf("Unable to read Process64Ex.Pid: %v", err) + } + err = binary.Read(rdr, binary.BigEndian, &p.Sid) if err != nil { return fmt.Errorf("Unable to read Process64Ex.Sid: %v", err) @@ -1569,11 +2134,6 @@ func (p *Process64Ex) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read Process64Ex.Tid.Port: %v", err) } - err = binary.Read(rdr, binary.BigEndian, &p.Tid.Ttype) - if err != nil { - return fmt.Errorf("Unable to read Process64Ex.Tid.Ttype: %v", err) - } - err = binary.Read(rdr, binary.BigEndian, &p.Tid.IpVers) if err != nil { return fmt.Errorf("Unable to read Process64Ex.Tid.IpVers: %v", err) @@ -1620,14 +2180,71 @@ func (p *Process64Ex) Print(file *os.File, delimiter string, flags int) { ip = PrintIpv6FromInt(p.Tid.Addr6) } - 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, - p.Tid.Ttype, delimiter, ip) + if flags&PRT_JSON == PRT_JSON { + type ttid struct { + Port uint64 `json:"port"` + Addr4 string `json:"ip4,omitempty"` + Addr6 string `json:"ip6,omitempty"` + } + tid := ttid{ + Port: p.Tid.Port, + } + if p.Tid.IpVers == 0x04 { + tid.Addr4 = ip + } else { + tid.Addr6 = ip + } + printable := struct { + Auid uint32 `json:"audit_id"` // Audit ID + Auser string `json:"audit_username",omitempty` + Euid uint32 `json:"effective_user_id"` // Effective user ID + Euser string `json:"effective_username",omitempty` + Egid uint32 `json:"effective_group_id"` // Effective Group ID + Egroup string `json:"effective_group",omitempty` + Ruid uint32 `json:"real_user_id"` // Real User ID + Ruser string `json:"real_username",omitempty` + Rgid uint32 `json:"real_group_id"` // Real Group ID + Rgroup string `json:"real_group",omitempty` + Pid uint32 `json:"process_id"` // Process ID + Sid uint32 `json:"session_id"` // Session ID + Tid ttid `json:"terminal"` + }{ + Auid: p.Auid, + Euid: p.Euid, + Egid: p.Egid, + Ruid: p.Ruid, + Rgid: p.Rgid, + Pid: p.Pid, + Sid: p.Sid, + Tid: tid, + } + if PRT_NORESOLVE_USER != flags&PRT_NORESOLVE_USER { + printable.Auser = auser + printable.Euser = euser + printable.Egroup = egroup + printable.Ruser = ruser + printable.Rgroup = rgroup + } - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"process64\":") + fmt.Fprintf(file, "%s", j) + // process64 is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + 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.Pid, delimiter, p.Sid, delimiter, + p.Tid.Port, delimiter, ip) + + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -1657,16 +2274,38 @@ func (r *Return32) LoadFromBinary(rdr *bufio.Reader) error { } func (r *Return32) Print(file *os.File, delimiter string, flags int) { + var errMsg string errNo, err := lookupErrno(r.Status) if err == nil { - fmt.Fprintf(file, "return%s%s%s%v", delimiter, errNo.StrError, delimiter, r.Ret) + errMsg = fmt.Sprintf("%s (%d)", errNo.StrError, r.Status) + } else { + errMsg = fmt.Sprintf("Godit error searching (%d)", r.Status) + } + if flags&PRT_JSON == PRT_JSON { + printable := struct { + Msg string `json:"error"` + Code uint32 `json:"retval"` // Effective user ID + }{ + Msg: errMsg, + Code: r.Ret, + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"return32\":") + fmt.Fprintf(file, "%s", j) + // return32 is always followed by something + fmt.Fprintf(file, ",") + } else { + fmt.Fprintf(file, "return%s%s%s%v", delimiter, errMsg, delimiter, r.Ret) if 0 == (flags & PRT_ONELINE) { fmt.Fprintf(file, "\n") } else { fmt.Fprintf(file, "%s", delimiter) } - } else { - fmt.Fprintf(file, "return%sgodit error: error code not found(%v)%s%s%v", delimiter, r.Status, delimiter, r.Ret) } } @@ -1696,11 +2335,38 @@ func (r *Return64) LoadFromBinary(rdr *bufio.Reader) error { } func (r *Return64) Print(file *os.File, delimiter string, flags int) { - fmt.Fprintf(file, "return%s%v%s%v", delimiter, r.Status, delimiter, r.Ret) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + var errMsg string + errNo, err := lookupErrno(r.Status) + if err == nil { + errMsg = fmt.Sprintf("%s (%d)", errNo.StrError, r.Status) } else { - fmt.Fprintf(file, "%s", delimiter) + errMsg = fmt.Sprintf("Godit error searching (%d)", r.Status) + } + if flags&PRT_JSON == PRT_JSON { + printable := struct { + Msg string `json:"message"` + Code uint64 `json:"code"` // Effective user ID + }{ + Msg: errMsg, + Code: r.Ret, + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"return64\":") + fmt.Fprintf(file, "%s", j) + // return64 is always followed by something + fmt.Fprintf(file, ",") + } else { + fmt.Fprintf(file, "return%s%v%s%v", delimiter, errMsg, delimiter, r.Ret) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -1730,9 +2396,27 @@ func (t *Trailer) LoadFromBinary(rdr *bufio.Reader) error { } func (t *Trailer) Print(file *os.File, delimiter string, flags int) { - fmt.Fprintf(file, "trailer%s%v", delimiter, t.Count) - // The trailer close the record print, whatever the oneLine flag value - fmt.Fprintf(file, "\n") + if flags&PRT_JSON == PRT_JSON { + printable := struct { + Count uint32 `json:"length"` // Effective user ID + }{ + Count: t.Count, + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"trailer\":") + fmt.Fprintf(file, "%s", j) + // trailer close the json object + fmt.Fprintf(file, "}\n") + } else { + fmt.Fprintf(file, "trailer%s%v", delimiter, t.Count) + // The trailer close the record print, whatever the oneLine flag value + fmt.Fprintf(file, "\n") + } } func NewArg32(a Arg32) *Arg32 { @@ -1775,11 +2459,33 @@ func (a *Arg32) LoadFromBinary(rdr *bufio.Reader) error { } func (a *Arg32) Print(file *os.File, delimiter string, flags int) { - fmt.Fprintf(file, "argument%s%v%s%v%s%s", delimiter, a.No, delimiter, a.Val, delimiter, string(a.Text)) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + if flags&PRT_JSON == PRT_JSON { + printable := struct { + Count uint32 `json:"count"` // Effective user ID + Val uint32 `json:"value"` + Text string `json:"text"` + }{ + Count: uint32(a.No), + Val: a.Val, + Text: string(a.Text), + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"arg32\":") + fmt.Fprintf(file, "%s", j) + // Arg32 is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + fmt.Fprintf(file, "argument%s%v%s%v%s%s", delimiter, a.No, delimiter, a.Val, delimiter, string(a.Text)) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -1823,11 +2529,33 @@ func (a *Arg64) LoadFromBinary(rdr *bufio.Reader) error { } func (a *Arg64) Print(file *os.File, delimiter string, flags int) { - fmt.Fprintf(file, "argument%s%v%s%v%s%s", delimiter, a.No, delimiter, a.Val, delimiter, string(a.Text)) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + if flags&PRT_JSON == PRT_JSON { + printable := struct { + Count uint32 `json:"count"` // Effective user ID + Val uint64 `json:"value"` + Text string `json:"text"` + }{ + Count: uint32(a.No), + Val: a.Val, + Text: string(a.Text), + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"arg64\":") + fmt.Fprintf(file, "%s", j) + // Arg64 is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + fmt.Fprintf(file, "argument%s%v%s%v%s%s", delimiter, a.No, delimiter, a.Val, delimiter, string(a.Text)) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -1916,19 +2644,32 @@ func (s *SocketEx) Print(file *os.File, delimiter string, flags int) { } else { // TODO : Handle error } - fmt.Fprintf(file, "socket%s%v%s%v%s%v%s%s%s%v%s%s", delimiter, s.Domain, delimiter, s.SockType, delimiter, s.LocalPort, delimiter, - lip, delimiter, s.RemotePort, delimiter, rip) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + + if flags&PRT_JSON == PRT_JSON { + j, err := json.Marshal(s) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"socket_ex\":") + fmt.Fprintf(file, "%s", j) + // SocketEx is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + fmt.Fprintf(file, "socket%s%v%s%v%s%v%s%s%s%v%s%s", delimiter, s.Domain, delimiter, s.SockType, delimiter, s.LocalPort, delimiter, + lip, delimiter, s.RemotePort, delimiter, rip) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } func NewSockInet32(s SockInet32) *SockInet32 { return &SockInet32{ Family: s.Family, - Lport: s.Lport, + Port: s.Port, Addr4: s.Addr4, } } @@ -1943,9 +2684,9 @@ func (s *SockInet32) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read SockInet32.Family: %v", err) } - err = binary.Read(rdr, binary.BigEndian, &s.Lport) + err = binary.Read(rdr, binary.BigEndian, &s.Port) if err != nil { - return fmt.Errorf("Unable to read SockInet32.Lport: %v", err) + return fmt.Errorf("Unable to read SockInet32.Port: %v", err) } err = binary.Read(rdr, binary.BigEndian, &s.Addr4) @@ -1957,18 +2698,40 @@ func (s *SockInet32) LoadFromBinary(rdr *bufio.Reader) error { } func (s *SockInet32) Print(file *os.File, delimiter string, flags int) { - fmt.Fprintf(file, "socket-inet%s%v%s%v%s%s", delimiter, s.Family, delimiter, s.Lport, delimiter, PrintIpv4FromInt(s.Addr4)) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + if flags&PRT_JSON == PRT_JSON { + printable := struct { + Family uint16 `json:"family"` + Port uint16 `json:"port"` + Addr4 string `json:"ip4"` + }{ + Family: s.Family, + Port: s.Port, + Addr4: PrintIpv4FromInt(s.Addr4), + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"sockinet32\":") + fmt.Fprintf(file, "%s", j) + // SockInet32 is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + fmt.Fprintf(file, "socket-inet%s%v%s%v%s%s", delimiter, s.Family, delimiter, s.Port, delimiter, PrintIpv4FromInt(s.Addr4)) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } func NewSockInet128(s SockInet128) *SockInet128 { return &SockInet128{ Family: s.Family, - Lport: s.Lport, + Port: s.Port, Addr6: s.Addr6, } } @@ -1983,9 +2746,9 @@ func (s *SockInet128) LoadFromBinary(rdr *bufio.Reader) error { return fmt.Errorf("Unable to read SockInet128.Family: %v", err) } - err = binary.Read(rdr, binary.BigEndian, &s.Lport) + err = binary.Read(rdr, binary.BigEndian, &s.Port) if err != nil { - return fmt.Errorf("Unable to read SockInet128.Lport: %v", err) + return fmt.Errorf("Unable to read SockInet128.Port: %v", err) } err = binary.Read(rdr, binary.BigEndian, &s.Addr6) @@ -1997,11 +2760,33 @@ func (s *SockInet128) LoadFromBinary(rdr *bufio.Reader) error { } func (s *SockInet128) Print(file *os.File, delimiter string, flags int) { - fmt.Fprintf(file, "socket-inet6%s%v%s%v%s%s", delimiter, s.Family, delimiter, s.Lport, delimiter, PrintIpv6FromInt(s.Addr6)) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + if flags&PRT_JSON == PRT_JSON { + printable := struct { + Family uint16 `json:"family"` + Port uint16 `json:"port"` + Addr6 string `json:"ip6"` + }{ + Family: s.Family, + Port: s.Port, + Addr6: PrintIpv6FromInt(s.Addr6), + } + + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"sockinet128\":") + fmt.Fprintf(file, "%s", j) + // SockInet128 is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + fmt.Fprintf(file, "socket-inet6%s%v%s%v%s%s", delimiter, s.Family, delimiter, s.Port, delimiter, PrintIpv6FromInt(s.Addr6)) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -2033,11 +2818,30 @@ func (s *SockUnix) LoadFromBinary(rdr *bufio.Reader) error { } func (s *SockUnix) Print(file *os.File, delimiter string, flags int) { - fmt.Fprintf(file, "socket-unix%s%v%s%s", delimiter, s.Family, delimiter, string(s.Path)) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + if flags&PRT_JSON == PRT_JSON { + printable := struct { + Family uint16 `json:"family"` + Path string `json:"path"` + }{ + Family: s.Family, + Path: string(s.Path), + } + j, err := json.Marshal(printable) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"sockunix\":") + fmt.Fprintf(file, "%s", j) + // SockUnix is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + fmt.Fprintf(file, "socket-unix%s%v%s%s", delimiter, s.Family, delimiter, string(s.Path)) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -2067,11 +2871,23 @@ func (e *Exit) LoadFromBinary(rdr *bufio.Reader) error { } func (e *Exit) Print(file *os.File, delimiter string, flags int) { - fmt.Fprintf(file, "exit%s%v%s%v", delimiter, e.Status, delimiter, e.Ret) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + if flags&PRT_JSON == PRT_JSON { + j, err := json.Marshal(e) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"exit\":") + fmt.Fprintf(file, "%s", j) + // Exit is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + fmt.Fprintf(file, "exit%s%v%s%v", delimiter, e.Status, delimiter, e.Ret) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } @@ -2103,11 +2919,23 @@ func (t *Text) LoadFromBinary(rdr *bufio.Reader) error { } func (t *Text) Print(file *os.File, delimiter string, flags int) { - fmt.Fprintf(file, "text%s%s", delimiter, t.Text) - if 0 == (flags & PRT_ONELINE) { - fmt.Fprintf(file, "\n") + if flags&PRT_JSON == PRT_JSON { + j, err := json.Marshal(t) + if err != nil { + // TODO + return + } + fmt.Fprintf(file, "\"text\":") + fmt.Fprintf(file, "%s", j) + // Text is always followed by something + fmt.Fprintf(file, ",") } else { - fmt.Fprintf(file, "%s", delimiter) + fmt.Fprintf(file, "text%s%s", delimiter, t.Text) + if 0 == (flags & PRT_ONELINE) { + fmt.Fprintf(file, "\n") + } else { + fmt.Fprintf(file, "%s", delimiter) + } } } diff --git a/main.go b/main.go index 20507dd..c51f0ac 100644 --- a/main.go +++ b/main.go @@ -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 // @@ -31,27 +33,27 @@ import ( ) const ( - version = "0.5.1" + version = "5.9.9a" ) var ( - randFlag bool - showVersion bool + randFlag bool + showVersion bool // Default delimiter - delimiter = "," + delimiter = "," ) - func main() { var flags int var oneLine bool var noUserResolve bool var timestamp bool + var json 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(×tamp, "timestamp", "t", false, "Print unix timestamp instead of formatted date/time.") + pflag.BoolVarP(&json, "json", "j", false, "Print compact json") pflag.BoolVarP(&showVersion, "version", "V", false, "Show version then exit") pflag.Parse() @@ -60,26 +62,22 @@ 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 json { + flags |= PRT_JSON + } args := os.Args filename := args[len(args)-1] - -/* fmt.Printf("Args: %s\n", args) - fmt.Printf("Filename: %s\n", filename) -*/ - + var f *os.File var r *bufio.Reader var err error @@ -102,7 +100,7 @@ func main() { if err != nil { if err != io.EOF { fmt.Printf("Erreur : %v\n", err) - } else { // v.0.4.2 : Continue on error + } else { // v.0.4.2 : Continue on error return } } @@ -110,5 +108,3 @@ func main() { } } } - -