Mercurial > crates > nonstick
diff src/libpam/handle.rs @ 98:b87100c5eed4
Start on environment variables, and make pointers nicer.
This starts work on the PAM environment handling, and in so doing,
introduces the CHeapBox and CHeapString structs. These are analogous
to Box and CString, but they're located on the C heap rather than
being Rust-managed memory.
This is because environment variables deal with even more pointers
and it turns out we can lose a lot of manual freeing using homemade
smart pointers.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Tue, 24 Jun 2025 04:25:25 -0400 |
parents | efe2f5f8b5b2 |
children | 94b51fa4f797 |
line wrap: on
line diff
--- a/src/libpam/handle.rs Mon Jun 23 19:10:34 2025 -0400 +++ b/src/libpam/handle.rs Tue Jun 24 04:25:25 2025 -0400 @@ -1,11 +1,13 @@ use super::conversation::LibPamConversation; use crate::constants::{ErrorCode, Result}; use crate::conv::Message; +use crate::environ::EnvironMapMut; use crate::handle::PamShared; +use crate::libpam::environ::{LibPamEnviron, LibPamEnvironMut}; pub use crate::libpam::pam_ffi::LibPamHandle; use crate::libpam::{memory, pam_ffi}; use crate::logging::Level; -use crate::{Conversation, Flags, PamHandleApplication, PamHandleModule}; +use crate::{Conversation, EnvironMap, Flags, PamHandleApplication, PamHandleModule}; use num_enum::{IntoPrimitive, TryFromPrimitive}; use std::cell::Cell; use std::ffi::{c_char, c_int, CString}; @@ -45,15 +47,20 @@ impl HandleBuilder { /// Creates a new HandleBuilder for the given service. fn new(service_name: String) -> Self { - Self{service_name, username: Default::default()} + Self { + service_name, + username: Default::default(), + } } /// Updates the service name. pub fn service_name(mut self, service_name: String) -> Self { - self.service_name = service_name; self + self.service_name = service_name; + self } /// Updates the username. pub fn username(mut self, username: String) -> Self { - self.username = Some(username); self + self.username = Some(username); + self } pub fn build(self, conv: &impl Conversation) -> Result<OwnedLibPamHandle> { @@ -65,7 +72,11 @@ pub fn build_with_service(service_name: String) -> HandleBuilder { HandleBuilder::new(service_name) } - fn start(service_name: String, username: Option<String>, conversation: &impl Conversation) -> Result<Self> { + fn start( + service_name: String, + username: Option<String>, + conversation: &impl Conversation, + ) -> Result<Self> { let conv = LibPamConversation::wrap(conversation); let service_cstr = CString::new(service_name).map_err(|_| ErrorCode::ConversationError)?; let username_cstr = memory::prompt_ptr(memory::option_cstr(username.as_deref())?.as_ref()); @@ -73,9 +84,10 @@ let mut handle: *mut LibPamHandle = ptr::null_mut(); // SAFETY: We've set everything up properly to call `pam_start`. // The returned value will be a valid pointer provided the result is OK. - let result = unsafe { pam_ffi::pam_start(service_cstr.as_ptr(), username_cstr, &conv, &mut handle) }; + let result = + unsafe { pam_ffi::pam_start(service_cstr.as_ptr(), username_cstr, &conv, &mut handle) }; ErrorCode::result_from(result)?; - Ok(Self{ + Ok(Self { handle: HandleWrap(handle), last_return: Cell::new(Ok(())), _conversation_lifetime: Default::default(), @@ -85,21 +97,21 @@ impl PamHandleApplication for OwnedLibPamHandle<'_> { fn authenticate(&mut self, flags: Flags) -> Result<()> { - let ret = unsafe { pam_ffi::pam_authenticate(self.handle.0, flags.bits() as c_int)}; + let ret = unsafe { pam_ffi::pam_authenticate(self.handle.0, flags.bits() as c_int) }; let result = ErrorCode::result_from(ret); self.last_return.set(result); result } fn account_management(&mut self, flags: Flags) -> Result<()> { - let ret = unsafe { pam_ffi::pam_acct_mgmt(self.handle.0, flags.bits() as c_int)}; + let ret = unsafe { pam_ffi::pam_acct_mgmt(self.handle.0, flags.bits() as c_int) }; let result = ErrorCode::result_from(ret); self.last_return.set(result); result } fn change_authtok(&mut self, flags: Flags) -> Result<()> { - let ret = unsafe { pam_ffi::pam_chauthtok(self.handle.0, flags.bits() as c_int)}; + let ret = unsafe { pam_ffi::pam_chauthtok(self.handle.0, flags.bits() as c_int) }; let result = ErrorCode::result_from(ret); self.last_return.set(result); result @@ -180,6 +192,14 @@ .unwrap_or(Err(ErrorCode::ConversationError)) } + fn environ(&self) -> impl EnvironMap { + LibPamEnviron::new(self) + } + + fn environ_mut(&mut self) -> impl EnvironMapMut { + LibPamEnvironMut::new(self) + } + cstr_item!(get = user_item, item = ItemType::User); cstr_item!(set = set_user_item, item = ItemType::User); cstr_item!(get = service, item = ItemType::Service); @@ -290,6 +310,7 @@ } macro_rules! delegate { + // First have the kind that save the result after delegation. (fn $meth:ident(&self $(, $param:ident: $typ:ty)*) -> Result<$ret:ty>) => { fn $meth(&self $(, $param: $typ)*) -> Result<$ret> { let result = self.handle.$meth($($param),*); @@ -304,6 +325,18 @@ result } }; + // Then have the kind that are just raw delegates + (fn $meth:ident(&self $(, $param:ident: $typ:ty)*) -> $ret:ty) => { + fn $meth(&self $(, $param: $typ)*) -> $ret { + self.handle.$meth($($param),*) + } + }; + (fn $meth:ident(&mut self $(, $param:ident: $typ:ty)*) -> $ret:ty) => { + fn $meth(&mut self $(, $param: $typ)*) -> $ret { + self.handle.$meth($($param),*) + } + }; + // Then have item getters / setters (get = $get:ident$(, set = $set:ident)?) => { delegate!(fn $get(&self) -> Result<Option<String>>); $(delegate!(set = $set);)? @@ -318,9 +351,9 @@ } impl PamShared for OwnedLibPamHandle<'_> { - fn log(&self, level: Level, entry: &str) { - self.handle.log(level, entry) - } + delegate!(fn log(&self, level: Level, entry: &str) -> ()); + delegate!(fn environ(&self) -> impl EnvironMap); + delegate!(fn environ_mut(&mut self) -> impl EnvironMapMut); delegate!(fn username(&mut self, prompt: Option<&str>) -> Result<String>); delegate!(get = user_item, set = set_user_item); delegate!(get = service, set = set_service);