Skip to content
Snippets Groups Projects
Verified Commit c85d31e9 authored by Nik | Klampfradler's avatar Nik | Klampfradler
Browse files

[WIP] Use thread-local objects for data store

parent b1d0b7f6
No related branches found
No related tags found
No related merge requests found
...@@ -21,6 +21,7 @@ use crate::BASE_NAME; ...@@ -21,6 +21,7 @@ use crate::BASE_NAME;
use crate::unix::{Passwd, getpwnam_safe, getpwuid_safe}; use crate::unix::{Passwd, getpwnam_safe, getpwuid_safe};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use std::cell::RefCell;
use std::sync::{Mutex, MutexGuard}; use std::sync::{Mutex, MutexGuard};
use libc::{geteuid, seteuid, uid_t}; use libc::{geteuid, seteuid, uid_t};
...@@ -54,34 +55,16 @@ pub struct UserInfo<'a> { ...@@ -54,34 +55,16 @@ pub struct UserInfo<'a> {
access_token: Option<BasicTokenResponse> access_token: Option<BasicTokenResponse>
} }
/// In-memory structure to hold global process state impl <'a>UserInfo<'a> {
/// Needed because the PAM and NSS components might be used chained (if NSS pub fn new() -> UserInfo<'a> {
/// resolution is necessary to complete PAM authentication), and we need to Self {
/// remember state between the calls. uid: None,
pub struct Cache<'a> { username: None,
/// The user currently calling the library passwd: None,
/// For NSS, this will be the process owner; for PAM, this will be the user access_token: None
/// logging in (after successful authentication)
pub context_user: UserInfo<'a>
}
impl Cache<'_> {
pub fn new<'a>() -> Cache<'a> {
let euid = unsafe {
geteuid()
};
Cache {
context_user: UserInfo {
uid: None,
username: None,
passwd: None,
access_token: None
}
} }
} }
}
impl <'a>UserInfo<'a> {
/// Set the information of this user object to that of the process owner /// Set the information of this user object to that of the process owner
// FIXME Move to Cache, with a from_current_user generator method here // FIXME Move to Cache, with a from_current_user generator method here
pub fn set_current_user(&mut self) { pub fn set_current_user(&mut self) {
...@@ -400,9 +383,11 @@ fn get_original_euid() -> uid_t { ...@@ -400,9 +383,11 @@ fn get_original_euid() -> uid_t {
} }
} }
lazy_static! { thread_local! {
static ref CACHE: Mutex<Cache<'static>> = Mutex::new(Cache::new()); static CONTEXT_USER: RefCell<UserInfo<'static>> = RefCell::new(UserInfo::new());
} }
pub fn get_cache() -> MutexGuard<'static, Cache<'static>> { pub fn with_context_user<R>(f: impl FnOnce(UserInfo<'static>) -> R) -> R {
CACHE.lock().unwrap() CONTEXT_USER.with(|rc| {
f(rc.into_inner())
})
} }
...@@ -18,7 +18,7 @@ use crate::config::{ ...@@ -18,7 +18,7 @@ use crate::config::{
get_optional, get_optional,
}; };
use config::Config; use config::Config;
use crate::cache::get_cache; use crate::cache::with_context_user;
use crate::logging::setup_log; use crate::logging::setup_log;
...@@ -53,9 +53,11 @@ fn nss_hook_prepare() -> Config { ...@@ -53,9 +53,11 @@ fn nss_hook_prepare() -> Config {
// Set the context user to the current user, but only if not already set // Set the context user to the current user, but only if not already set
// When doing PAM, we might get called back into by libc to do some NSS // When doing PAM, we might get called back into by libc to do some NSS
// lookup, and we want to keep the PAM login user context in that case // lookup, and we want to keep the PAM login user context in that case
if !get_cache().context_user.is_initialized() { with_context_user(|mut cu| {
get_cache().context_user.set_current_user(); if !cu.is_initialized() {
} cu.set_current_user();
}
});
return conf; return conf;
} }
...@@ -67,99 +69,102 @@ impl PasswdHooks for OidcPasswd { ...@@ -67,99 +69,102 @@ impl PasswdHooks for OidcPasswd {
let conf = nss_hook_prepare(); let conf = nss_hook_prepare();
info!("[NSS] passwd.get_all_entries called"); info!("[NSS] passwd.get_all_entries called");
let mut cache = get_cache(); with_context_user(|mut cu| {
let user_token_res = cache.context_user.get_access_token(); let user_token_res = cu.get_access_token();
// FIXME Implement caching of system token // FIXME Implement caching of system token
let system_token_res = get_access_token_client(&conf, "nss", "", ""); let system_token_res = get_access_token_client(&conf, "nss", "", "");
let system_token_res = system_token_res.as_ref(); let system_token_res = system_token_res;
let token = match user_token_res { let token = match user_token_res {
Some(t) => t, Some(t) => t,
None => { None => {
debug!("Could not find a user token to request NSS data; trying client credentials"); debug!("Could not find a user token to request NSS data; trying client credentials");
match system_token_res { match system_token_res.as_ref() {
Ok(ct) => ct, Ok(ct) => ct,
Err(e) => { Err(e) => {
error!("Failed to get access token with client credentials: {}", e); error!("Failed to get access token with client credentials: {}", e);
return Response::Unavail; return Response::Unavail;
}
} }
} }
} };
};
let data: Vec<PasswdHelper> = match get_data_jq(&conf, "nss", "passwd.list", "".to_string(), &token, true) {
let data: Vec<PasswdHelper> = match get_data_jq(&conf, "nss", "passwd.list", "".to_string(), &token, true) { Ok(d) => d,
Ok(d) => d, Err(e) => {
Err(e) => { error!("Could not load JSON data for passwd: {}", e);
error!("Could not load JSON data for passwd: {}", e); return Response::Unavail;
return Response::Unavail; }
} };
}; Response::Success(data.into_iter().map(|p| p.0).collect())
Response::Success(data.into_iter().map(|p| p.0).collect()) })
} }
fn get_entry_by_uid(uid: libc::uid_t) -> Response<Passwd> { fn get_entry_by_uid(uid: libc::uid_t) -> Response<Passwd> {
let conf = nss_hook_prepare(); let conf = nss_hook_prepare();
info!("[NSS] passwd.get_entry_by_uid called for {}", uid); info!("[NSS] passwd.get_entry_by_uid called for {}", uid);
let mut cache = get_cache(); with_context_user(|mut cu| {
let user_token_res = cache.context_user.get_access_token(); let user_token_res = cu.get_access_token();
// FIXME Implement caching of system token // FIXME Implement caching of system token
let system_token_res = get_access_token_client(&conf, "nss", "", ""); let system_token_res = get_access_token_client(&conf, "nss", "", "");
let system_token_res = system_token_res.as_ref(); let system_token_res = system_token_res;
let token = match user_token_res { let token = match user_token_res {
Some(t) => t, Some(t) => t,
None => { None => {
debug!("Could not find a user token to request NSS data; trying client credentials"); debug!("Could not find a user token to request NSS data; trying client credentials");
match system_token_res { match system_token_res.as_ref() {
Ok(ct) => ct, Ok(ct) => ct,
Err(e) => { Err(e) => {
error!("Failed to get access token with client credentials: {}", e); error!("Failed to get access token with client credentials: {}", e);
return Response::Unavail; return Response::Unavail;
}
} }
} }
} };
};
let data: Passwd = match get_data_jq(&conf, "nss", "passwd.by_uid", uid, &token, false).map(|PasswdHelper(p)| p) {
let data: Passwd = match get_data_jq(&conf, "nss", "passwd.by_uid", uid, &token, false).map(|PasswdHelper(p)| p) { Ok(d) => d,
Ok(d) => d, Err(e) => {
Err(e) => { error!("Could not load JSON data for passwd: {}", e);
error!("Could not load JSON data for passwd: {}", e); return Response::NotFound;
return Response::NotFound; }
} };
}; Response::Success(data)
Response::Success(data) })
} }
fn get_entry_by_name(name: String) -> Response<Passwd> { fn get_entry_by_name(name: String) -> Response<Passwd> {
let conf = nss_hook_prepare(); let conf = nss_hook_prepare();
info!("[NSS] passwd.get_entry_by_name called for {}", name); info!("[NSS] passwd.get_entry_by_name called for {}", name);
let mut cache = get_cache(); with_context_user(|mut cu| {
let user_token_res = cache.context_user.get_access_token(); let user_token_res = cu.get_access_token();
// FIXME Implement caching of system token // FIXME Implement caching of system token
let system_token_res = get_access_token_client(&conf, "nss", "", ""); let system_token_res = get_access_token_client(&conf, "nss", "", "");
let system_token_res = system_token_res.as_ref(); let system_token_res = system_token_res;
let token = match user_token_res { let token = match user_token_res {
Some(t) => t, Some(t) => t,
None => { None => {
debug!("Could not find a user token to request NSS data; trying client credentials"); debug!("Could not find a user token to request NSS data; trying client credentials");
match system_token_res { match system_token_res.as_ref() {
Ok(ct) => ct, Ok(ct) => ct,
Err(e) => { Err(e) => {
error!("Failed to get access token with client credentials: {}", e); error!("Failed to get access token with client credentials: {}", e);
return Response::Unavail; return Response::Unavail;
}
} }
} }
} };
};
let data: Passwd = match get_data_jq(&conf, "nss", "passwd.by_name", &name, &token, false).map(|PasswdHelper(p)| p) {
let data: Passwd = match get_data_jq(&conf, "nss", "passwd.by_name", name, &token, false).map(|PasswdHelper(p)| p) { Ok(d) => d,
Ok(d) => d, Err(e) => {
Err(e) => { error!("Could not load JSON data for passwd: {}", e);
error!("Could not load JSON data for passwd: {}", e); return Response::NotFound;
return Response::NotFound; }
} };
}; Response::Success(data)
Response::Success(data) })
} }
} }
......
...@@ -24,7 +24,7 @@ use crate::oauth::get_access_token_password; ...@@ -24,7 +24,7 @@ use crate::oauth::get_access_token_password;
use crate::logging::setup_log; use crate::logging::setup_log;
use crate::cache::{get_cache, set_is_getpwnam_safe}; use crate::cache::{set_is_getpwnam_safe, with_context_user};
use pamsm::{PamServiceModule, Pam, PamFlag, PamError, PamLibExt}; use pamsm::{PamServiceModule, Pam, PamFlag, PamError, PamLibExt};
...@@ -91,8 +91,10 @@ impl PamServiceModule for PamOidc { ...@@ -91,8 +91,10 @@ impl PamServiceModule for PamOidc {
Ok(t) => { Ok(t) => {
info!("Authenticated {} using Resource Owner Password Grant", username); info!("Authenticated {} using Resource Owner Password Grant", username);
set_is_getpwnam_safe(false); set_is_getpwnam_safe(false);
get_cache().context_user.set_username(username.to_string()); with_context_user(|mut cu| {
get_cache().context_user.set_access_token(t); cu.set_username(username.to_string());
cu.set_access_token(t);
});
set_is_getpwnam_safe(true); set_is_getpwnam_safe(true);
return PamError::SUCCESS; return PamError::SUCCESS;
}, },
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment