Skip to main content

auc_tool/
agent.rs

1use std::sync::Arc;
2use std::sync::atomic::AtomicBool;
3
4use anyhow::{Context, Result, bail};
5use capulus::managed::{
6    ActivatedListeners, ManagedAgent, ManagementServer, ManagementServerOptions,
7};
8
9use crate::application::{ApplicationServer, AucApplication, LocalSessionAuthorizer};
10use crate::authenticator::PresenceGate;
11use crate::product::{application_agent_info, managed_product};
12use crate::release::AucReleaseSource;
13use crate::transport::run_uhid;
14use crate::vault::Vault;
15
16pub fn run() -> Result<()> {
17    require_root()?;
18    let listeners = ActivatedListeners::from_environment(&["application", "capulus"])
19        .context("failed to adopt auc systemd sockets")?;
20    runtime()?.block_on(serve(listeners))
21}
22
23pub fn runtime() -> Result<tokio::runtime::Runtime> {
24    tokio::runtime::Builder::new_multi_thread()
25        .enable_all()
26        .thread_name("auc-agent")
27        .build()
28        .context("failed to create the auc async runtime")
29}
30
31pub fn application_health() -> Result<capulus::managed::AgentInfo> {
32    let product = managed_product()?;
33    application_agent_info()
34        .with_context(|| format!("{} application health check failed", product.name()))
35}
36
37pub fn require_root() -> Result<()> {
38    if rustix::process::geteuid().is_root() {
39        Ok(())
40    } else {
41        bail!("auc agent operations must run as root")
42    }
43}
44
45async fn serve(mut listeners: ActivatedListeners) -> Result<()> {
46    let application_listener = listeners.take_tokio("application")?;
47    let management_listener = listeners.take_tokio("capulus")?;
48    if !listeners.is_empty() {
49        bail!("auc agent retained an unexpected systemd listener");
50    }
51    let product = Arc::new(managed_product()?);
52    let vault = Vault::open()?;
53    let presence = PresenceGate::new();
54    let device_present = Arc::new(AtomicBool::new(false));
55    let application = Arc::new(AucApplication::new(
56        vault.clone(),
57        presence.clone(),
58        Arc::clone(&device_present),
59        LocalSessionAuthorizer::connect().await?,
60    ));
61    let management = Arc::new(ManagedAgent::new(
62        Arc::clone(&product),
63        Arc::new(AucReleaseSource::new()?),
64    )?);
65    let application_server = ApplicationServer::new(application_listener, application);
66    let management_server = ManagementServer::new(
67        management_listener,
68        management,
69        ManagementServerOptions::default(),
70    )?;
71    let transport = tokio::task::spawn_blocking(move || run_uhid(vault, presence, device_present));
72
73    tokio::select! {
74        result = application_server.run() => result.context("auc application server stopped"),
75        result = management_server.run() => result.context("auc management server stopped"),
76        result = transport => result
77            .context("auc UHID task panicked")?
78            .context("auc UHID transport stopped"),
79    }
80}