Skip to content

Commit 5fbad3b

Browse files
committed
Add Parser object that encapsulate settings
So far, this is only the "enriched" setting, but more will follow later.
1 parent d8c448c commit 5fbad3b

File tree

1 file changed

+109
-85
lines changed

1 file changed

+109
-85
lines changed

src/parser.rs

Lines changed: 109 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ use thiserror::Error;
1313
use crate::constants::*;
1414
use 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)]
1831
pub 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)]
4456
pub 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)]
192216
fn parse_kv(input: &[u8], ty: MessageType) -> IResult<&[u8], (Key, Value)> {

0 commit comments

Comments
 (0)