diff --git a/bffhd/audit.rs b/bffhd/audit.rs index d58884e..5c4c5fe 100644 --- a/bffhd/audit.rs +++ b/bffhd/audit.rs @@ -2,33 +2,41 @@ use std::fs::{File, OpenOptions}; use std::io; use std::io::{LineWriter, Write}; use std::sync::Mutex; +use once_cell::sync::OnceCell; use crate::Config; use serde::{Serialize, Deserialize}; use serde_json::Serializer; +pub static AUDIT: OnceCell = OnceCell::new(); + #[derive(Debug)] pub struct AuditLog { writer: Mutex>, } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct AuditLogLine { +pub struct AuditLogLine<'a> { timestamp: i64, - machine: String, - state: String, + machine: &'a str, + state: &'a str, } impl AuditLog { - pub fn new(config: &Config) -> io::Result { - let fd = OpenOptions::new().create(true).append(true).open(&config.auditlog_path)?; - let writer = Mutex::new(LineWriter::new(fd)); - Ok(Self { writer }) + pub fn new(config: &Config) -> io::Result<&'static Self> { + AUDIT.get_or_try_init(|| { + tracing::debug!(path = %config.auditlog_path.display(), "Initializing audit log"); + let fd = OpenOptions::new().create(true).append(true).open(&config.auditlog_path)?; + let writer = Mutex::new(LineWriter::new(fd)); + Ok(Self { writer }) + }) } pub fn log(&self, machine: &str, state: &str) -> io::Result<()> { let timestamp = chrono::Utc::now().timestamp(); - let line = AuditLogLine { timestamp, machine: machine.to_string(), state: state.to_string() }; + let line = AuditLogLine { timestamp, machine, state }; + + tracing::debug!(?line, "writing audit log line"); let mut guard = self.writer.lock().unwrap(); let mut writer: &mut LineWriter = &mut *guard; diff --git a/bffhd/lib.rs b/bffhd/lib.rs index 84c615f..de2ba9d 100644 --- a/bffhd/lib.rs +++ b/bffhd/lib.rs @@ -50,6 +50,7 @@ use once_cell::sync::OnceCell; use signal_hook::consts::signal::*; use executor::pool::Executor; +use crate::audit::AuditLog; use crate::authentication::AuthenticationHandle; use crate::authorization::roles::Roles; use crate::capnp::APIServer; @@ -93,6 +94,8 @@ impl Diflouroborane { let users = Users::new(env.clone()).context("Failed to open users DB file")?; let roles = Roles::new(config.roles.clone()); + let _audit_log = AuditLog::new(&config).context("Failed to initialize audit log")?; + let resources = ResourcesHandle::new(config.machines.iter().map(|(id, desc)| { Resource::new(Arc::new(resources::Inner::new(id.to_string(), statedb.clone(), desc.clone()))) })); diff --git a/bffhd/resources/mod.rs b/bffhd/resources/mod.rs index 1b42f68..ac5573b 100644 --- a/bffhd/resources/mod.rs +++ b/bffhd/resources/mod.rs @@ -7,6 +7,7 @@ use rkyv::{Archived, Deserialize}; use rkyv::option::ArchivedOption; use rkyv::ser::Serializer; use rkyv::ser::serializers::AllocSerializer; +use crate::audit::AUDIT; use crate::authorization::permissions::PrivilegesBuf; use crate::config::MachineDescription; use crate::db::ArchivedValue; @@ -75,6 +76,8 @@ impl Inner { self.db.put(&self.id.as_bytes(), &state).unwrap(); tracing::trace!("Updated DB, sending update signal"); + AUDIT.get().unwrap().log(self.id.as_str(), &format!("{}", state)); + self.signal.set(state); tracing::trace!("Sent update signal"); } diff --git a/bffhd/resources/modules/fabaccess.rs b/bffhd/resources/modules/fabaccess.rs index 8912c85..d30c4b9 100644 --- a/bffhd/resources/modules/fabaccess.rs +++ b/bffhd/resources/modules/fabaccess.rs @@ -1,4 +1,5 @@ - +use std::fmt; +use std::fmt::{Write, write}; use crate::utils::oid::ObjectIdentifier; use once_cell::sync::Lazy; use rkyv::{Archive, Archived, Deserialize, Infallible}; @@ -57,6 +58,19 @@ pub struct MachineState { pub previous: Option, } +impl fmt::Display for ArchivedMachineState { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.state { + ArchivedStatus::Free => f.write_str("free"), + ArchivedStatus::InUse(user) => write!(f, "inuse {}", user), + ArchivedStatus::ToCheck(user) => write!(f, "tocheck {}", user), + ArchivedStatus::Blocked(user) => write!(f, "blocked {}", user), + ArchivedStatus::Disabled => f.write_str("disabled"), + ArchivedStatus::Reserved(user) => write!(f, "reserved {}", user), + } + } +} + impl MachineState { pub fn new() -> Self { Self { diff --git a/bffhd/resources/state/mod.rs b/bffhd/resources/state/mod.rs index 5d244e1..1d5ccb6 100644 --- a/bffhd/resources/state/mod.rs +++ b/bffhd/resources/state/mod.rs @@ -31,6 +31,7 @@ pub struct State { pub inner: MachineState, } + impl fmt::Debug for State { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut sf = f.debug_struct("State"); @@ -42,6 +43,12 @@ impl fmt::Debug for State { } } +impl fmt::Display for ArchivedState { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + Display::fmt(&self.inner, f) + } +} + impl serde::Serialize for State { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer diff --git a/bffhd/users/mod.rs b/bffhd/users/mod.rs index 364684a..18c36a2 100644 --- a/bffhd/users/mod.rs +++ b/bffhd/users/mod.rs @@ -3,6 +3,7 @@ use lmdb::Environment; use once_cell::sync::OnceCell; use rkyv::{Archive, Deserialize, Infallible, Serialize}; use std::collections::HashMap; +use std::fmt::{Display, Formatter, Write}; use std::ops::Deref; use std::path::Path; use std::sync::Arc; @@ -41,6 +42,12 @@ impl PartialEq for ArchivedUserRef { } } +impl Display for ArchivedUserRef { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(self.id.as_str()) + } +} + impl UserRef { pub fn new(id: String) -> Self { UserRef { id }