view src/libpam/pam_ffi.rs @ 105:13b4d2a19674

Support Rust v1.75.0. This is the version included in Ubuntu 24.04 LTS and Debian Trixie, so it's old enough to have wide penetration without being too old to get new features (Debian Stable, I love you but v1.63 is just not going to work out).
author Paul Fisher <paul@pfish.zone>
date Thu, 26 Jun 2025 00:48:51 -0400
parents dfcd96a74ac4
children e97534be35e3
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`](crate::libpam::memory::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>>,
}

/// 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,
    /// Marker to associate the lifetime of this with the conversation
    /// that was passed in.
    pub life: PhantomData<&'a mut ()>,
}

/// 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"));