Skip to content
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
35 changes: 34 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ programs = \
${TARGETDIR}/${PROFILE}/crau-agent \
${TARGETDIR}/${PROFILE}/crau-client \
${TARGETDIR}/${PROFILE}/crau-event-broker \
${TARGETDIR}/${PROFILE}/crau-log-parser \
${TARGETDIR}/${PROFILE}/crau-query \
${TARGETDIR}/${PROFILE}/crau-monitor

conffiles = \
dist/conf/agent.conf \
dist/conf/client.conf \
dist/conf/event-broker.conf \
dist/conf/query.conf \
dist/conf/monitor.conf

.PHONY: all
Expand Down
1 change: 1 addition & 0 deletions dist/conf/query.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# log_file = "/var/log/crypto-auditing/audit.cborseq"
6 changes: 4 additions & 2 deletions log-parser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ serde.workspace = true
serde_cbor.workspace = true
serde_json.workspace = true
serde_with = { workspace = true, features = ["hex"] }
toml.workspace = true
pager = "0.16"

[[bin]]
name = "crau-log-parser"
path = "src/log_parser.rs"
name = "crau-query"
path = "src/query.rs"
89 changes: 89 additions & 0 deletions log-parser/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2022-2023 The crypto-auditing developers.

use anyhow::{Context as _, Result, anyhow};
use clap::{ArgMatches, arg, command, parser::ValueSource, value_parser};
use std::fs;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use toml::{Table, Value};

const CONFIG: &str = "/etc/crypto-auditing/query.conf";
const LOG: &str = "/var/log/crypto-auditing/audit.cborseq";

#[derive(Debug)]
pub struct Config {
/// Path to output log file
pub log_file: PathBuf,
}

impl Default for Config {
fn default() -> Self {
Self {
log_file: PathBuf::from(LOG),
}
}
}

impl Config {
pub fn new() -> Result<Self> {
let mut config = Config::default();

let matches = command!()
.arg(
arg!(
-c --config <FILE> "Path to configuration file"
)
.required(false)
.value_parser(value_parser!(PathBuf)),
)
.arg(
arg!(
--"log-file" <FILE> "Path to output log file"
)
.required(false)
.value_parser(value_parser!(PathBuf))
.default_value("audit.cborseq"),
)
.get_matches();

if let Some(config_file) = matches.get_one::<PathBuf>("config") {
config.merge_config_file(config_file)?;
} else if Path::new(CONFIG).exists() {
config.merge_config_file(CONFIG)?;
}

config.merge_arg_matches(&matches)?;

Ok(config)
}

fn merge_config_file(&mut self, file: impl AsRef<Path>) -> Result<()> {
let s = fs::read_to_string(file.as_ref())
.with_context(|| format!("unable to read config file `{}`", file.as_ref().display()))?;
let config = Table::from_str(&s).with_context(|| {
format!("unable to parse config file `{}`", file.as_ref().display())
})?;

if let Some(value) = config.get("log_file") {
self.log_file = pathbuf_from_value(value)?;
}

Ok(())
}

fn merge_arg_matches(&mut self, matches: &ArgMatches) -> Result<()> {
if let Some(ValueSource::CommandLine) = matches.value_source("log-file") {
self.log_file = matches.try_get_one::<PathBuf>("log-file")?.unwrap().clone();
}

Ok(())
}
}

fn pathbuf_from_value(value: &Value) -> Result<PathBuf> {
value
.as_str()
.ok_or_else(|| anyhow!("value must be string"))
.map(PathBuf::from)
}
28 changes: 15 additions & 13 deletions log-parser/src/log_parser.rs → log-parser/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,30 @@
// Copyright (C) 2022-2023 The crypto-auditing developers.

use anyhow::{Context as _, Result};
use clap::Parser;
use crypto_auditing::types::{ContextTracker, EventGroup};
use pager::Pager;
use serde_cbor::de::Deserializer;
use std::path::PathBuf;
use std::io::{self, Write};

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[command(about = "Primary log parser for crypto-auditing")]
struct Cli {
/// Path to log file to parse
log_path: PathBuf,
}
mod config;

fn main() -> Result<(), Box<dyn std::error::Error>> {
let cli = Cli::parse();
let log_file = std::fs::File::open(&cli.log_path)
.with_context(|| format!("unable to read file `{}`", cli.log_path.display()))?;
let config = config::Config::new()?;
Pager::new().skip_on_notty().setup();

let log_file = std::fs::File::open(&config.log_file)
.with_context(|| format!("unable to read file `{}`", config.log_file.display()))?;

let mut tracker = ContextTracker::new(None);
for group in Deserializer::from_reader(&log_file).into_iter::<EventGroup>() {
tracker.handle_event_group(&group?);
}
let root_contexts: Vec<_> = tracker.flush(None).into_iter().collect();
println!("{}", serde_json::to_string_pretty(&root_contexts).unwrap());
let content = serde_json::to_string_pretty(&root_contexts)?;
if let Err(e) = io::stdout().write_all(content.as_bytes()) {
if e.kind() != io::ErrorKind::BrokenPipe {
return Err(Box::new(e));
}
}
Ok(())
}