use anyhow::{Context, Result}; use std::sync::Arc; use tracing::{info, warn}; mod dbus; mod fido; mod lockout; mod policy_apply; mod polkit; mod recovery; mod state; mod storage; const BUS_NAME: &str = "io.dangerousthings.AuthForge"; const OBJECT_PATH: &str = "/io/dangerousthings/AuthForge"; #[tokio::main] async fn main() -> Result<()> { tracing_subscriber::fmt() .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) .init(); info!("authforged {} starting", env!("CARGO_PKG_VERSION")); let conn = zbus::Connection::system() .await .context("connecting to system D-Bus")?; let polkit = if std::env::var("AUTHFORGE_POLKIT_BYPASS").is_ok() { warn!( "AUTHFORGE_POLKIT_BYPASS set — polkit checks are DISABLED. Do not use in production." ); polkit::Polkit::permissive() } else { polkit::Polkit::system(conn.clone()).await }; let cfg = state::StorageConfig::from_env_or_defaults(); let policy_dir = cfg.policy_dir.clone(); let authn: Arc = Arc::new(fido::ctap::CtapAuthenticator::new()); let state = Arc::new(state::AppState::open(cfg, authn)?); let auth = dbus::AuthForge { state: state.clone(), polkit: Arc::new(polkit), }; conn.object_server().at(OBJECT_PATH, auth).await?; conn.request_name(BUS_NAME) .await .context("acquiring well-known bus name (another instance running?)")?; info!("listening on D-Bus as {BUS_NAME} at {OBJECT_PATH}"); // Inotify watcher → PolicyChanged signal. let policy_store = storage::policy::PolicyStore::new(policy_dir.clone()); match policy_store.watch() { Ok((watcher, mut rx)) => { let conn_for_signal = conn.clone(); tokio::spawn(async move { while rx.changed().await.is_ok() { let iface_ref = match conn_for_signal .object_server() .interface::<_, dbus::AuthForge>(OBJECT_PATH) .await { Ok(r) => r, Err(e) => { warn!(error=%e, "no AuthForge interface; skipping signal"); continue; } }; if let Err(e) = dbus::AuthForge::policy_changed(iface_ref.signal_context()).await { warn!(error=%e, "PolicyChanged emit failed"); } } }); // Daemon lives until SIGTERM; deliberately leak to keep watcher alive. std::mem::forget(watcher); info!("watching {} for policy changes", policy_dir.display()); } Err(e) => warn!(error=%e, "failed to start policy.d watcher"), } // Park forever. systemd will SIGTERM the process when stopping the unit. std::future::pending::<()>().await; Ok(()) }