view src/libpam/pam_ffi.rs @ 81:a8f4718fed5d

When dynamically linking against the wrong PAM, fail.
author Paul Fisher <paul@pfish.zone>
date Tue, 10 Jun 2025 01:16:39 -0400
parents 5aa1a010f1e8
children 05291b601f0a
line wrap: on
line source

//! The types that are directly represented in PAM function signatures.

#![allow(non_camel_case_types)]

use crate::libpam::memory::Immovable;
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::ffi::{c_int, c_void};
use std::marker::PhantomData;

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