Files
Linux-Hello/linux-hello-daemon/src/main.rs
eliott e359d71db4 feat: wire TPM-backed encrypted template storage into auth pipeline
Replace plain TemplateStore with SecureTemplateStore in the auth
service. Templates are now encrypted with AES-256-GCM via TPM2 when
available, falling back to software encryption with PBKDF2 key
derivation (600k iterations) otherwise.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:23:12 +02:00

172 lines
5.6 KiB
Rust

//! Linux Hello Daemon
//!
//! Main daemon process for face authentication. Handles camera capture,
//! face detection, anti-spoofing checks, and template matching.
//!
//! The daemon provides two communication interfaces:
//! - IPC (Unix socket): For PAM module authentication
//! - D-Bus: For desktop applications and system integration
mod camera;
mod detection;
use linux_hello_common::{Config, Result, TemplateStore};
use linux_hello_daemon::auth::AuthService;
use linux_hello_daemon::dbus_server::{check_system_bus_available, DbusServer};
use linux_hello_daemon::ipc::IpcServer;
use linux_hello_daemon::secure_template_store::SecureTemplateStore;
use tracing::{error, info, warn, Level};
use tracing_subscriber::FmtSubscriber;
#[tokio::main]
async fn main() -> Result<()> {
// Initialize logging
let _subscriber = FmtSubscriber::builder()
.with_max_level(Level::INFO)
.with_target(false)
.init();
info!("Linux Hello Daemon starting...");
// Load configuration
let config = Config::load_or_default();
info!("Configuration loaded");
info!(" Camera device: {}", config.camera.device);
info!(" Detection model: {}", config.detection.model);
info!(" Anti-spoofing enabled: {}", config.anti_spoofing.enabled);
// Initialize camera
#[cfg(target_os = "linux")]
{
match camera::enumerate_cameras() {
Ok(cameras) => {
info!("Found {} camera(s)", cameras.len());
for cam in &cameras {
info!(" - {}", cam);
}
}
Err(e) => {
warn!("Camera enumeration failed: {}", e);
}
}
}
#[cfg(not(target_os = "linux"))]
{
info!("Camera functions not available on this platform");
info!("V4L2 camera support requires Linux");
}
// Initialize face detection
info!("Face detection module initialized (placeholder)");
// Initialize authentication service
let template_path = std::env::var("LINUX_HELLO_TEMPLATES")
.map(std::path::PathBuf::from)
.unwrap_or_else(|_| SecureTemplateStore::default_path());
let auth_service = AuthService::with_paths(config.clone(), template_path.clone());
auth_service.initialize()?;
info!("Authentication service initialized (Templates: {})", template_path.display());
// Start IPC server
let socket_path = std::env::var("LINUX_HELLO_SOCKET")
.map(std::path::PathBuf::from)
.unwrap_or_else(|_| IpcServer::default_socket_path());
let mut ipc_server = IpcServer::new(socket_path.clone());
// Set authentication handler
let auth_service_for_auth = auth_service.clone();
ipc_server.set_auth_handler(move |user| {
let auth_service = auth_service_for_auth.clone();
async move { auth_service.authenticate(&user).await }
});
// Set enrollment handler
let auth_service_for_enroll = auth_service.clone();
ipc_server.set_enroll_handler(move |user, label, frame_count| {
let auth_service = auth_service_for_enroll.clone();
async move { auth_service.enroll(&user, &label, frame_count).await }
});
// Set list handler
let template_path_for_list = template_path.clone();
ipc_server.set_list_handler(move |user| {
let template_path = template_path_for_list.clone();
async move {
let store = TemplateStore::new(template_path);
store.list_templates(&user)
}
});
// Set remove handler
let template_path_for_remove = template_path.clone();
ipc_server.set_remove_handler(move |user, label, all| {
let template_path = template_path_for_remove.clone();
async move {
let store = TemplateStore::new(template_path);
if all {
store.remove_all(&user)
} else if let Some(l) = label {
store.remove(&user, &l)
} else {
Err(linux_hello_common::Error::Config(
"No label specified".to_string(),
))
}
}
});
// Initialize D-Bus server (optional - will fail gracefully if system bus unavailable)
let dbus_enabled = check_system_bus_available().await;
let mut dbus_server = DbusServer::new();
if dbus_enabled {
match dbus_server
.start(auth_service.clone(), config.clone())
.await
{
Ok(()) => {
info!("D-Bus server started successfully");
info!(" Service: org.linuxhello.Daemon");
info!(" Object path: /org/linuxhello/Manager");
}
Err(e) => {
warn!("Failed to start D-Bus server: {}", e);
warn!("D-Bus interface will not be available");
}
}
} else {
info!("System D-Bus not available, skipping D-Bus server");
}
info!("Linux Hello Daemon ready");
info!("Listening for authentication requests...");
if dbus_enabled && dbus_server.is_connected() {
info!(" - IPC: {}", socket_path.display());
info!(" - D-Bus: org.linuxhello.Daemon");
} else {
info!(" - IPC: {}", socket_path.display());
}
// Start IPC server as a task
let ipc_future = ipc_server.start();
// Wait for shutdown signal or server error
// Both IPC and D-Bus run concurrently using tokio
tokio::select! {
_ = tokio::signal::ctrl_c() => {
info!("Shutdown signal received");
}
result = ipc_future => {
if let Err(e) = result {
error!("IPC server error: {}", e);
}
}
}
info!("Linux Hello Daemon shutting down");
Ok(())
}