Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

lock

The session lock: whether it is held, authentication progress and the last failure.

The lock screen itself is a lock surface; this capability locks the session and relays PAM’s conversation. PAM starts when the session locks: prompt is its own question ("Password: ", a verification code) and messages its info and error lines. The one secure field answers every prompt; bind its masked to not prompt.echo so a visible answer shows.

With fprintd and an enrolled finger, a fingerprint unlocks too. A second conversation on the mantle-fingerprint PAM service runs beside the password, and the first to succeed unlocks. fingerprint is nil while it is off, else { messages } with pam_fprintd’s lines such as “Place your finger”. It is briefly non-nil on every lock even without a reader, since the worker exits within milliseconds, so draw a fingerprint icon only once fingerprint.messages is non-empty.

rect {
    on_click = function() mantle.lock:lock() end,
    children = { text { content = "Lock" } },
}

State

mantle.lock:get() returns LockState, nil before the first push. A field marked ? may be absent.

mantle.lock’s payload.

FieldTypeDescription
activebooleanThe Renderer confirmed the session locked; a requested lock stays false until then.
attemptsintegerRejected passwords since this lock was confirmed; reset by the next lock.
authenticatingbooleanAn answer is with PAM, or typed before its prompt and held for it. A second submit is refused while true.
errorstringLast failure to draw: PAM’s verdict ("authentication failed", "too many attempts", or a PAM or worker error) or a refused lock’s reason. Cleared by a correct password, lock, a confirmed lock, and unlock.
fingerprint?FingerprintStateThe fingerprint conversation beside the password one, or nil while none runs: no mantle-fingerprint stack, or it ended without a match. A password submit and the next lock start it again. prompt, messages, attempts and error stay the password’s.
messagesPamNotice[]PAM’s info and error lines, oldest first, at most 8. Cleared by the next answer and when the lock ends.
prompt?PamPromptPAM’s pending question, or nil while it owes nothing.
unlockingbooleanPAM said yes and the lock is still up: the window for an out-animation.

FingerprintState

mantle.lock.fingerprint while its conversation runs.

FieldTypeDescription
messagesPamNotice[]pam_fprintd’s lines, such as “Place your finger” or “Failed to match”, oldest first, at most 8. Translated: show them, never match on them.

PamNotice

One line a PAM module showed without asking anything, e.g. a fingerprint hint or a lockout.

FieldTypeDescription
kindPamNoticeKind"info" or "error".
textstringWhat the module said, as it said it.

PamNoticeKind

What a PamNotice reports.

One of "info", "error".

PamPrompt

A question a PAM module asked.

FieldTypeDescription
echobooleanThe answer is meant to be seen: set the secure field’s masked to not echo.
idintegerUnique for this session, so two identical prompts in a row still differ.
textstringPAM’s own text, e.g. "Password: " or "Verification code:".

Actions

Call each as mantle.lock:<action>(arguments...); ? marks an argument you may omit.

mantle.lock actions. There is no unlock; only a correct password unlocks.

ActionArgumentsDescription
lockLocks the session; a no-op while active.
set_unlock_animationms?: integerKeeps the lock up ms after a correct password for an out-animation. Clamped to 600; omitted is 0.

Backend

ContractBehavior
OwnershipThe Supervisor decides lock and unlock; the Renderer holds and paints ext_session_lock_v1. Built at boot, unlike other capabilities
TriggersThe lock action, and logind’s Lock signal (loginctl lock-session). logind’s Unlock is logged and ignored. Each lock and unlock sets logind’s LockedHint
UnlockOnly a successful PAM conversation, run in a re-exec’d worker with the mantle PAM service from /etc/pam.d or /usr/lib/pam.d, else login. PAM must reply within 30 s of an answer; a prompt waits for you without limit. An expired password still unlocks
ConversationStarts on lock and again after a wrong password. A failure before any prompt (a faillock lockout) waits for the next submit. An answer typed before its prompt goes to the next masked prompt; a visible prompt drops it
FingerprintStarts on lock when mantle-fingerprint is in /etc/pam.d or /usr/lib/pam.d, with no fallback service. pam_fprintd retries misses for the whole lock. Any other end, or a prompt from that stack, turns it off until the next password submit or lock. Misses never count as attempts or set error. Packages install the stack
Unlock animationset_unlock_animation delays the release by up to 600 ms; the value persists across reloads
CrashA dead Renderer never unlocks; the replacement retakes the lock. $XDG_RUNTIME_DIR/mantle/session-locked carries the lock across a Supervisor restart
Refused or lostSets mantle.rescue with the reason
ReloadAn edit that would recreate a lock surface is refused while locked (lock surface)

How do I…

TaskAnswer
Show “wrong password”error and attempts: lock surface example
Ask for a second factorShow prompt.text above the field and set masked = lock:map(function(l) return not (l.prompt and l.prompt.echo) end, true)
Show a lockout noticemessages, each { kind = "info" or "error", text }, cleared by the next answer
Show a fingerprint hintfingerprint.messages, the same shape, when fingerprint is not nil: Lock screen recipe
Turn fingerprint offReplace the content of /etc/pam.d/mantle-fingerprint with auth requisite pam_deny.so. An empty file falls back to PAM’s other stack, and a deleted one returns with the next upgrade
Animate the lock screen outset_unlock_animation with the animation’s length, then drive the fade from unlocking: Lock screen recipe

Gotchas

TrapFix
Removing set_unlock_animation from the config keeps the old delayThe value outlives reloads. Call set_unlock_animation with no argument to reset it to 0
A 1 s out-animation is cut shortThe delay clamps to 600 ms. Keep the animation within it
With pam_fprintd inside the password stack (system-auth, as Fedora’s authselect sets), each submit restarts its scanUse the mantle-fingerprint stack instead, and point /etc/pam.d/mantle at a stack without pam_fprintd
fingerprint turns nil with “device claimed” after a quick relock, or after suspendThe reader was still busy. Submit a password, even a wrong one, to retry, or lock again

See also: Lock screen recipe; idle to lock after inactivity.

Source: supervisor/src/capabilities/lock/