Skip to content

Commit

Permalink
Deploy Trust (#85)
Browse files Browse the repository at this point in the history
Write ancillary trust file and signal fapolicyd to reload.

Steps applied during deployment

    back up trust file to user data dir
    write ancillary state to the fapolicyd.trust file
    signal fapolicyd

Required a bit of additional configuration work to sketch in the application config. The app config consists of user specific settings and paths. For example in this PR is the users application data directory where we will store backup snapshots of the trust file.

This is not currently taking a backup of the fapolicyd lmdb directory, only the ancillary trust file. It may be determined that the fapolicyd db needs a snapshot as well, but for now there is no need for that.

closes #41
closes #42
  • Loading branch information
jw3 committed Apr 13, 2021
1 parent 56938fb commit 4a7a7a3
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 24 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -14,3 +14,4 @@ dbus = "0.9.1"
lmdb-rkv = "0.14.0"
confy = "0.4.0"
serde = { version = "1.0", features = ["derive"] }
directories = "2.0.2"
1 change: 1 addition & 0 deletions python/Cargo.lock

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

42 changes: 34 additions & 8 deletions python/examples/changeset.py
@@ -1,16 +1,42 @@
from fapolicy_analyzer import *
import pathlib
import itertools as it
from fapolicy_analyzer import *

# config is loaded from $HOME/.config/fapolicy-analyzer/fapolicy-analyzer.toml

# a system represents the state of the host sytems
s1 = System()
print(f"system1 has {len(s1.ancillary_trust())} trust entries")

xs = Changeset()
for p in pathlib.Path("/bin").iterdir():
xs.add_trust(str(p))
print(f"adding {xs.len()} trust entries")
# changeset represents changes to trust
xs1 = Changeset()
for p in it.islice(pathlib.Path("/bin").iterdir(), 5):
xs1.add_trust(str(p))
print(f"adding {xs1.len()} trust entries")

# changesets are inexpensive
xs2 = Changeset()
for p in it.islice(pathlib.Path("/bin").iterdir(), 5, 10):
xs2.add_trust(str(p))
print(f"adding {xs2.len()} trust entries")

s2 = s1.apply_changeset(xs)
# changesets get applied to a system, producing a new system
s2 = s1.apply_changeset(xs1)
print(f"system2 has {len(s2.ancillary_trust())} trust entries")
for t in s2.ancillary_trust():
print(f"{t.status} {t.path} {t.size} {t.hash}")

# the new system can have changes applied to it
s3 = s2.apply_changeset(xs2)
print(f"system3 has {len(s3.ancillary_trust())} trust entries")

# a system is deployed, updating the fapolicyd ancillary trust
# s2.deploy()

# the output is
# ==================================
# system1 has 0 trust entries
# adding 5 trust entries
# adding 5 trust entries
# applying changeset to current state...
# system2 has 5 trust entries
# applying changeset to current state...
# system3 has 10 trust entries
8 changes: 8 additions & 0 deletions python/examples/show_ancillary.py
@@ -0,0 +1,8 @@
from fapolicy_analyzer import *

# config is loaded from $HOME/.config/fapolicy-analyzer/fapolicy-analyzer.toml
s1 = System()
for t in s1.ancillary_trust():
print(f"{t.path} {t.size} {t.hash}")

print(f"found {len(s1.ancillary_trust())} ancillary trust entries")
6 changes: 3 additions & 3 deletions python/src/app.rs
Expand Up @@ -29,8 +29,8 @@ impl From<PySystem> for State {
impl PySystem {
#[new]
fn new() -> PySystem {
let conf = cfg::load();
State::new(&conf.system).into()
let conf = cfg::All::default();
State::new(&conf).into()
}

fn system_trust(&self) -> Vec<PyTrust> {
Expand Down Expand Up @@ -60,7 +60,7 @@ impl PySystem {
}

fn deploy(&self) {
deploy_app_state(&self.state);
deploy_app_state(&self.state).expect("deployment failed")
}

fn is_stale(&self) -> bool {
Expand Down
28 changes: 24 additions & 4 deletions src/app.rs
@@ -1,24 +1,26 @@
use directories::ProjectDirs;
use serde::Deserialize;
use serde::Serialize;

use crate::api::{Trust, TrustSource};
use crate::sys::Config;
use crate::cfg::All;
use crate::cfg::PROJECT_NAME;
use crate::trust::load_trust_db;
use crate::trust::Changeset;

/// Represents an immutable view of the application state.
/// Carries along the configuration that provided the state.
#[derive(Clone, Serialize, Deserialize)]
pub struct State {
pub config: Config,
pub config: All,
pub trust_db: Vec<Trust>,
}

impl State {
pub fn new(cfg: &Config) -> State {
pub fn new(cfg: &All) -> State {
State {
config: cfg.clone(),
trust_db: load_trust_db(&cfg.trust_db_path),
trust_db: load_trust_db(&cfg.system.trust_db_path),
}
}

Expand All @@ -43,3 +45,21 @@ impl State {
}
}
}

#[derive(Clone, Serialize, Deserialize)]
pub struct Config {
pub data_dir: String,
}

impl Default for Config {
fn default() -> Self {
let proj_dirs =
ProjectDirs::from("rs", "", PROJECT_NAME).expect("failed to init project dirs");

let dd = proj_dirs.data_dir();

Self {
data_dir: dd.to_path_buf().into_os_string().into_string().unwrap(),
}
}
}
10 changes: 8 additions & 2 deletions src/cfg.rs
@@ -1,14 +1,20 @@
use serde::Deserialize;
use serde::Serialize;

use crate::app;
use crate::sys;

pub const PROJECT_NAME: &str = "fapolicy-analyzer";

/// All configuration loaded from the user toml under XDG config dir
#[derive(Clone, Serialize, Deserialize, Default)]
pub struct All {
pub system: sys::Config,
pub application: app::Config,
}

pub fn load() -> All {
confy::load("fapolicy-analyzer").expect("unable to load user configuration")
impl All {
pub fn data_dir(&self) -> &str {
self.application.data_dir.as_str()
}
}
4 changes: 2 additions & 2 deletions src/fapolicyd.rs
Expand Up @@ -18,9 +18,9 @@ pub fn reload_databases() {
.write(true)
.read(false)
.open(FIFO_PIPE)
.unwrap()
.expect("unable to open fifo pipe")
.write_all("1".as_bytes())
.unwrap();
.expect("unable to write fifo pipe");
}

/// filtering logic as implemented by fapolicyd rpm backend
Expand Down
19 changes: 14 additions & 5 deletions src/sys.rs
@@ -1,21 +1,30 @@
use serde::Deserialize;
use serde::Serialize;

use crate::api::TrustSource;
use crate::app::State;
use crate::fapolicyd;
use std::fs::File;
use std::io::Write;

pub fn deploy_app_state(_state: &State) {
pub fn deploy_app_state(state: &State) -> Result<(), String> {
// todo;; back up trust file
println!("backing up trust file...");

// todo;; write changeset
println!("writing changeset to disk...");
let mut tf = File::create(&state.config.system.ancillary_trust_path)
.expect("unable to create ancillary trust");
for t in &state.trust_db {
if t.source == TrustSource::Ancillary {
tf.write_all(format!("{} {} {}\n", t.path, t.size.to_string(), t.hash).as_bytes())
.expect("unable to write ancillary trust file")
}
}

// todo;; signal fapolicyd update
println!("signaling fapolicdy reload...");
fapolicyd::reload_databases();

// todo;; return new Application
println!("reloading app trust database...");
Ok(())
}

/// host system configuration information
Expand Down

0 comments on commit 4a7a7a3

Please sign in to comment.