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;
use crate::unix::{Passwd, getpwnam_safe, getpwuid_safe};
use lazy_static::lazy_static;
use std::cell::RefCell;
use std::sync::{Mutex, MutexGuard};
use libc::{geteuid, seteuid, uid_t};
......@@ -54,34 +55,16 @@ pub struct UserInfo<'a> {
access_token: Option<BasicTokenResponse>
}
/// In-memory structure to hold global process state
/// Needed because the PAM and NSS components might be used chained (if NSS
/// resolution is necessary to complete PAM authentication), and we need to
/// remember state between the calls.
pub struct Cache<'a> {
/// The user currently calling the library
/// For NSS, this will be the process owner; for PAM, this will be the user
/// 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> {
pub fn new() -> UserInfo<'a> {
Self {
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
// FIXME Move to Cache, with a from_current_user generator method here
pub fn set_current_user(&mut self) {
......@@ -400,9 +383,11 @@ fn get_original_euid() -> uid_t {
}
}
lazy_static! {
static ref CACHE: Mutex<Cache<'static>> = Mutex::new(Cache::new());
thread_local! {
static CONTEXT_USER: RefCell<UserInfo<'static>> = RefCell::new(UserInfo::new());
}
pub fn get_cache() -> MutexGuard<'static, Cache<'static>> {
CACHE.lock().unwrap()
pub fn with_context_user<R>(f: impl FnOnce(UserInfo<'static>) -> R) -> R {
CONTEXT_USER.with(|rc| {
f(rc.into_inner())
})
}
......@@ -18,7 +18,7 @@ use crate::config::{
get_optional,
};
use config::Config;
use crate::cache::get_cache;
use crate::cache::with_context_user;
use crate::logging::setup_log;
......@@ -53,9 +53,11 @@ fn nss_hook_prepare() -> Config {
// 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
// lookup, and we want to keep the PAM login user context in that case
if !get_cache().context_user.is_initialized() {
get_cache().context_user.set_current_user();
}
with_context_user(|mut cu| {
if !cu.is_initialized() {
cu.set_current_user();
}
});
return conf;
}
......@@ -67,99 +69,102 @@ impl PasswdHooks for OidcPasswd {
let conf = nss_hook_prepare();
info!("[NSS] passwd.get_all_entries called");
let mut cache = get_cache();
let user_token_res = cache.context_user.get_access_token();
// FIXME Implement caching of system token
let system_token_res = get_access_token_client(&conf, "nss", "", "");
let system_token_res = system_token_res.as_ref();
let token = match user_token_res {
Some(t) => t,
None => {
debug!("Could not find a user token to request NSS data; trying client credentials");
match system_token_res {
Ok(ct) => ct,
Err(e) => {
error!("Failed to get access token with client credentials: {}", e);
return Response::Unavail;
with_context_user(|mut cu| {
let user_token_res = cu.get_access_token();
// FIXME Implement caching of system token
let system_token_res = get_access_token_client(&conf, "nss", "", "");
let system_token_res = system_token_res;
let token = match user_token_res {
Some(t) => t,
None => {
debug!("Could not find a user token to request NSS data; trying client credentials");
match system_token_res.as_ref() {
Ok(ct) => ct,
Err(e) => {
error!("Failed to get access token with client credentials: {}", e);
return Response::Unavail;
}
}
}
}
};
let data: Vec<PasswdHelper> = match get_data_jq(&conf, "nss", "passwd.list", "".to_string(), &token, true) {
Ok(d) => d,
Err(e) => {
error!("Could not load JSON data for passwd: {}", e);
return Response::Unavail;
}
};
Response::Success(data.into_iter().map(|p| p.0).collect())
};
let data: Vec<PasswdHelper> = match get_data_jq(&conf, "nss", "passwd.list", "".to_string(), &token, true) {
Ok(d) => d,
Err(e) => {
error!("Could not load JSON data for passwd: {}", e);
return Response::Unavail;
}
};
Response::Success(data.into_iter().map(|p| p.0).collect())
})
}
fn get_entry_by_uid(uid: libc::uid_t) -> Response<Passwd> {
let conf = nss_hook_prepare();
info!("[NSS] passwd.get_entry_by_uid called for {}", uid);
let mut cache = get_cache();
let user_token_res = cache.context_user.get_access_token();
// FIXME Implement caching of system token
let system_token_res = get_access_token_client(&conf, "nss", "", "");
let system_token_res = system_token_res.as_ref();
let token = match user_token_res {
Some(t) => t,
None => {
debug!("Could not find a user token to request NSS data; trying client credentials");
match system_token_res {
Ok(ct) => ct,
Err(e) => {
error!("Failed to get access token with client credentials: {}", e);
return Response::Unavail;
with_context_user(|mut cu| {
let user_token_res = cu.get_access_token();
// FIXME Implement caching of system token
let system_token_res = get_access_token_client(&conf, "nss", "", "");
let system_token_res = system_token_res;
let token = match user_token_res {
Some(t) => t,
None => {
debug!("Could not find a user token to request NSS data; trying client credentials");
match system_token_res.as_ref() {
Ok(ct) => ct,
Err(e) => {
error!("Failed to get access token with client credentials: {}", e);
return Response::Unavail;
}
}
}
}
};
let data: Passwd = match get_data_jq(&conf, "nss", "passwd.by_uid", uid, &token, false).map(|PasswdHelper(p)| p) {
Ok(d) => d,
Err(e) => {
error!("Could not load JSON data for passwd: {}", e);
return Response::NotFound;
}
};
Response::Success(data)
};
let data: Passwd = match get_data_jq(&conf, "nss", "passwd.by_uid", uid, &token, false).map(|PasswdHelper(p)| p) {
Ok(d) => d,
Err(e) => {
error!("Could not load JSON data for passwd: {}", e);
return Response::NotFound;
}
};
Response::Success(data)
})
}
fn get_entry_by_name(name: String) -> Response<Passwd> {
let conf = nss_hook_prepare();
info!("[NSS] passwd.get_entry_by_name called for {}", name);
let mut cache = get_cache();
let user_token_res = cache.context_user.get_access_token();
// FIXME Implement caching of system token
let system_token_res = get_access_token_client(&conf, "nss", "", "");
let system_token_res = system_token_res.as_ref();
let token = match user_token_res {
Some(t) => t,
None => {
debug!("Could not find a user token to request NSS data; trying client credentials");
match system_token_res {
Ok(ct) => ct,
Err(e) => {
error!("Failed to get access token with client credentials: {}", e);
return Response::Unavail;
with_context_user(|mut cu| {
let user_token_res = cu.get_access_token();
// FIXME Implement caching of system token
let system_token_res = get_access_token_client(&conf, "nss", "", "");
let system_token_res = system_token_res;
let token = match user_token_res {
Some(t) => t,
None => {
debug!("Could not find a user token to request NSS data; trying client credentials");
match system_token_res.as_ref() {
Ok(ct) => ct,
Err(e) => {
error!("Failed to get access token with client credentials: {}", e);
return Response::Unavail;
}
}
}
}
};
let data: Passwd = match get_data_jq(&conf, "nss", "passwd.by_name", name, &token, false).map(|PasswdHelper(p)| p) {
Ok(d) => d,
Err(e) => {
error!("Could not load JSON data for passwd: {}", e);
return Response::NotFound;
}
};
Response::Success(data)
};
let data: Passwd = match get_data_jq(&conf, "nss", "passwd.by_name", &name, &token, false).map(|PasswdHelper(p)| p) {
Ok(d) => d,
Err(e) => {
error!("Could not load JSON data for passwd: {}", e);
return Response::NotFound;
}
};
Response::Success(data)
})
}
}
......
......@@ -24,7 +24,7 @@ use crate::oauth::get_access_token_password;
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};
......@@ -91,8 +91,10 @@ impl PamServiceModule for PamOidc {
Ok(t) => {
info!("Authenticated {} using Resource Owner Password Grant", username);
set_is_getpwnam_safe(false);
get_cache().context_user.set_username(username.to_string());
get_cache().context_user.set_access_token(t);
with_context_user(|mut cu| {
cu.set_username(username.to_string());
cu.set_access_token(t);
});
set_is_getpwnam_safe(true);
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