• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Achiefs / fim / 9908854470

12 Jul 2024 01:40PM UTC coverage: 85.413% (+0.03%) from 85.381%
9908854470

push

github

okynos
Solved clippy report, clone_from and unwrap_or_default

6 of 6 new or added lines in 2 files covered. (100.0%)

1 existing line in 1 file now uncovered.

1095 of 1282 relevant lines covered (85.41%)

1.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.58
/src/logreader.rs
1
// Copyright (C) 2022, Achiefs.
2

3
// Global constants definitions
4
pub const AUDIT_PATH: &str = "/var/log/audit";
5
pub const AUDIT_LOG_PATH: &str = "/var/log/audit/audit.log";
6

7
// To manage file reading
8
use std::io::{BufReader, SeekFrom};
9
use std::io::prelude::*;
10
// To manage readed data into collection
11
use std::collections::HashMap;
12
// To log the program process
13
use log::{debug, error};
14

15
// Single event data management
16
use crate::auditevent::Event;
17
// To manage common functions
18
use crate::utils;
19
// To get configuration constants
20
use crate::appconfig::*;
21

22
// Defined type to simplify syntax
23
type SHashMap = HashMap<String, String>;
24

25
// ----------------------------------------------------------------------------
26

27
// Read file to extract last data until the Audit ID changes
28
pub fn read_log(file: String, cfg: AppConfig, position: u64, itx: u64) -> (Event, u64) {
1✔
29
    let mut event: Event = Event::new();
1✔
30
    let mut current_position = position;
1✔
31
    let log = utils::open_file(&file, 0);
2✔
32
    let mut buff = BufReader::new(log);
1✔
33
    match buff.seek(SeekFrom::Current(position as i64)) {
2✔
34
        Ok(p) => debug!("Seek audit log file, position: {}", p),
3✔
35
        Err(e) => error!("{}", e)
×
36
    };
37

38
    // Read from last registered position until we get event or the end
39
    let mut data: Vec<HashMap<String, String>> = Vec::new();
1✔
40
    let mut line = String::new();
2✔
41
    while current_position < utils::get_file_end(&file, 0) {
2✔
42
        debug!("Reading start: {}", current_position);
2✔
43
        let bytes_read = match buff.read_line(&mut line){
2✔
44
            Ok(bytes) => {
1✔
45
                debug!("Read string: '{}', bytes read: {}", line, bytes);
3✔
46
                bytes as u64
1✔
47
            },
48
            Err(e) => {
×
49
                error!("Reading string line, position: {}, error: {}", current_position, e);
×
50
                0
×
51
            }
52
        };
53
        current_position += bytes_read;
2✔
54
        debug!("End read position: {}\n", current_position);
3✔
55

56
        let line_info = parse_audit_log(line.clone());
2✔
57
        if line_info.contains_key("type") && (line_info["type"] == "SYSCALL" ||
3✔
58
            line_info["type"] == "CWD" ||
2✔
59
            line_info["type"] == "PATH" ||
1✔
60
            line_info["type"] == "PROCTITLE") {
1✔
61
            data.push(line_info.clone());
2✔
62
            if line_info.contains_key("type") &&
1✔
63
                line_info["type"] == "PROCTITLE" {
1✔
64
                debug!("PROCTITLE line detected, breaking loop. Data: {:?}", data);
3✔
65
                break;
66
            }
67
        }
68
        line = String::new();
2✔
69
    }
70
    if !data.is_empty() {
2✔
71
        let last = data.last().unwrap();
3✔
72
        let first = data.first().unwrap();
2✔
73
        if last.contains_key("type") &&
2✔
74
            first.contains_key("type") &&
1✔
75
            last["type"] == "PROCTITLE" &&
1✔
76
            first["type"] == "SYSCALL" {
1✔
77
            let (syscall, cwd, proctitle, paths) = extract_fields(data.clone());
2✔
78
            let audit_vec = cfg.audit.to_vec();
2✔
79

80
            // Skip the event generation of paths not monitored by FIM
81
            if paths.iter().any(|p| {
4✔
82
                let cwd_path = cwd["cwd"].as_str();
1✔
83
                cfg.path_in(p["name"].as_str(), cwd_path, audit_vec.clone()) ||
2✔
84
                cfg.path_in(cwd_path, "", audit_vec.clone())
×
85
            }) {
86
                event = Event::from(syscall, cwd, proctitle, paths, cfg.clone());
1✔
87
            }
88
        }else if data.iter().any(|line| {
2✔
89
            line["type"] == "SYSCALL" ||
×
90
            line["type"] == "CWD" ||
×
91
            line["type"] == "PATH" ||
×
92
            line["type"] == "PROCTITLE"
×
93
        }) && itx < 120 {
×
94
            current_position = position;
×
95
        }else{
96
            debug!("Audit log discarded, data: {:?}", data);
×
97
        }
98
    }
99
    (event, current_position)
1✔
100
}
101

102
// ----------------------------------------------------------------------------
103

104
pub fn extract_fields(data: Vec<HashMap<String, String>>) -> (SHashMap,
1✔
105
    SHashMap, SHashMap, Vec<SHashMap>) {
106
    let mut paths: Vec<SHashMap> = Vec::new();
1✔
107
    let mut syscall = SHashMap::new();
1✔
108
    let mut cwd = SHashMap::from([ (String::from("cwd"), String::from("/UNKNOWN")) ]);
2✔
109
    let mut proctitle = SHashMap::new();
1✔
110

111
    data.iter().for_each(|v| {
3✔
112
        match v["type"].as_str() {
1✔
113
            "SYSCALL" => syscall.clone_from(v),
2✔
114
            "PATH" => paths.push(v.clone()),
2✔
115
            "CWD" => cwd.clone_from(v),
2✔
116
            "PROCTITLE" => proctitle.clone_from(v),
2✔
UNCOV
117
            _ => error!("Unidentified Audit field")
×
118
        }
119
    });
120
    (syscall, cwd, proctitle, paths)
1✔
121
}
122

123
// ----------------------------------------------------------------------------
124

125
pub fn parse_audit_log(log: String) -> HashMap<String, String> {
1✔
126
    let fields: Vec<&str> = log.split(' ').collect();
2✔
127
    fields.iter()
2✔
128
        .map(|f| {
1✔
129
            let obj: Vec<&str> = f.split('=').collect();
1✔
130
            if obj.len() == 2 {
2✔
131
                (String::from(obj[0]), String::from(obj[1]).replace(['\"', '\n'], ""))
2✔
132
            }else{
133
                (String::from(obj[0]), String::from("UNKNOWN"))
×
134
            }
135
        }).collect::<HashMap<String, String>>()
1✔
136
}
137

138
// ----------------------------------------------------------------------------
139

140
#[cfg(test)]
141
mod tests {
142
    use super::*;
143

144
    #[test]
145
    fn test_read_log() {
146
        if utils::get_os() == "linux" {
147
            let cfg = AppConfig::new("linux", None);
148
            let (event, position) = read_log(String::from("test/unit/audit.log"),
149
                cfg, 0, 0);
150

151
            assert_eq!(event.id.len(), 36);
152
            assert_eq!(event.path, ".");
153
            assert_eq!(event.operation, "CREATE");
154
            assert_eq!(event.file, "sedTsutP7");
155
            assert_eq!(event.timestamp, "1659026449689");
156
            assert_eq!(event.proctitle, "736564002D6900737C68656C6C6F7C4849217C670066696C6531302E747874");
157
            assert_eq!(event.cap_fver, "0");
158
            assert_eq!(event.inode, "1972630");
159
            assert_eq!(event.cap_fp, "0");
160
            assert_eq!(event.cap_fe, "0");
161
            assert_eq!(event.item, "1");
162
            assert_eq!(event.cap_fi, "0");
163
            assert_eq!(event.dev, "08:02");
164
            assert_eq!(event.mode, "0100000");
165
            assert_eq!(event.cap_frootid, "0");
166
            assert_eq!(event.ouid, "0");
167
            assert_eq!(event.paths[0]["item"], "0");
168
            assert_eq!(event.paths[0]["name"], "./");
169
            assert_eq!(event.paths[0]["inode"], "1966138");
170
            assert_eq!(event.paths[0]["dev"], "08:02");
171
            assert_eq!(event.paths[0]["mode"], "040755");
172
            assert_eq!(event.paths[0]["ouid"], "1000");
173
            assert_eq!(event.paths[0]["ogid"], "0");
174
            assert_eq!(event.paths[0]["rdev"], "00:00");
175
            assert_eq!(event.paths[0]["nametype"], "PARENT");
176
            assert_eq!(event.paths[0]["cap_fp"], "0");
177
            assert_eq!(event.paths[0]["cap_fi"], "0");
178
            assert_eq!(event.paths[0]["cap_fe"], "0");
179
            assert_eq!(event.paths[0]["cap_fver"], "0");
180
            assert_eq!(event.paths[0]["cap_frootid"], "0");
181
            assert_eq!(event.paths[1]["item"], "1");
182
            assert_eq!(event.paths[1]["name"], "./sedTsutP7");
183
            assert_eq!(event.paths[1]["inode"], "1972630");
184
            assert_eq!(event.paths[1]["dev"], "08:02");
185
            assert_eq!(event.paths[1]["mode"], "0100000");
186
            assert_eq!(event.paths[1]["ouid"], "0");
187
            assert_eq!(event.paths[1]["ogid"], "0");
188
            assert_eq!(event.paths[1]["rdev"], "00:00");
189
            assert_eq!(event.paths[1]["nametype"], "CREATE");
190
            assert_eq!(event.paths[1]["cap_fp"], "0");
191
            assert_eq!(event.paths[1]["cap_fi"], "0");
192
            assert_eq!(event.paths[1]["cap_fe"], "0");
193
            assert_eq!(event.paths[1]["cap_fver"], "0");
194
            assert_eq!(event.paths[1]["cap_frootid"], "0");
195
            assert_eq!(event.cwd, "/tmp");
196
            assert_eq!(event.syscall, "257");
197
            assert_eq!(event.ppid, "161880");
198
            assert_eq!(event.comm, "sed");
199
            assert_eq!(event.fsuid, "0");
200
            assert_eq!(event.pid, "161937");
201
            assert_eq!(event.a0, "ffffff9c");
202
            assert_eq!(event.a1, "556150ee3c00");
203
            assert_eq!(event.a2, "c2");
204
            assert_eq!(event.a3, "180");
205
            assert_eq!(event.arch, "c000003e");
206
            assert_eq!(event.auid, "1000");
207
            assert_eq!(event.items, "2");
208
            assert_eq!(event.gid, "0");
209
            assert_eq!(event.euid, "0");
210
            assert_eq!(event.sgid, "0");
211
            assert_eq!(event.uid, "0");
212
            assert_eq!(event.tty, "pts0");
213
            assert_eq!(event.success, "yes");
214
            assert_eq!(event.exit, "4");
215
            assert_eq!(event.ses, "807");
216
            assert_eq!(event.key, "fim");
217
            assert_eq!(event.suid, "0");
218
            assert_eq!(event.egid, "0");
219
            assert_eq!(event.fsgid, "0");
220
            assert_eq!(event.exe, "/usr/bin/sed");
221
            assert_eq!(position, 845);
222
        }
223
    }
224

225
    // ------------------------------------------------------------------------
226

227
    #[test]
228
    fn test_extract_fields() {
229
        let mut data = Vec::<HashMap<String, String>>::new();
230
        data.push(HashMap::from([ (String::from("type"), String::from("SYSCALL")) ]));
231
        data.push(HashMap::from([ (String::from("type"), String::from("CWD")) ]));
232
        data.push(HashMap::from([ (String::from("type"), String::from("PROCTITLE")) ]));
233
        data.push(HashMap::from([ (String::from("type"), String::from("PATH")),
234
            (String::from("nametype"), String::from("CREATE")) ]));
235
        data.push(HashMap::from([ (String::from("type"), String::from("PATH")),
236
            (String::from("nametype"), String::from("PARENT")) ]));
237
        let (a, b, c, vd) = extract_fields(data);
238
        assert_eq!(a["type"], String::from("SYSCALL"));
239
        assert_eq!(b["type"], String::from("CWD"));
240
        assert_eq!(c["type"], String::from("PROCTITLE"));
241
        assert_eq!(vd[0]["type"], String::from("PATH"));
242
        assert_eq!(vd[0]["nametype"], String::from("CREATE"));
243
        assert_eq!(vd[1]["type"], String::from("PATH"));
244
        assert_eq!(vd[1]["nametype"], String::from("PARENT"));
245
    }
246

247
    // ------------------------------------------------------------------------
248

249
    #[test]
250
    fn test_parse_audit_log() {
251
        let audit_line = String::from("type=CWD msg=audit(1659026449.689:6434): cwd=\"/tmp/test\"");
252
        let map = parse_audit_log(audit_line);
253
        assert_eq!(map["type"], "CWD");
254
        assert_eq!(map["msg"], "audit(1659026449.689:6434):");
255
        assert_eq!(map["cwd"], "/tmp/test");
256
        assert_eq!(map.len(), 3);
257
    }
258
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc