System Contracts

Stable contracts. Do not change without updating this document.

Binaries

BinaryCratePurpose
facelockfacelock-cliUnified CLI (daemon, auth, enroll, test, setup, etc.)
pam_facelock.sopam-facelockPAM authentication module
facelock-polkit-agentfacelock-polkitPolkit face authentication agent (not production-ready — do not autostart; will steal polkit auth from the DE's agent)

CLI Subcommands

CommandPurpose
facelock setupDownload models, create directories
facelock setup --systemdInstall/enable systemd units
facelock setup --pamInstall PAM module to /etc/pam.d/
facelock enrollCapture and store a face
facelock testTest face recognition
facelock listList enrolled face models
facelock remove <id>Remove a specific model
facelock clearRemove all models for a user
facelock previewLive camera preview
facelock devicesList V4L2 cameras
facelock statusCheck system status
facelock configShow/edit configuration
facelock daemonRun persistent daemon
facelock auth --user XOne-shot auth (PAM helper)
facelock tpm statusTPM status
facelock encryptEncrypt face database
facelock decryptDecrypt face database
facelock auditView audit log
facelock benchBenchmarks
facelock restartRestart daemon

Operating Modes

ModeConfigPAM BehaviorCLI Behavior
Daemondaemon.mode = "daemon" (default)D-Bus IPC to daemonUses daemon if available, falls back to direct
Oneshotdaemon.mode = "oneshot"Spawns facelock authOperates directly (no daemon)

The CLI silently falls back to direct mode when the daemon is not available on D-Bus, regardless of config mode.

facelock auth Exit Codes

CodeMeaningPAM Code
0Face matchedPAM_SUCCESS
1No match / timeout / darkPAM_AUTH_ERR
2Error / no enrolled facesPAM_IGNORE

Filesystem Paths

PathOwnerModePurpose
/etc/facelock/config.tomlroot:root644Configuration
/var/lib/facelock/facelock.dbroot:facelock640Face embeddings
/var/lib/facelock/models/root:root755ONNX models
/var/log/facelock/snapshots/root:facelock750Auth snapshots
/usr/bin/facelockroot:root755CLI binary
/lib/security/pam_facelock.soroot:root755PAM module

All paths overridable via config. FACELOCK_CONFIG is honored for unprivileged processes, but privileged PAM/root auth flows ignore the environment and use either an explicit --config path or /etc/facelock/config.toml.

Config Schema

TOML format. All keys optional -- camera auto-detected, sensible defaults for everything. See Configuration for the full reference.

Sections

SectionKey fields
[device]path (Option), max_height, rotation, warmup_frames, dark_threshold, dark_pixel_value, ir_emitter, camera_release_secs
[recognition]threshold, timeout_secs, detector_model, embedder_model, threads, execution_provider
[daemon]mode (DaemonMode enum), model_dir, idle_timeout_secs
[storage]db_path
[security]disabled, suppress_unknown, require_ir, require_frame_variance, min_auth_frames, abort_if_ssh, abort_if_lid_closed, rate_limit sub-section
[notification]mode (off/terminal/desktop/both), notify_prompt, notify_on_success, notify_on_failure
[snapshots]mode (off/all/failure/success), dir
[encryption]method (none/keyfile/tpm), key_path, sealed_key_path
[audit]enabled, path, rotate_size_mb
[tpm]pcr_binding, pcr_indices, tcti

Camera Auto-Detection

When device.path is omitted:

  1. Enumerate /dev/video0 through /dev/video63
  2. Filter to VIDEO_CAPTURE devices
  3. Prefer IR cameras (name contains "ir"/"infrared", or supports GREY/Y16 format)
  4. Fall back to first available device

Database Schema

SQLite with WAL mode and foreign keys:

CREATE TABLE face_models (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user TEXT NOT NULL,
    label TEXT NOT NULL,
    created_at INTEGER NOT NULL,
    UNIQUE(user, label)
);

CREATE TABLE face_embeddings (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    model_id INTEGER NOT NULL REFERENCES face_models(id) ON DELETE CASCADE,
    embedding BLOB NOT NULL,  -- 512 x f32 = 2048 bytes (or encrypted blob)
    sealed INTEGER NOT NULL DEFAULT 0
);

CREATE TABLE rate_limit (
    user TEXT NOT NULL,
    attempt_time INTEGER NOT NULL
);

Only failed authentication attempts are recorded in rate_limit. Daemon mode and oneshot mode share the same SQLite-backed window, so daemon restarts do not clear lockout state.

IPC Protocol

D-Bus system bus (org.facelock.Daemon). Only used in daemon mode. The daemon exposes a D-Bus interface on the system bus, and both the PAM module and CLI connect as D-Bus clients. Access is controlled by D-Bus system bus policy (/etc/dbus-1/system.d/org.facelock.Daemon.conf).

Methods

Authenticate, Enroll, ListModels, RemoveModel, ClearModels, PreviewFrame, PreviewDetectFrame, ListDevices, ReleaseCamera, Ping, Shutdown

Return Types

AuthResult, Enrolled, Models, Removed, Frame, DetectFrame, Devices, Ok, Error

PAM Semantics

OutcomePAM Code
Face matchedPAM_SUCCESS (0)
No matchPAM_AUTH_ERR (7)
Daemon unavailable / errorPAM_IGNORE (25)
TimeoutPAM_AUTH_ERR (7)

PAM module never blocks indefinitely. All operations have timeouts.

Syslog Format

pam_facelock(<service>): <result> for user <username>

Anti-Spoofing

DefenseConfigDefault
IR camera enforcementsecurity.require_irtrue
Frame variance checksecurity.require_frame_variancetrue
Landmark livenesssecurity.require_landmark_livenessfalse
Minimum auth framessecurity.min_auth_frames3
Variance thresholdFRAME_VARIANCE_THRESHOLD0.998

These defaults must not be weakened without security review.

Models

ModelFileSizeDefault
SCRFD 2.5Gscrfd_2.5g_bnkps.onnx~3MBYes
ArcFace R50w600k_r50.onnx~166MBYes
SCRFD 10Gdet_10g.onnx~17MBOptional
ArcFace R100glintr100.onnx~249MBOptional

Configurable via recognition.detector_model and recognition.embedder_model.