From 28fa58620042f873cbec45458848888e936366a1 Mon Sep 17 00:00:00 2001 From: Dominik George <dominik.george@teckids.org> Date: Mon, 17 May 2021 18:56:00 +0200 Subject: [PATCH] [PAM] Fix and properly document PAM token handling code --- src/cache.rs | 4 ++++ src/pam.rs | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/cache.rs b/src/cache.rs index dcdaeb3..5698a92 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -398,6 +398,7 @@ fn get_original_euid() -> uid_t { unsafe { if !original_euid_set { original_euid = geteuid(); + debug!("Original EUID stored as {}", original_euid); original_euid_set = true; } original_euid @@ -412,5 +413,8 @@ lazy_static! { static ref CONTEXT_USER: Mutex<UserInfo> = Mutex::new(UserInfo::new()); } pub fn get_context_user() -> MutexGuard<'static, UserInfo> { + // Ensure original EUID is set before first action on context user + get_original_euid(); + CONTEXT_USER.lock().unwrap() } diff --git a/src/pam.rs b/src/pam.rs index d7637ed..487caae 100644 --- a/src/pam.rs +++ b/src/pam.rs @@ -92,12 +92,28 @@ impl PamServiceModule for PamOidc { match get_access_token_password(&conf, "pam", username.to_string(), password.to_string(), PamError::SERVICE_ERR, PamError::AUTH_ERR) { Ok(t) => { info!("Authenticated {} using Resource Owner Password Grant", username); + + // Cast a a butt-backwards somersault to get the token where it belongs + // This is because we cannot store the token in the user's home directory + // without resolving the user through getpwnam, and we (probably) cannot + // do getpwnam without having the user's access token, and we (certainly) + // cannot do getpwnam form inside the UserInfo cache object while having + // the UserInfo cache object locked for PAM. Therefore... + + // 1. ...mark getpwnam unsafe (prevent cache code from calling it) set_is_getpwnam_safe(false); + // 2. ...store the access token (will not go through to $HOME, as getpwnam + // is locked) + get_context_user().set_access_token(t.clone()); + // 3. ...call getpwnam ourselves without having the cache object locked let passwd = getpwnam_safe(username.to_string()); if passwd.is_ok() { + // 4. ...if getpwnam was successful, store the token again (this time, + // modulo other errors, it will go through to $HOME) get_context_user().set_passwd(passwd.unwrap()); + get_context_user().set_access_token(t.clone()); } - get_context_user().set_access_token(t); + // 5. ...unlock getpwnam again (somewhat unnecessary) set_is_getpwnam_safe(true); return PamError::SUCCESS; }, -- GitLab