view src/pam_ffi/mod.rs @ 72:47eb242a4f88

Fill out the PamHandle trait. This updates the PamHandle trait to have methods for each Item, and implements them on the LibPamHandle.
author Paul Fisher <paul@pfish.zone>
date Wed, 04 Jun 2025 03:53:36 -0400
parents 58f9d2a4df38
children ac6881304c78
line wrap: on
line source

//! The PAM library FFI and helpers for managing it.
//!
//! This includes the functions provided by PAM and the data structures
//! used by PAM, as well as a few low-level abstractions for dealing with
//! those data structures.
//!
//! Everything in here is hazmat.
//!

#![allow(dead_code)]

pub mod memory;
mod message;
mod response;

use crate::pam_ffi::memory::Immovable;
use crate::pam_ffi::message::OwnedMessages;
#[doc(inline)]
pub use message::Message;
#[doc(inline)]
pub use response::RawResponse;
use std::ffi::{c_char, c_int, c_void};

/// 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,
}

/// The callback that PAM uses to get information in a conversation.
///
/// - `num_msg` is the number of messages in the `pam_message` array.
/// - `messages` is a pointer to the messages being sent to the user.
///   For details about its structure, see the documentation of
///   [`OwnedMessages`](super::OwnedMessages).
/// - `responses` is a pointer to an array of [`RawResponse`]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 `responses` as `num_msg`.
/// - `appdata` is the `appdata` field of the [`LibPamConversation`] we were passed.
pub type ConversationCallback = extern "C" fn(
    num_msg: c_int,
    messages: &OwnedMessages,
    responses: &mut *mut RawResponse,
    appdata: *const AppData,
) -> c_int;

/// The type used by libpam to call back into a conversation.
#[repr(C)]
pub struct LibPamConversation {
    /// The function that is called to get information from the user.
    callback: ConversationCallback,
    /// The pointer that will be passed as the last parameter
    /// to the conversation callback.
    appdata: *const AppData,
}

#[link(name = "pam")]
extern "C" {
    pub fn pam_get_data(
        pamh: *const LibPamHandle,
        module_data_name: *const c_char,
        data: &mut *const c_void,
    ) -> c_int;

    pub fn pam_set_data(
        pamh: *mut LibPamHandle,
        module_data_name: *const c_char,
        data: *const c_void,
        cleanup: extern "C" fn(pamh: *const c_void, data: *mut c_void, error_status: c_int),
    ) -> c_int;

    pub fn pam_get_item(
        pamh: *mut LibPamHandle,
        item_type: c_int,
        item: &mut *const c_void,
    ) -> c_int;

    pub fn pam_set_item(pamh: *mut LibPamHandle, item_type: c_int, item: *const c_void) -> c_int;

    pub fn pam_get_user(
        pamh: *mut LibPamHandle,
        user: &mut *const c_char,
        prompt: *const c_char,
    ) -> c_int;

    pub fn pam_get_authtok(
        pamh: *mut LibPamHandle,
        item_type: c_int,
        data: &mut *const c_char,
        prompt: *const c_char,
    ) -> c_int;

    pub fn pam_end(pamh: *mut LibPamHandle, status: c_int) -> c_int;
}