@@ -16,13 +16,18 @@ use crate::*;
1616/// Parser for Linux Audit messages, with a few configurable options
1717#[ derive( Debug ) ]
1818pub struct Parser {
19- /// Process enriched (i.e. ALL-CAPS keys)
19+ /// Process enriched (i.e. ALL-CAPS keys). Default: true
2020 pub enriched : bool ,
21+ /// Try to process common msg='…' strings into key/value maps. Default: true
22+ pub split_msg : bool ,
2123}
2224
2325impl Default for Parser {
2426 fn default ( ) -> Self {
25- Self { enriched : true }
27+ Self {
28+ enriched : true ,
29+ split_msg : true ,
30+ }
2631 }
2732}
2833
@@ -53,6 +58,9 @@ pub enum ParseError {
5358/// produce `log_format=ENRICHED` logs, i.e. to resolve `uid`, `gid`,
5459/// `syscall`, `arch`, `sockaddr` fields, those resolved values are
5560/// dropped by the parser.
61+ ///
62+ /// To maintain compatibility, `parse` does not attempt to process
63+ /// single-quoted `msg='…'` strings into key/value maps.
5664pub fn parse < ' a > ( raw : & [ u8 ] , skip_enriched : bool ) -> Result < Message < ' a > , ParseError > {
5765 Parser {
5866 enriched : !skip_enriched,
@@ -135,7 +143,7 @@ impl Parser {
135143
136144 let ( input, mut kv) = if !self . enriched {
137145 terminated (
138- separated_list0 ( tag ( b" " ) , |input| parse_kv ( input, ty) ) ,
146+ separated_list0 ( tag ( b" " ) , |input| self . parse_kv ( input, ty) ) ,
139147 alt ( (
140148 value ( ( ) , tuple ( ( tag ( "\x1d " ) , is_not ( "\n " ) , tag ( "\n " ) ) ) ) ,
141149 value ( ( ) , tag ( "\n " ) ) ,
@@ -144,7 +152,7 @@ impl Parser {
144152 } else {
145153 terminated (
146154 separated_list0 ( take_while1 ( |c| c == b' ' || c == b'\x1d' ) , |input| {
147- parse_kv ( input, ty)
155+ self . parse_kv ( input, ty)
148156 } ) ,
149157 newline,
150158 ) ( input) ?
@@ -156,6 +164,101 @@ impl Parser {
156164
157165 Ok ( ( input, kv) )
158166 }
167+
168+ /// Recognize one key/value pair
169+ #[ inline( always) ]
170+ fn parse_kv < ' a > ( & ' a self , input : & ' a [ u8 ] , ty : MessageType ) -> IResult < & ' a [ u8 ] , ( Key , Value ) > {
171+ let ( input, key) = match ty {
172+ // Special case for execve arguments: aX, aX[Y], aX_len
173+ MessageType :: EXECVE
174+ if !input. is_empty ( ) && input[ 0 ] == b'a' && !input. starts_with ( b"argc" ) =>
175+ {
176+ terminated (
177+ alt ( ( parse_key_a_x_len, parse_key_a_xy, parse_key_a_x) ) ,
178+ tag ( "=" ) ,
179+ ) ( input)
180+ }
181+ // Special case for syscall params: aX
182+ MessageType :: SYSCALL => terminated ( alt ( ( parse_key_a_x, parse_key) ) , tag ( "=" ) ) ( input) ,
183+ _ => terminated ( parse_key, tag ( "=" ) ) ( input) ,
184+ } ?;
185+
186+ let ( input, value) = match ( ty, & key) {
187+ ( MessageType :: SYSCALL , Key :: Arg ( _, None ) ) => map (
188+ recognize ( terminated (
189+ many1_count ( take_while1 ( is_hex_digit) ) ,
190+ peek ( take_while1 ( is_sep) ) ,
191+ ) ) ,
192+ |s| {
193+ let ps = unsafe { str:: from_utf8_unchecked ( s) } ;
194+ match u64:: from_str_radix ( ps, 16 ) {
195+ Ok ( n) => Value :: Number ( Number :: Hex ( n) ) ,
196+ Err ( _) => Value :: Str ( s, Quote :: None ) ,
197+ }
198+ } ,
199+ ) ( input) ?,
200+ ( MessageType :: SYSCALL , Key :: Common ( c) ) => self . parse_common ( input, ty, * c) ?,
201+ ( MessageType :: EXECVE , Key :: Arg ( _, _) ) => parse_encoded ( input) ?,
202+ ( MessageType :: EXECVE , Key :: ArgLen ( _) ) => parse_dec ( input) ?,
203+ ( _, Key :: Name ( name) ) => parse_named ( input, ty, name) ?,
204+ ( _, Key :: Common ( c) ) => self . parse_common ( input, ty, * c) ?,
205+ ( _, Key :: NameUID ( name) ) | ( _, Key :: NameGID ( name) ) => {
206+ alt ( ( parse_dec, |input| parse_unspec_value ( input, ty, name) ) ) ( input) ?
207+ }
208+ _ => parse_encoded ( input) ?,
209+ } ;
210+
211+ Ok ( ( input, ( key, value) ) )
212+ }
213+
214+ #[ inline( always) ]
215+ fn parse_common < ' a > (
216+ & ' a self ,
217+ input : & ' a [ u8 ] ,
218+ ty : MessageType ,
219+ c : Common ,
220+ ) -> IResult < & ' a [ u8 ] , Value > {
221+ let name = <& str >:: from ( c) . as_bytes ( ) ;
222+ match c {
223+ Common :: Arch | Common :: CapFi | Common :: CapFp | Common :: CapFver => {
224+ alt ( ( parse_hex, |input| parse_unspec_value ( input, ty, name) ) ) ( input)
225+ }
226+ Common :: Argc
227+ | Common :: Exit
228+ | Common :: CapFe
229+ | Common :: Inode
230+ | Common :: Item
231+ | Common :: Items
232+ | Common :: Pid
233+ | Common :: PPid
234+ | Common :: Ses
235+ | Common :: Syscall => {
236+ alt ( ( parse_dec, |input| parse_unspec_value ( input, ty, name) ) ) ( input)
237+ }
238+ Common :: Success
239+ | Common :: Cwd
240+ | Common :: Dev
241+ | Common :: Tty
242+ | Common :: Comm
243+ | Common :: Exe
244+ | Common :: Name
245+ | Common :: Nametype
246+ | Common :: Subj
247+ | Common :: Key => {
248+ alt ( ( parse_encoded, |input| parse_unspec_value ( input, ty, name) ) ) ( input)
249+ }
250+ Common :: Mode => alt ( ( parse_oct, |input| parse_unspec_value ( input, ty, name) ) ) ( input) ,
251+ Common :: Msg => {
252+ if self . split_msg {
253+ alt ( ( parse_kv_sq_as_map, |input| {
254+ parse_unspec_value ( input, ty, name)
255+ } ) ) ( input)
256+ } else {
257+ alt ( ( parse_encoded, |input| parse_unspec_value ( input, ty, name) ) ) ( input)
258+ }
259+ }
260+ }
261+ }
159262}
160263
161264/// Recognize the header: node, type, event identifier
@@ -211,52 +314,6 @@ fn parse_msgid(input: &[u8]) -> IResult<&[u8], EventID> {
211314 ) ( input)
212315}
213316
214- /// Recognize one key/value pair
215- #[ inline( always) ]
216- fn parse_kv ( input : & [ u8 ] , ty : MessageType ) -> IResult < & [ u8 ] , ( Key , Value ) > {
217- let ( input, key) = match ty {
218- // Special case for execve arguments: aX, aX[Y], aX_len
219- MessageType :: EXECVE
220- if !input. is_empty ( ) && input[ 0 ] == b'a' && !input. starts_with ( b"argc" ) =>
221- {
222- terminated (
223- alt ( ( parse_key_a_x_len, parse_key_a_xy, parse_key_a_x) ) ,
224- tag ( "=" ) ,
225- ) ( input)
226- }
227- // Special case for syscall params: aX
228- MessageType :: SYSCALL => terminated ( alt ( ( parse_key_a_x, parse_key) ) , tag ( "=" ) ) ( input) ,
229- _ => terminated ( parse_key, tag ( "=" ) ) ( input) ,
230- } ?;
231-
232- let ( input, value) = match ( ty, & key) {
233- ( MessageType :: SYSCALL , Key :: Arg ( _, None ) ) => map (
234- recognize ( terminated (
235- many1_count ( take_while1 ( is_hex_digit) ) ,
236- peek ( take_while1 ( is_sep) ) ,
237- ) ) ,
238- |s| {
239- let ps = unsafe { str:: from_utf8_unchecked ( s) } ;
240- match u64:: from_str_radix ( ps, 16 ) {
241- Ok ( n) => Value :: Number ( Number :: Hex ( n) ) ,
242- Err ( _) => Value :: Str ( s, Quote :: None ) ,
243- }
244- } ,
245- ) ( input) ?,
246- ( MessageType :: SYSCALL , Key :: Common ( c) ) => parse_common ( input, ty, * c) ?,
247- ( MessageType :: EXECVE , Key :: Arg ( _, _) ) => parse_encoded ( input) ?,
248- ( MessageType :: EXECVE , Key :: ArgLen ( _) ) => parse_dec ( input) ?,
249- ( _, Key :: Name ( name) ) => parse_named ( input, ty, name) ?,
250- ( _, Key :: Common ( c) ) => parse_common ( input, ty, * c) ?,
251- ( _, Key :: NameUID ( name) ) | ( _, Key :: NameGID ( name) ) => {
252- alt ( ( parse_dec, |input| parse_unspec_value ( input, ty, name) ) ) ( input) ?
253- }
254- _ => parse_encoded ( input) ?,
255- } ;
256-
257- Ok ( ( input, ( key, value) ) )
258- }
259-
260317#[ inline( always) ]
261318fn parse_named < ' a > ( input : & ' a [ u8 ] , ty : MessageType , name : & [ u8 ] ) -> IResult < & ' a [ u8 ] , Value < ' a > > {
262319 match FIELD_TYPES . get ( name) {
@@ -277,37 +334,6 @@ fn parse_named<'a>(input: &'a [u8], ty: MessageType, name: &[u8]) -> IResult<&'a
277334 }
278335}
279336
280- #[ inline( always) ]
281- fn parse_common ( input : & [ u8 ] , ty : MessageType , c : Common ) -> IResult < & [ u8 ] , Value > {
282- let name = <& str >:: from ( c) . as_bytes ( ) ;
283- match c {
284- Common :: Arch | Common :: CapFi | Common :: CapFp | Common :: CapFver => {
285- alt ( ( parse_hex, |input| parse_unspec_value ( input, ty, name) ) ) ( input)
286- }
287- Common :: Argc
288- | Common :: Exit
289- | Common :: CapFe
290- | Common :: Inode
291- | Common :: Item
292- | Common :: Items
293- | Common :: Pid
294- | Common :: PPid
295- | Common :: Ses
296- | Common :: Syscall => alt ( ( parse_dec, |input| parse_unspec_value ( input, ty, name) ) ) ( input) ,
297- Common :: Success
298- | Common :: Cwd
299- | Common :: Dev
300- | Common :: Tty
301- | Common :: Comm
302- | Common :: Exe
303- | Common :: Name
304- | Common :: Nametype
305- | Common :: Subj
306- | Common :: Key => alt ( ( parse_encoded, |input| parse_unspec_value ( input, ty, name) ) ) ( input) ,
307- Common :: Mode => alt ( ( parse_oct, |input| parse_unspec_value ( input, ty, name) ) ) ( input) ,
308- }
309- }
310-
311337/// Recognize encoded value:
312338///
313339/// May be double-quoted string, hex-encoded blob, (null), ?.
@@ -447,6 +473,20 @@ fn parse_str_unq_inside_sq(input: &[u8]) -> IResult<&[u8], &[u8]> {
447473 take_while ( |c| is_safe_chr ( c) && c != b'\'' ) ( input)
448474}
449475
476+ #[ inline( always) ]
477+ fn parse_str_words_inside_sq ( input : & [ u8 ] ) -> IResult < & [ u8 ] , & [ u8 ] > {
478+ let mut rest = input;
479+ loop {
480+ ( rest, _) = take_while ( |c| !b"' " . contains ( & c) ) ( rest) ?;
481+ if let Ok ( _) = alt ( ( recognize ( tuple ( ( space1, parse_key, tag ( "=" ) ) ) ) , tag ( "'" ) ) ) ( rest) {
482+ break ;
483+ }
484+ ( rest, _) = space1 ( rest) ?;
485+ }
486+ let l = input. len ( ) - rest. len ( ) ;
487+ Ok ( ( rest, & input[ ..l] ) )
488+ }
489+
450490/// More "correct" variant of parse_str_sq
451491#[ inline( always) ]
452492fn parse_kv_sq ( input : & [ u8 ] ) -> IResult < & [ u8 ] , & [ u8 ] > {
@@ -464,6 +504,33 @@ fn parse_kv_sq(input: &[u8]) -> IResult<&[u8], &[u8]> {
464504 ) ( input)
465505}
466506
507+ /// Recognize a map enclosed in single quotes
508+ #[ inline( always) ]
509+ fn parse_kv_sq_as_map ( input : & [ u8 ] ) -> IResult < & [ u8 ] , Value > {
510+ map (
511+ delimited (
512+ tag ( "'" ) ,
513+ separated_list0 (
514+ space1,
515+ alt ( ( separated_pair (
516+ parse_key,
517+ alt ( (
518+ tag ( "=" ) ,
519+ recognize ( tuple ( ( tag ( ":" ) , space0) ) ) , // for 'avc: mumble mumble mumble …'
520+ ) ) ,
521+ alt ( (
522+ parse_encoded,
523+ map ( parse_str_words_inside_sq, |v| Value :: Str ( v, Quote :: None ) ) ,
524+ map ( parse_str_unq_inside_sq, |v| Value :: Str ( v, Quote :: None ) ) ,
525+ ) ) ,
526+ ) , ) ) ,
527+ ) ,
528+ tag ( "'" ) ,
529+ ) ,
530+ Value :: Map ,
531+ ) ( input)
532+ }
533+
467534/// More "correct" variant of parse_str_braced
468535#[ inline( always) ]
469536fn parse_kv_braced ( input : & [ u8 ] ) -> IResult < & [ u8 ] , & [ u8 ] > {
0 commit comments