diff src/libpam/items.rs @ 146:1bc52025156b

Split PAM items into their own separate struct. To trim down the number of methods on `PamShared`, this puts all the Items into their own struct(s). This also makes the split between authtok/authtok_item easier to understand.
author Paul Fisher <paul@pfish.zone>
date Sun, 06 Jul 2025 19:10:26 -0400
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libpam/items.rs	Sun Jul 06 19:10:26 2025 -0400
@@ -0,0 +1,90 @@
+use crate::constants::ErrorCode;
+use crate::constants::Result;
+use crate::items::{Items, ItemsMut};
+use crate::libpam::handle::ItemType;
+use crate::libpam::handle::LibPamHandle;
+use crate::libpam::memory;
+use std::ffi::{c_int, OsStr, OsString};
+use std::ptr;
+
+pub struct LibPamItems<'a>(pub &'a LibPamHandle);
+pub struct LibPamItemsMut<'a>(pub &'a mut LibPamHandle);
+
+/// Macro to implement getting/setting a CStr-based item.
+macro_rules! cstr_item {
+    (get = $getter:ident, item = $item_type:path) => {
+        fn $getter(&self) -> Result<Option<OsString>> {
+            unsafe { get_cstr_item(&self.0, $item_type) }
+        }
+    };
+    (set = $setter:ident, item = $item_type:path) => {
+        fn $setter(&mut self, value: Option<&OsStr>) -> Result<()> {
+            unsafe { set_cstr_item(&mut self.0, $item_type, value) }
+        }
+    };
+}
+
+impl Items<'_> for LibPamItems<'_> {
+    cstr_item!(get = user, item = ItemType::User);
+    cstr_item!(get = service, item = ItemType::Service);
+    cstr_item!(get = user_prompt, item = ItemType::UserPrompt);
+    cstr_item!(get = tty_name, item = ItemType::Tty);
+    cstr_item!(get = remote_user, item = ItemType::RemoteUser);
+    cstr_item!(get = remote_host, item = ItemType::RemoteHost);
+}
+
+impl Items<'_> for LibPamItemsMut<'_> {
+    cstr_item!(get = user, item = ItemType::User);
+    cstr_item!(get = service, item = ItemType::Service);
+    cstr_item!(get = user_prompt, item = ItemType::UserPrompt);
+    cstr_item!(get = tty_name, item = ItemType::Tty);
+    cstr_item!(get = remote_user, item = ItemType::RemoteUser);
+    cstr_item!(get = remote_host, item = ItemType::RemoteHost);
+}
+
+impl ItemsMut<'_> for LibPamItemsMut<'_> {
+    cstr_item!(set = set_user, item = ItemType::User);
+    cstr_item!(set = set_service, item = ItemType::Service);
+    cstr_item!(set = set_user_prompt, item = ItemType::UserPrompt);
+    cstr_item!(set = set_tty_name, item = ItemType::Tty);
+    cstr_item!(set = set_remote_user, item = ItemType::RemoteUser);
+    cstr_item!(set = set_remote_host, item = ItemType::RemoteHost);
+    cstr_item!(set = set_authtok, item = ItemType::AuthTok);
+    cstr_item!(set = set_old_authtok, item = ItemType::OldAuthTok);
+}
+
+/// Gets a C string item.
+///
+/// # Safety
+///
+/// You better be requesting an item which is a C string.
+pub unsafe fn get_cstr_item(
+    hdl: &LibPamHandle,
+    item_type: ItemType,
+) -> crate::Result<Option<OsString>> {
+    let mut output = ptr::null();
+    let ret = unsafe { libpam_sys::pam_get_item(hdl.raw_ref(), item_type as c_int, &mut output) };
+    ErrorCode::result_from(ret)?;
+    Ok(memory::copy_pam_string(output.cast()))
+}
+
+/// Sets a C string item.
+///
+/// # Safety
+///
+/// You better be setting an item which is a C string.
+pub unsafe fn set_cstr_item(
+    hdl: &mut LibPamHandle,
+    item_type: ItemType,
+    data: Option<&OsStr>,
+) -> crate::Result<()> {
+    let data_str = memory::option_cstr_os(data);
+    let ret = unsafe {
+        libpam_sys::pam_set_item(
+            hdl.raw_mut(),
+            item_type as c_int,
+            memory::prompt_ptr(data_str.as_deref()).cast(),
+        )
+    };
+    ErrorCode::result_from(ret)
+}