From b5bfa1280dc0c3f6b5032d7e16b608d7a25aa9de Mon Sep 17 00:00:00 2001
From: Dominik George <dominik.george@teckids.org>
Date: Tue, 11 May 2021 21:55:38 +0200
Subject: [PATCH] [Cache] Get rid of global state

---
 src/cache.rs | 28 ++++++++++------------------
 src/nss.rs   | 17 ++++++++---------
 src/pam.rs   | 12 +++++++-----
 3 files changed, 25 insertions(+), 32 deletions(-)

diff --git a/src/cache.rs b/src/cache.rs
index db9a71a..066081d 100644
--- a/src/cache.rs
+++ b/src/cache.rs
@@ -15,9 +15,7 @@
 
 use crate::BASE_NAME;
 
-use lazy_static::lazy_static;
 use std::collections::HashMap;
-use std::sync::{RwLock, RwLockReadGuard};
 
 use libc::{geteuid, seteuid, getpwnam, uid_t};
 use std::ffi::{CStr, CString};
@@ -39,17 +37,19 @@ const USER_TOKEN_FILENAME: &str = "user_token.json";
 pub struct Cache {
     user_tokens: HashMap<String, BasicTokenResponse>,
     original_euid: uid_t,
+    prefix: String
 }
 
 impl Cache {
-    pub fn new() -> Cache {
+    pub fn new(prefix: &str) -> Cache {
         let euid;
         unsafe {
             euid = geteuid();
         };
         Cache {
             user_tokens: HashMap::new(),
-            original_euid: euid
+            original_euid: euid,
+            prefix: prefix.to_string()
         }
     }
 
@@ -144,7 +144,7 @@ impl Cache {
         }
     }
 
-    pub fn load_user_token(&self, owner: &String) -> Option<&BasicTokenResponse> {
+    pub fn load_user_token(&mut self, owner: &String) -> Option<&BasicTokenResponse> {
         if !self.user_tokens.contains_key(owner) {
             debug!("No token for {} in memory, trying to load from file", owner);
 
@@ -160,7 +160,7 @@ impl Cache {
 
             match new_token {
                 Some(t) => {
-                    CACHE.write().unwrap().user_tokens.insert(owner.to_string(), t);
+                    self.user_tokens.insert(owner.to_string(), t);
                     self.user_tokens.get(owner)
                 },
                 None => None
@@ -171,8 +171,8 @@ impl Cache {
         }
     }
 
-    pub fn save_user_token(&self, owner: &String, token: BasicTokenResponse) -> Result<(), io::Error> {
-        CACHE.write().unwrap().user_tokens.insert(owner.to_string(), token.clone());
+    pub fn save_user_token(&mut self, owner: &String, token: BasicTokenResponse) -> Result<(), io::Error> {
+        self.user_tokens.insert(owner.to_string(), token.clone());
         debug!("Saved token for {} in memory", owner);
 
         // Try to write user's token cache file
@@ -190,8 +190,8 @@ impl Cache {
         return res;
     }
 
-    pub fn delete_user_token(&self, owner: &String) {
-        CACHE.write().unwrap().user_tokens.remove(owner);
+    pub fn delete_user_token(&mut self, owner: &String) {
+        self.user_tokens.remove(owner);
         debug!("Token for {} removed from memory", owner);
 
         // Try to remove user's token cache file
@@ -225,11 +225,3 @@ fn save_json<O: Serialize>(path: PathBuf, obj: O) -> Result<(), io::Error> {
 
     fs::write(path, json)
 }
-
-lazy_static! {
-    static ref CACHE: RwLock<Cache> = RwLock::new(Cache::new());
-}
-
-pub fn get_cache() -> RwLockReadGuard<'static, Cache> {
-    CACHE.read().unwrap()
-}
diff --git a/src/nss.rs b/src/nss.rs
index 986cf0f..1c062cb 100644
--- a/src/nss.rs
+++ b/src/nss.rs
@@ -19,7 +19,7 @@ use crate::config::{
     get_or_error
 };
 use config::Config;
-use crate::cache::get_cache;
+use crate::cache::Cache;
 
 use crate::logging::setup_log;
 
@@ -45,7 +45,7 @@ struct PasswdDef {
 }
 #[derive(Deserialize)] struct PasswdHelper(#[serde(with = "PasswdDef")] Passwd);
 
-fn nss_hook_prepare() -> Config {
+fn nss_hook_prepare() -> (Cache, Config) {
     let conf = get_config(None);
 
     let mut log_level = log::LevelFilter::Error;
@@ -54,7 +54,9 @@ fn nss_hook_prepare() -> Config {
     }
     setup_log(log_level);
 
-    return conf;
+    let cache = Cache::new("nss");
+
+    return (cache, conf);
 }
 
 fn get_current_user() -> String {
@@ -80,8 +82,7 @@ struct OidcPasswd;
 
 impl PasswdHooks for OidcPasswd {
     fn get_all_entries() -> Response<Vec<Passwd>> {
-        let conf = nss_hook_prepare();
-        let mut cache = get_cache();
+        let (mut cache, conf) = nss_hook_prepare();
 
         let user = get_current_user();
         let ctc;
@@ -114,8 +115,7 @@ impl PasswdHooks for OidcPasswd {
     }
 
     fn get_entry_by_uid(uid: libc::uid_t) -> Response<Passwd> {
-        let conf = nss_hook_prepare();
-        let mut cache = get_cache();
+        let (mut cache, conf) = nss_hook_prepare();
 
         let user = get_current_user();
         let ctc;
@@ -148,8 +148,7 @@ impl PasswdHooks for OidcPasswd {
     }
 
     fn get_entry_by_name(name: String) -> Response<Passwd> {
-        let conf = nss_hook_prepare();
-        let mut cache = get_cache();
+        let (mut cache, conf) = nss_hook_prepare();
 
         let user = get_current_user();
         let ctc;
diff --git a/src/pam.rs b/src/pam.rs
index 2133f7f..1042ade 100644
--- a/src/pam.rs
+++ b/src/pam.rs
@@ -24,11 +24,11 @@ use crate::oauth::get_access_token_password;
 
 use crate::logging::setup_log;
 
-use crate::cache::get_cache;
+use crate::cache::Cache;
 
 use pamsm::{PamServiceModule, Pam, PamFlag, PamError, PamLibExt};
 
-fn pam_sm_prepare(argv: &Vec<String>) -> Config {
+fn pam_sm_prepare(argv: &Vec<String>) -> (Cache, Config) {
     let conf_args = argv_to_config(argv);
     let conf = get_config(Some(conf_args));
 
@@ -38,14 +38,16 @@ fn pam_sm_prepare(argv: &Vec<String>) -> Config {
     }
     setup_log(log_level);
 
-    return conf;
+    let cache = Cache::new("pam");
+
+    return (cache, conf);
 }
 
 struct PamOidc;
 
 impl PamServiceModule for PamOidc {
     fn authenticate(pamh: Pam, _: PamFlag, argv: Vec<String>) -> PamError {
-        let conf = pam_sm_prepare(&argv);
+        let (mut cache, conf) = pam_sm_prepare(&argv);
         if conf.get_str("pam.flow").unwrap() == "password" {
             debug!("Starting Resource Owner Password Credentials OAuth flow");
 
@@ -90,7 +92,7 @@ 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);
-                    get_cache().save_user_token(&username.to_string(), t.into());
+                    cache.save_user_token(&username.to_string(), t.into());
                     return PamError::SUCCESS;
                 },
                 Err(e) => {
-- 
GitLab