Mercurial > crates > nonstick
view src/libpam/environ.rs @ 99:8840fa6534f6
Streamline dependencies and rename to openpam-extensions.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Tue, 24 Jun 2025 14:54:47 -0400 |
parents | b87100c5eed4 |
children | 3f11b8d30f63 |
line wrap: on
line source
#![allow(unused_variables)] // for now use crate::environ::EnvironMapMut; use crate::libpam::memory::CHeapString; use crate::{EnvironMap, LibPamHandle}; use std::ffi::{c_char, OsStr, OsString}; use std::os::unix::ffi::OsStrExt; use std::ptr::NonNull; use std::{iter, ptr}; use crate::libpam::memory; pub struct LibPamEnviron<'a> { source: &'a LibPamHandle, } pub struct LibPamEnvironMut<'a> { source: &'a mut LibPamHandle, } impl<'a> LibPamEnviron<'a> { pub fn new(source: &'a LibPamHandle) -> Self { Self { source } } } impl<'a> LibPamEnvironMut<'a> { pub fn new(source: &'a mut LibPamHandle) -> Self { Self { source } } fn immut(&self) -> LibPamEnviron { LibPamEnviron { source: self.source, } } } impl EnvironMap for LibPamEnviron<'_> { fn get(&self, val: &OsStr) -> Option<&OsStr> { todo!() } fn iter(&self) -> impl Iterator<Item = (&OsStr, &OsStr)> { iter::from_fn(|| todo!()) } } impl EnvironMap for LibPamEnvironMut<'_> { fn get(&self, val: &OsStr) -> Option<&OsStr> { todo!() } fn iter(&self) -> impl Iterator<Item = (&OsStr, &OsStr)> { iter::from_fn(|| todo!()) } } impl EnvironMapMut for LibPamEnvironMut<'_> { fn insert(&mut self, key: &OsStr, val: &OsStr) -> Option<OsString> { todo!() } fn remove(&mut self, key: &OsStr) -> Option<OsString> { todo!() } } struct EnvList { /// Pointer to the start of the environment variable list. /// /// This can't be a `CHeapBox` because it's not just a single /// `Option<EnvVar>`. vars: NonNull<Option<EnvVar>>, } impl EnvList { unsafe fn from_ptr(ptr: NonNull<*mut c_char>) -> Self { Self{vars: ptr.cast()} } fn iter(&self) -> impl Iterator<Item = (&OsStr, &OsStr)> { let mut current = self.vars; iter::from_fn(move || { match unsafe {current.as_ref()} { None => None, Some(item) => { let ret = item.as_kv(); current = unsafe {current.add(1) }; Some(ret) } } }) } } impl Drop for EnvList { fn drop(&mut self) { // SAFETY: We own this pointer, and we know it's valid environment data // from PAM. unsafe { let mut var = self.vars; while let Some(var_ref) = var.as_mut() { ptr::drop_in_place(var_ref as *mut EnvVar); var = var.add(1); } memory::free(self.vars.as_ptr()) } } } struct EnvVar(CHeapString); impl EnvVar { fn as_kv(&self) -> (&OsStr, &OsStr) { let bytes = self.0.to_bytes(); let mut split = bytes.splitn(2, |&b| b == b'='); ( OsStr::from_bytes(split.next().unwrap_or_default()), OsStr::from_bytes(split.next().unwrap_or_default()), ) } } #[cfg(test)] mod tests { use crate::libpam::memory::CHeapBox; use super::*; #[test] fn test_split_kv() { fn test(input: &str, key: &str, value: &str) { let data = CHeapString::new(input).unwrap(); let key = OsStr::from_bytes(key.as_bytes()); let value = OsStr::from_bytes(value.as_bytes()); assert_eq!(EnvVar(data).as_kv(), (key, value)); } test("THIS=that", "THIS", "that"); test("THESE=those, no one=knows", "THESE", "those, no one=knows"); test("HERE=", "HERE", ""); test("SOME", "SOME", ""); test("", "", ""); } #[test] fn test_iter() { let bx = CHeapBox::new([ Some("ONE=two"), Some("BIRDS=birds=birds"), Some("me"), Some("you="), None, ].map(|txt| txt.map(|txt| CHeapString::new(txt).unwrap()))).unwrap(); let env_ptr = CHeapBox::into_ptr(bx); let envs = unsafe {EnvList::from_ptr(env_ptr.cast())}; let bytes = |data: &'static str| OsStr::from_bytes(data.as_ref()); let result: Vec<_> = envs.iter().collect(); assert_eq!(vec![ (bytes("ONE"), bytes("two")), (bytes("BIRDS"), bytes("birds=birds")), (bytes("me"), bytes("")), (bytes("you"), bytes("")), ], result); } }