diff options
| author | srdusr <[email protected]> | 2024-10-30 23:52:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2024-10-30 23:52:00 +0200 |
| commit | 9748bca006cd2498c4c0f2730d8789c667bda52b (patch) | |
| tree | f917af35cd32f9745c940253f2400ab0b92f0b0a /crates/platform | |
| parent | 3509cf6127185d9fed5a63ceca18a003213a20d7 (diff) | |
| download | srdwm-9748bca006cd2498c4c0f2730d8789c667bda52b.tar.gz srdwm-9748bca006cd2498c4c0f2730d8789c667bda52b.zip | |
Add srdwm's own native session-lock screen (blur, PAM auth)
A real ext-session-lock-v1 implementation drawn by the compositor
itself, not a hand-off to an external locker process: a live-blurred
background, PAM authentication on a background thread, and its own
config surface (lock_config.rs) rather than hardcoded appearance.
Diffstat (limited to 'crates/platform')
| -rw-r--r-- | crates/platform/src/pam_auth.rs | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/crates/platform/src/pam_auth.rs b/crates/platform/src/pam_auth.rs new file mode 100644 index 0000000..bdad439 --- /dev/null +++ b/crates/platform/src/pam_auth.rs @@ -0,0 +1,58 @@ +//! PAM authentication for srdwm's own session-lock UI +//! (`crates/wayland/src/native_lock.rs`) - the one piece of that feature +//! that must never be "close enough": this is what stands between a typed +//! password and actually unlocking the session. +//! +//! Uses `pam_client`'s application-side API (the same shape swaylock, +//! gtklock, and every other real screen locker use) rather than reading +//! `/etc/shadow` by hand - PAM already handles the privilege boundary +//! correctly (on a normal distro, `pam_unix.so` shells out to the setuid +//! `unix_chkpwd` helper to compare the password, so this process never +//! needs elevated privileges or shadow-file access itself) and honors +//! whatever the system's actual auth policy is (a YubiKey module, an +//! account lockout policy, anything `/etc/pam.d/srdwm` enables), not just +//! a plain password check. +//! +//! Needs `/etc/pam.d/srdwm` to exist (any distro's default `login`-derived +//! policy works, e.g. `auth include login`) - a service with no PAM +//! config file at all fails every authentication attempt, not falls back +//! to some default. That file is a root-owned system config change, +//! deliberately not written by this code. + +use pam_client::conv_mock::Conversation; +use pam_client::{Context, Flag}; + +/// The PAM service name - see `Context::new`'s own docs: this is what +/// selects the policy from `/etc/pam.d/<service>`. +const SERVICE: &str = "srdwm"; + +/// Verifies `password` for `username` against the system's real PAM +/// policy. `true` only for a genuine, complete authentication success +/// (both `authenticate` *and* `acct_mgmt`, so a correct password on a +/// locked or expired account still correctly fails) - every other +/// outcome, including a PAM setup problem that has nothing to do with the +/// password itself, resolves to `false`. Deliberately no distinction +/// between "wrong password" and "something is broken" in the return value +/// - fail secure means every non-success path stays locked, not just the +/// ones that are the user's own fault. Logged at `warn` for whoever's +/// debugging a setup problem, never at a level that would put the +/// password itself in a log. +pub fn authenticate(username: &str, password: &str) -> bool { + let conversation = Conversation::with_credentials(username, password); + let mut context = match Context::new(SERVICE, Some(username), conversation) { + Ok(ctx) => ctx, + Err(e) => { + log::warn!("session lock: failed to start PAM context for service '{SERVICE}': {e} ({:?})", e.code()); + return false; + } + }; + if let Err(e) = context.authenticate(Flag::NONE) { + log::warn!("session lock: PAM authentication failed: {e} ({:?})", e.code()); + return false; + } + if let Err(e) = context.acct_mgmt(Flag::NONE) { + log::warn!("session lock: PAM account check failed: {e} ({:?})", e.code()); + return false; + } + true +} |