Mercurial > crates > nonstick
view src/libpam/pam_ffi.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 source
//! The types that are directly represented in PAM function signatures. #![allow(non_camel_case_types, non_upper_case_globals)] use crate::libpam::memory::{CHeapBox, Immovable}; use std::ffi::{c_int, c_uint, c_void, CStr}; use std::marker::PhantomData; use std::ptr; /// An opaque structure that a PAM handle points to. #[repr(C)] pub struct LibPamHandle { _data: (), _marker: Immovable, } /// An opaque structure that is passed through PAM in a conversation. #[repr(C)] pub struct AppData { _data: (), _marker: Immovable, } /// Generic version of answer data. /// /// This has the same structure as [`BinaryAnswer`](crate::libpam::answer::BinaryAnswer) /// and [`TextAnswer`](crate::libpam::answer::TextAnswer). #[repr(C)] #[derive(Debug, Default)] pub struct Answer { /// Owned pointer to the data returned in an answer. /// For most answers, this will be a [`CHeapString`], /// but for [`BinaryQAndA`](crate::conv::BinaryQAndA)s (a Linux-PAM extension), /// this will be a [`CHeapBox`] of /// [`CBinaryData`](crate::libpam::memory::CBinaryData). pub data: Option<CHeapBox<c_void>>, /// Unused. Just here for the padding. return_code: c_int, _marker: Immovable, } /// A question sent by PAM or a module to an application. /// /// PAM refers to this as a "message", but we call it a question /// to avoid confusion with [`Message`](crate::conv::Message). /// /// This question, and its internal data, is owned by its creator /// (either the module or PAM itself). #[repr(C)] #[derive(Debug)] pub struct Question { /// The style of message to request. pub style: c_uint, /// A description of the data requested. /// /// For most requests, this will be an owned [`CStr`], /// but for requests with style `PAM_BINARY_PROMPT`, /// this will be `CBinaryData` (a Linux-PAM extension). pub data: Option<CHeapBox<c_void>>, pub _marker: Immovable, } /// The callback that PAM uses to get information in a conversation. /// /// - `num_msg` is the number of messages in the `questions` array. /// - `questions` is a pointer to the [`Question`]s being sent to the user. /// For information about its structure, /// see [`QuestionsTrait`](super::question::QuestionsTrait). /// - `answers` is a pointer to an array of [`Answer`]s, /// which PAM sets in response to a module's request. /// This is an array of structs, not an array of pointers to a struct. /// There must always be exactly as many `answers` as `num_msg`. /// - `appdata` is the `appdata` field of the [`LibPamConversation`]. pub type ConversationCallback = unsafe extern "C" fn( num_msg: c_int, questions: *const *const Question, answers: *mut *mut Answer, appdata: *const AppData, ) -> c_int; /// The type used by PAM to call back into a conversation. #[repr(C)] pub struct LibPamConversation<'a> { /// The function that is called to get information from the user. pub callback: ConversationCallback, /// The pointer that will be passed as the last parameter /// to the conversation callback. pub appdata: *const AppData, pub life: PhantomData<&'a mut ()>, pub _marker: Immovable, } /// Gets a string version of an error message. pub fn strerror(code: c_uint) -> Option<&'static str> { // SAFETY: Every single PAM implementation I can find (Linux-PAM, OpenPAM, // Solaris, etc.) returns a static string and ignores the handle value. let strerror = unsafe { pam_strerror(ptr::null_mut(), code as c_int) }; if strerror.is_null() { None } else { unsafe { CStr::from_ptr(strerror) }.to_str().ok() } } type pam_handle = LibPamHandle; type pam_conv = LibPamConversation<'static>; include!(concat!(env!("OUT_DIR"), "/bindings.rs"));