@@ -13,6 +13,19 @@ use thiserror::Error;
1313use crate :: constants:: * ;
1414use crate :: * ;
1515
16+ /// Parser for Linux Audit messages, with a few configurable options
17+ #[ derive( Debug ) ]
18+ pub struct Parser {
19+ /// Process enriched (i.e. ALL-CAPS keys)
20+ pub enriched : bool ,
21+ }
22+
23+ impl Default for Parser {
24+ fn default ( ) -> Self {
25+ Self { enriched : true }
26+ }
27+ }
28+
1629/// Audit parser error type
1730#[ derive( Debug , Error ) ]
1831pub enum ParseError {
@@ -40,26 +53,109 @@ pub enum ParseError {
4053/// produce `log_format=ENRICHED` logs, i.e. to resolve `uid`, `gid`,
4154/// `syscall`, `arch`, `sockaddr` fields, those resolved values are
4255/// dropped by the parser.
43- #[ allow( clippy:: type_complexity) ]
4456pub fn parse < ' a > ( raw : & [ u8 ] , skip_enriched : bool ) -> Result < Message < ' a > , ParseError > {
45- let ( rest, ( node, ty, id) ) =
46- parse_header ( raw) . map_err ( |_| ParseError :: MalformedHeader ( raw. to_vec ( ) ) ) ?;
57+ Parser {
58+ enriched : !skip_enriched,
59+ ..Parser :: default ( )
60+ }
61+ . parse ( raw)
62+ }
4763
48- let ( rest, kv) = parse_body ( rest, ty, skip_enriched)
49- . map_err ( |_| ParseError :: MalformedBody ( rest. to_vec ( ) ) ) ?;
64+ impl Parser {
65+ /// Parse a single log line as produced by _auditd(8)_
66+ pub fn parse < ' a , ' b > ( & ' a self , raw : & ' a [ u8 ] ) -> Result < Message < ' b > , ParseError > {
67+ let ( rest, ( node, ty, id) ) =
68+ parse_header ( raw) . map_err ( |_| ParseError :: MalformedHeader ( raw. to_vec ( ) ) ) ?;
5069
51- if !rest . is_empty ( ) {
52- return Err ( ParseError :: TrailingGarbage ( rest . to_vec ( ) ) ) ;
53- }
70+ let ( rest , kv ) = self
71+ . parse_body ( rest , ty )
72+ . map_err ( |_| ParseError :: MalformedBody ( rest . to_vec ( ) ) ) ? ;
5473
55- let node = node. map ( |s| s. to_vec ( ) ) ;
74+ if !rest. is_empty ( ) {
75+ return Err ( ParseError :: TrailingGarbage ( rest. to_vec ( ) ) ) ;
76+ }
77+
78+ let node = node. map ( |s| s. to_vec ( ) ) ;
5679
57- let mut body = Body :: new ( ) ;
58- for ( k, v) in kv {
59- body. push ( ( k, v) ) ;
80+ let mut body = Body :: new ( ) ;
81+ for ( k, v) in kv {
82+ body. push ( ( k, v) ) ;
83+ }
84+
85+ Ok ( Message { id, node, ty, body } )
6086 }
6187
62- Ok ( Message { id, node, ty, body } )
88+ /// Recognize the body: Multiple key/value pairs, with special cases
89+ /// for some irregular messages
90+ #[ inline( always) ]
91+ fn parse_body < ' a > (
92+ & ' a self ,
93+ input : & ' a [ u8 ] ,
94+ ty : MessageType ,
95+ ) -> IResult < & ' a [ u8 ] , Vec < ( Key , Value ) > > {
96+ // Handle some corner cases that don't fit the general key=value
97+ // scheme.
98+ let ( input, special) = match ty {
99+ MessageType :: AVC => opt ( map (
100+ tuple ( (
101+ preceded (
102+ pair ( tag ( "avc:" ) , space0) ,
103+ alt ( ( tag ( "granted" ) , tag ( "denied" ) ) ) ,
104+ ) ,
105+ delimited (
106+ tuple ( ( space0, tag ( "{" ) , space0) ) ,
107+ many1 ( terminated ( parse_identifier, space0) ) ,
108+ tuple ( ( tag ( "}" ) , space0, tag ( "for" ) , space0) ) ,
109+ ) ,
110+ ) ) ,
111+ |( k, v) | {
112+ (
113+ Key :: Name ( NVec :: from ( k) ) ,
114+ Value :: List (
115+ v. iter ( )
116+ . map ( |e| Value :: Str ( e, Quote :: None ) )
117+ . collect :: < Vec < _ > > ( ) ,
118+ ) ,
119+ )
120+ } ,
121+ ) ) ( input) ?,
122+ MessageType :: TTY => {
123+ let ( input, _) = opt ( tag ( "tty " ) ) ( input) ?;
124+ ( input, None )
125+ }
126+ MessageType :: MAC_POLICY_LOAD => {
127+ let ( input, _) = opt ( tag ( "policy loaded " ) ) ( input) ?;
128+ ( input, None )
129+ }
130+ _ => opt ( map (
131+ terminated ( tag ( "netlabel" ) , pair ( tag ( ":" ) , space0) ) ,
132+ |s| ( Key :: Name ( NVec :: from ( s) ) , Value :: Empty ) ,
133+ ) ) ( input) ?,
134+ } ;
135+
136+ let ( input, mut kv) = if !self . enriched {
137+ terminated (
138+ separated_list0 ( tag ( b" " ) , |input| parse_kv ( input, ty) ) ,
139+ alt ( (
140+ value ( ( ) , tuple ( ( tag ( "\x1d " ) , is_not ( "\n " ) , tag ( "\n " ) ) ) ) ,
141+ value ( ( ) , tag ( "\n " ) ) ,
142+ ) ) ,
143+ ) ( input) ?
144+ } else {
145+ terminated (
146+ separated_list0 ( take_while1 ( |c| c == b' ' || c == b'\x1d' ) , |input| {
147+ parse_kv ( input, ty)
148+ } ) ,
149+ newline,
150+ ) ( input) ?
151+ } ;
152+
153+ if let Some ( s) = special {
154+ kv. push ( s)
155+ }
156+
157+ Ok ( ( input, kv) )
158+ }
63159}
64160
65161/// Recognize the header: node, type, event identifier
@@ -115,78 +211,6 @@ fn parse_msgid(input: &[u8]) -> IResult<&[u8], EventID> {
115211 ) ( input)
116212}
117213
118- /// Recognize the body: Multiple key/value pairs, with special cases
119- /// for some irregular messages
120- #[ inline( always) ]
121- fn parse_body (
122- input : & [ u8 ] ,
123- ty : MessageType ,
124- skip_enriched : bool ,
125- ) -> IResult < & [ u8 ] , Vec < ( Key , Value ) > > {
126- // Handle some corner cases that don't fit the general key=value
127- // scheme.
128- let ( input, special) = match ty {
129- MessageType :: AVC => opt ( map (
130- tuple ( (
131- preceded (
132- pair ( tag ( "avc:" ) , space0) ,
133- alt ( ( tag ( "granted" ) , tag ( "denied" ) ) ) ,
134- ) ,
135- delimited (
136- tuple ( ( space0, tag ( "{" ) , space0) ) ,
137- many1 ( terminated ( parse_identifier, space0) ) ,
138- tuple ( ( tag ( "}" ) , space0, tag ( "for" ) , space0) ) ,
139- ) ,
140- ) ) ,
141- |( k, v) | {
142- (
143- Key :: Name ( NVec :: from ( k) ) ,
144- Value :: List (
145- v. iter ( )
146- . map ( |e| Value :: Str ( e, Quote :: None ) )
147- . collect :: < Vec < _ > > ( ) ,
148- ) ,
149- )
150- } ,
151- ) ) ( input) ?,
152- MessageType :: TTY => {
153- let ( input, _) = opt ( tag ( "tty " ) ) ( input) ?;
154- ( input, None )
155- }
156- MessageType :: MAC_POLICY_LOAD => {
157- let ( input, _) = opt ( tag ( "policy loaded " ) ) ( input) ?;
158- ( input, None )
159- }
160- _ => opt ( map (
161- terminated ( tag ( "netlabel" ) , pair ( tag ( ":" ) , space0) ) ,
162- |s| ( Key :: Name ( NVec :: from ( s) ) , Value :: Empty ) ,
163- ) ) ( input) ?,
164- } ;
165-
166- let ( input, mut kv) = if skip_enriched {
167- terminated (
168- separated_list0 ( tag ( b" " ) , |input| parse_kv ( input, ty) ) ,
169- alt ( (
170- value ( ( ) , tuple ( ( tag ( "\x1d " ) , is_not ( "\n " ) , tag ( "\n " ) ) ) ) ,
171- value ( ( ) , tag ( "\n " ) ) ,
172- ) ) ,
173- ) ( input) ?
174- } else {
175- terminated (
176- separated_list0 ( take_while1 ( |c| c == b' ' || c == b'\x1d' ) , |input| {
177- parse_kv ( input, ty)
178- } ) ,
179- newline,
180- ) ( input) ?
181- } ;
182-
183- if let Some ( s) = special {
184- kv. push ( s)
185- }
186-
187- Ok ( ( input, kv) )
188- }
189-
190214/// Recognize one key/value pair
191215#[ inline( always) ]
192216fn parse_kv ( input : & [ u8 ] , ty : MessageType ) -> IResult < & [ u8 ] , ( Key , Value ) > {
0 commit comments