Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump Notify dependency to 5.1 #91

Merged
merged 10 commits into from
Feb 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
[package]
name = "fim"
version = "0.4.4"
version = "0.4.5"
authors = ["José Fernández <´[email protected]´>"]
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
yaml-rust = "0.4"
notify = "4.0.17"
notify = "5.1.0"
simplelog = "0.12.0" # Candidate to remove
itertools = "0.10.3"
hex = "0.4.3"
Expand Down
1 change: 1 addition & 0 deletions config/index_template.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"file": { "type": "keyword" },
"hostname": { "type": "keyword" },
"operation": { "type": "keyword" },
"detailed_operation": { "type": "keyword" },
"node": { "type": "keyword" },
"version": { "type": "keyword" },
"checksum": { "type": "keyword" },
Expand Down
6 changes: 6 additions & 0 deletions pkg/deb/debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
fim (0.4.5-1) xenial; urgency=medium

* More info: https://github.com/Achiefs/fim/releases/tag/v0.4.5

-- Jose Fernandez <[email protected]> Sat, 18 Feb 2023 01:04:00 +0000

fim (0.4.4-1) xenial; urgency=medium

* More info: https://github.com/Achiefs/fim/releases/tag/v0.4.4
Expand Down
2 changes: 1 addition & 1 deletion pkg/fim.1
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
.\" *
.\" **************************************************************************
.\"
.TH fim 1 "01 Jun 2022" "FIM 0.4.4" "FIM Manual"
.TH fim 1 "01 Jun 2022" "FIM 0.4.5" "FIM Manual"

.SH NAME
.B FIM
Expand Down
2 changes: 1 addition & 1 deletion pkg/msi/fim.wxs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
<Product Name='File Integrity Monitor' Manufacturer='Achiefs LLC.' Id='*'
UpgradeCode='5b9136b1-f19d-4af0-9efe-356fabdf1467'
Language='1033' Codepage='1252' Version='0.4.4'>
Language='1033' Codepage='1252' Version='0.4.5'>
<Package Id='*' Keywords='Installer'
Description="FIM is a Host-based file monitoring tool that performs file system analysis and real time alerting."
Comments='FIM is an open source application, coded in Rust.'
Expand Down
3 changes: 3 additions & 0 deletions pkg/rpm/fim.spec
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ rm -fr %{buildroot}
# -----------------------------------------------------------------------------

%changelog
* Sat Feb 18 2023 support <[email protected]> - 0.4.5
- More info: https://github.com/Achiefs/fim/releases/tag/v0.4.5

* Tue Feb 14 2023 support <[email protected]> - 0.4.4
- More info: https://github.com/Achiefs/fim/releases/tag/v0.4.4

Expand Down
2 changes: 1 addition & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (C) 2021, Achiefs.

// Global constants definitions
pub const VERSION: &str = "0.4.4";
pub const VERSION: &str = "0.4.5";
pub const NETWORK_MODE: &str = "NETWORK";
pub const FILE_MODE: &str = "FILE";
pub const BOTH_MODE: &str = "BOTH";
Expand Down
238 changes: 194 additions & 44 deletions src/event.rs

Large diffs are not rendered by default.

197 changes: 101 additions & 96 deletions src/monitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// To read and write directories and files
use std::fs;
// To get file system changes
use notify::{RecommendedWatcher, Watcher, RecursiveMode};
use notify::{RecommendedWatcher, RecursiveMode, Watcher, Config as NConfig};
use std::sync::mpsc;
// To log the program process
use log::{info, error, debug, warn};
Expand All @@ -18,8 +18,7 @@ use itertools::Itertools;
// To run commands
use std::process::Command;
// Event handling
use notify::op::Op;
use notify::RawEvent;
use notify::event::{EventKind, AccessKind};


// Utils functions
Expand Down Expand Up @@ -89,7 +88,8 @@ async fn push_template(destination: &str, config: config::Config){
// ----------------------------------------------------------------------------

// Function that monitorize files in loop
pub async fn monitor(tx: mpsc::Sender<RawEvent>, rx: mpsc::Receiver<RawEvent>){
pub async fn monitor(tx: mpsc::Sender<Result<notify::Event, notify::Error>>,
rx: mpsc::Receiver<Result<notify::Event, notify::Error>>){
println!("Achiefs File Integrity Monitoring software started!");
println!("[INFO] Reading config...");
let config = config::Config::new(&utils::get_os());
Expand All @@ -103,8 +103,9 @@ pub async fn monitor(tx: mpsc::Sender<RawEvent>, rx: mpsc::Receiver<RawEvent>){
// Check if we have to push index template
push_template(destination.as_str(), config.clone()).await;

let mut watcher = RecommendedWatcher::new(tx, NConfig::default()).unwrap();

// Iterating over monitor paths and set watcher on each folder to watch.
let mut watcher: RecommendedWatcher = Watcher::new_raw(tx).unwrap();
if ! config.monitor.is_empty() {
for element in config.monitor.clone() {
let path = element["path"].as_str().unwrap();
Expand All @@ -117,7 +118,7 @@ pub async fn monitor(tx: mpsc::Sender<RawEvent>, rx: mpsc::Receiver<RawEvent>){
},
None => info!("Ignore for '{}' not set", path)
};
match watcher.watch(path, RecursiveMode::Recursive) {
match watcher.watch(Path::new(path), RecursiveMode::Recursive) {
Ok(_d) => debug!("Monitoring path: {}", path),
Err(e) => warn!("Could not monitor given path '{}', description: {}", path, e)
};
Expand All @@ -144,7 +145,7 @@ pub async fn monitor(tx: mpsc::Sender<RawEvent>, rx: mpsc::Receiver<RawEvent>){
};
}
// Detect if file is moved or renamed (rotation)
watcher.watch(logreader::AUDIT_PATH, RecursiveMode::NonRecursive).unwrap();
watcher.watch(Path::new(logreader::AUDIT_PATH), RecursiveMode::NonRecursive).unwrap();
last_position = utils::get_file_end(logreader::AUDIT_LOG_PATH, 0);
// Remove auditd rules introduced by FIM
let cconfig = config.clone();
Expand All @@ -163,109 +164,113 @@ pub async fn monitor(tx: mpsc::Sender<RawEvent>, rx: mpsc::Receiver<RawEvent>){
}).expect("Error setting Ctrl-C handler");
}


// Main loop, receive any produced event and write it into the events log.
loop {
match rx.recv() {
Ok(raw_event) => {
// Get the event path and filename
debug!("Event received: {:?}", raw_event);

if raw_event.path.clone().unwrap().to_str().unwrap() == "DISCONNECT" {
info!("Received exit signal, exiting...");
break;
}

let plain_path = raw_event.path.as_ref().unwrap().to_str().unwrap();
let event_path = Path::new(plain_path);
let event_filename = event_path.file_name().unwrap();
for message in &rx {
match message {
Ok(event) => {
// Get the event path and filename
debug!("Event received: {:?}", event);

let plain_path: &str = event.paths[0].to_str().unwrap();
if plain_path == "DISCONNECT" {
info!("Received exit signal, exiting...");
break;
}

let current_date = OffsetDateTime::now_utc();
let index_name = format!("fim-{}-{}-{}", current_date.year(), current_date.month() as u8, current_date.day() );
let current_timestamp = format!("{:?}", SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis());
let current_hostname = utils::get_hostname();
let op = raw_event.op.unwrap();
let path = raw_event.path.clone().unwrap();
let event_path = Path::new(plain_path);
let event_filename = event_path.file_name().unwrap();

// Reset reading position due to log rotation
if plain_path == logreader::AUDIT_LOG_PATH && op == Op::CHMOD {
last_position = 0;
}
let current_date = OffsetDateTime::now_utc();
let index_name = format!("fim-{}-{}-{}", current_date.year(), current_date.month() as u8, current_date.day() );
let current_timestamp = format!("{:?}", SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_millis());
let current_hostname = utils::get_hostname();
let kind = event.kind.clone();
let path = event.paths[0].clone();

// If the event comes from audit.log
if plain_path == logreader::AUDIT_LOG_PATH {
// Getting events from audit.log
let mut events = Vec::new();
let (event, position) = logreader::read_log(String::from(logreader::AUDIT_LOG_PATH), config.clone(), last_position, 0);
if event.id != "0" { events.push(event); };
let mut ctr = 0;
last_position = position;
while last_position < utils::get_file_end(logreader::AUDIT_LOG_PATH, 0) {
debug!("Reading events, iteration: {}", ctr);
ctr += 1;
let (evt, pos) = logreader::read_log(String::from(logreader::AUDIT_LOG_PATH), config.clone(), last_position, ctr);
if evt.id != "0" {
events.push(evt);
ctr = 0;
};
last_position = pos;
// Reset reading position due to log rotation
if plain_path == logreader::AUDIT_LOG_PATH && kind == EventKind::Access(AccessKind::Any) {
last_position = 0;
}
debug!("Events read from audit log, position: {}", last_position);

for audit_event in events {
if ! audit_event.is_empty() {
// Getting the position of event in config (match ignore and labels)
let index = config.get_index(audit_event.clone().path.as_str(),
audit_event.clone().cwd.as_str(),
config.audit.clone().to_vec());

if index != usize::MAX {
// If event contains ignored string ignore event
if ! config.match_ignore(index,
audit_event.clone().file.as_str(),
config.audit.clone()) {
audit_event.process(destination.clone().as_str(), index_name.clone(), config.clone()).await;

// If the event comes from audit.log
if plain_path == logreader::AUDIT_LOG_PATH {
// Getting events from audit.log
let mut events = Vec::new();
let (event, position) = logreader::read_log(String::from(logreader::AUDIT_LOG_PATH), config.clone(), last_position, 0);
if event.id != "0" { events.push(event); };
let mut ctr = 0;
last_position = position;
while last_position < utils::get_file_end(logreader::AUDIT_LOG_PATH, 0) {
debug!("Reading events, iteration: {}", ctr);
ctr += 1;
let (evt, pos) = logreader::read_log(String::from(logreader::AUDIT_LOG_PATH), config.clone(), last_position, ctr);
if evt.id != "0" {
events.push(evt);
ctr = 0;
};
last_position = pos;
}
debug!("Events read from audit log, position: {}", last_position);

for audit_event in events {
if ! audit_event.is_empty() {
// Getting the position of event in config (match ignore and labels)
let index = config.get_index(audit_event.clone().path.as_str(),
audit_event.clone().cwd.as_str(),
config.audit.clone().to_vec());

if index != usize::MAX {
// If event contains ignored string ignore event
if ! config.match_ignore(index,
audit_event.clone().file.as_str(),
config.audit.clone()) {
audit_event.process(destination.clone().as_str(), index_name.clone(), config.clone()).await;
}else{
debug!("Event ignored not stored in alerts");
}
}else{
debug!("Event ignored not stored in alerts");
debug!("Event not monitored by FIM");
}
}else{
debug!("Event not monitored by FIM");
}
debug!("Event processed: {:?}", audit_event.clone());
}
debug!("Event processed: {:?}", audit_event.clone());
}
}else {
let index = config.get_index(event_path.to_str().unwrap(), "", config.monitor.clone().to_vec());
if index != usize::MAX {
let labels = config.get_labels(index, config.monitor.clone());
if ! config.match_ignore(index,
event_filename.to_str().unwrap(), config.monitor.clone()){
let event = event::Event {
id: utils::get_uuid(),
timestamp: current_timestamp,
hostname: current_hostname,
node: config.node.clone(),
version: String::from(config::VERSION),
op,
path: path.clone(),
labels,
operation: event::get_op(op),
checksum: hash::get_checksum( String::from(path.to_str().unwrap()) ),
fpid: utils::get_pid(),
system: config.system.clone()
};

debug!("Event processed: {:?}", event);
event.process(destination.clone().as_str(), index_name.clone(), config.clone()).await;
}else {
let index = config.get_index(event_path.to_str().unwrap(), "", config.monitor.clone().to_vec());
if index != usize::MAX {
let labels = config.get_labels(index, config.monitor.clone());
if ! config.match_ignore(index,
event_filename.to_str().unwrap(), config.monitor.clone()){
let event = event::Event {
id: utils::get_uuid(),
timestamp: current_timestamp,
hostname: current_hostname,
node: config.node.clone(),
version: String::from(config::VERSION),
kind: kind.clone(),
path: path.clone(),
labels,
operation: event::get_operation(kind.clone()),
detailed_operation: event::get_detailed_operation(kind),
checksum: hash::get_checksum( String::from(path.to_str().unwrap()) ),
fpid: utils::get_pid(),
system: config.system.clone()
};

debug!("Event processed: {:?}", event);
event.process(destination.clone().as_str(), index_name.clone(), config.clone()).await;
}else{
debug!("Event ignored not stored in alerts");
}
}else{
debug!("Event ignored not stored in alerts");
debug!("Event not matched monitor");
}
}else{
debug!("Event not matched monitor");
}
},
Err(e) => {
error!("Watch for event failed, error: {:?}", e);
}
},
Err(e) => {
error!("Watch for event failed, error: {:?}", e);
}
}
}
Expand Down
15 changes: 8 additions & 7 deletions src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@

// To manage aynchronous functions
use futures::executor::block_on;
use notify::{Op, RawEvent};
use notify::event::{Event, EventKind, EventAttributes};
// Monitor functions
use crate::monitor;
// To log the program process
use log::error;
use std::{
ffi::OsString,
sync::mpsc,
time::Duration, path::PathBuf,
time::Duration,
path::PathBuf,
};
use windows_service::{
define_windows_service,
Expand Down Expand Up @@ -70,11 +71,11 @@ pub fn run_service() -> Result<()> {

// Handle stop
ServiceControl::Stop => {
signal_handler.send(RawEvent {
path: Some(PathBuf::from("DISCONNECT")),
op: Ok(Op::WRITE),
cookie: Some(0)
}).unwrap();
signal_handler.send(Ok(Event {
paths: vec![PathBuf::from("DISCONNECT")],
kind: EventKind::Any,
attrs: EventAttributes::new()
})).unwrap();
ServiceControlHandlerResult::NoError
},

Expand Down
Loading