diff --git a/src/pam.rs b/src/pam.rs index 9088c60cf37808452fb71c22771e3cf56ef3b4f7..3c7fda3affe3a67c1ee85934640aaa8f1786ec96 100644 --- a/src/pam.rs +++ b/src/pam.rs @@ -50,6 +50,8 @@ struct PamOidc; impl PamServiceModule for PamOidc { fn authenticate(pamh: Pam, _: PamFlag, argv: Vec<String>) -> PamError { let conf = pam_sm_prepare(&argv); + debug!("[PAM] authenticate called"); + if conf.get_str("pam.flow").unwrap() == "password" { debug!("Starting Resource Owner Password Credentials OAuth flow"); @@ -104,17 +106,15 @@ impl PamServiceModule for PamOidc { // 1. ...mark getpwnam unsafe (prevent cache code from calling it) set_is_getpwnam_safe(false); - // 2. ...store the access token in memory + // 2. ...store the access token in memory, so the NSS part can use it + // on re-entry through getpwnam get_context_user().set_access_token(t.clone(), false, false).ok(); // 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) + // 4. ...if getpwnam was successful, store the result for context user; + // setcred() will pick it up and write to /run and/or $HOME get_context_user().set_passwd(passwd.unwrap()); - let persist_run = conf.get_bool("pam.persist_token.run").unwrap(); - let persist_home = conf.get_bool("pam.persist_token.home").unwrap(); - get_context_user().set_access_token(t.clone(), persist_run, persist_home).ok(); } // 5. ...unlock getpwnam again (somewhat unnecessary) set_is_getpwnam_safe(true); @@ -133,6 +133,7 @@ impl PamServiceModule for PamOidc { fn acct_mgmt(pamh: Pam, _: PamFlag, argv: Vec<String>) -> PamError { let conf = pam_sm_prepare(&argv); + debug!("[PAM] acct_mgmt called"); if conf.get_str("pam.urls.authz").unwrap_or_default() == "" { info!("Authorization endpoint not set, granting access by default"); @@ -172,6 +173,53 @@ impl PamServiceModule for PamOidc { } } } + + fn setcred(pamh: Pam, flag: PamFlag, argv: Vec<String>) -> PamError { + let conf = pam_sm_prepare(&argv); + debug!("[PAM] setcred called"); + + let persist_run = conf.get_bool("pam.persist_token.run").unwrap(); + let persist_home = conf.get_bool("pam.persist_token.home").unwrap(); + + let token = match get_context_user().get_access_token() { + Some(t) => t, + None => { + error!("Access token not yet known, cannot persist"); + return PamError::CRED_UNAVAIL; + } + }; + + let res; + if matches!(flag, PamFlag::ESTABLISH_CRED) { + set_is_getpwnam_safe(false); + let token = + res = match get_context_user().set_access_token(token.clone(), persist_run, persist_home) { + Ok(_) => { + debug!("Successfully set credentials"); + PamError::SUCCESS + }, + Err(e) => { + error!("Failed setting credentials: {}", e); + PamError::CRED_ERR + } + }; + set_is_getpwnam_safe(true); + } else if matches!(flag, PamFlag::DELETE_CRED) { + // FIXME Implement in UserInfo class + res = PamError::SERVICE_ERR; + } else if matches!(flag, PamFlag::REINITIALIZE_CRED) { + // FIXME Implement + res = PamError::SERVICE_ERR; + } else if matches!(flag, PamFlag::REFRESH_CRED) { + // FIXME Implement in UserInfo class (probably) + res = PamError::SERVICE_ERR; + } else { + error!("setcred called with unexpected flag"); + res = PamError::SERVICE_ERR; + } + + res + } } pam_module!(PamOidc);