view src/libpam/items.rs @ 171:e27c5c667a5a

Create full new types for return code and flags, separate end to end. This plumbs the ReturnCode and RawFlags types through the places where we call into or are called from PAM. Also adds Sun documentation to the project.
author Paul Fisher <paul@pfish.zone>
date Fri, 25 Jul 2025 20:52:14 -0400
parents a75a66cb4181
children a1bb1d013567
line wrap: on
line source

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) -> Result<Option<OsString>> {
    let mut output = ptr::null();
    let ret = unsafe { libpam_sys::pam_get_item(hdl.inner(), 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>,
) -> Result<()> {
    let data_str = memory::option_cstr_os(data);
    let ret = unsafe {
        libpam_sys::pam_set_item(
            hdl.inner_mut(),
            item_type as c_int,
            memory::prompt_ptr(data_str.as_deref()).cast(),
        )
    };
    ErrorCode::result_from(ret)
}