diff src/libpam/pam_ffi.rs @ 80:5aa1a010f1e8

Start using PAM headers; improve owned/borrowed distinction. - Uses bindgen to generate bindings (only if needed). - Gets the story together on owned vs. borrowed handles. - Reduces number of mutable borrows in handle operation (since `PamHandle` is neither `Send` nor `Sync`, we never have to worry about thread safety. - Improves a bunch of macros so we don't have our own special syntax for docs. - Implement question indirection for standard XSSO PAM implementations.
author Paul Fisher <paul@pfish.zone>
date Tue, 10 Jun 2025 01:09:30 -0400
parents
children a8f4718fed5d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libpam/pam_ffi.rs	Tue Jun 10 01:09:30 2025 -0400
@@ -0,0 +1,115 @@
+//! The types that are directly represented in PAM function signatures.
+
+#![allow(non_camel_case_types)]
+
+use crate::libpam::memory::Immovable;
+use std::ffi::{c_int, c_void};
+use std::marker::PhantomData;
+use num_enum::{IntoPrimitive, TryFromPrimitive};
+
+/// 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)]
+pub struct Answer {
+    /// Pointer to the data returned in an answer.
+    /// For most answers, this will be a [`CStr`](std::ffi::CStr),
+    /// but for [`BinaryQAndA`](crate::conv::BinaryQAndA)s (a Linux-PAM extension),
+    /// this will be [`CBinaryData`](crate::libpam::memory::CBinaryData)
+    pub data: *mut c_void,
+    /// Unused.
+    return_code: c_int,
+    _marker: Immovable,
+}
+
+/// The C enum values for messages shown to the user.
+#[derive(Debug, PartialEq, TryFromPrimitive, IntoPrimitive)]
+#[repr(i32)]
+pub enum Style {
+    /// Requests information from the user; will be masked when typing.
+    PromptEchoOff = 1,
+    /// Requests information from the user; will not be masked.
+    PromptEchoOn = 2,
+    /// An error message.
+    ErrorMsg = 3,
+    /// An informational message.
+    TextInfo = 4,
+    /// Yes/No/Maybe conditionals. A Linux-PAM extension.
+    RadioType = 5,
+    /// For server–client non-human interaction.
+    ///
+    /// NOT part of the X/Open PAM specification.
+    /// A Linux-PAM extension.
+    BinaryPrompt = 7,
+}
+
+/// 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::Message).
+///
+/// This question, and its internal data, is owned by its creator
+/// (either the module or PAM itself).
+#[repr(C)]
+pub struct Question {
+    /// The style of message to request.
+    pub style: c_int,
+    /// A description of the data requested.
+    ///
+    /// For most requests, this will be an owned [`CStr`](std::ffi::CStr), but for requests
+    /// with [`Style::BinaryPrompt`], this will be [`CBinaryData`]
+    /// (a Linux-PAM extension).
+    pub data: *mut 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 `pam_message` array.
+/// - `questions` is a pointer to the [`Question`]s being sent to the user.
+///   For information about its structure,
+///   see [`GenericQuestions`](super::question::GenericQuestions).
+/// - `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 should always be exactly as many `answers` as `num_msg`.
+/// - `appdata` is the `appdata` field of the [`LibPamConversation`] we were passed.
+pub type ConversationCallback = unsafe extern "C" fn(
+    num_msg: c_int,
+    questions: *const *const Question,
+    answers: *mut *mut Answer,
+    appdata: *mut 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: *mut AppData,
+    pub life: PhantomData<&'a mut ()>,
+    pub _marker: Immovable,
+}
+
+type pam_handle = LibPamHandle;
+type pam_conv = LibPamConversation<'static>;
+
+include!(concat!(env!("OUT_DIR"), "/bindings.rs"));