view src/pam_ffi/mod.rs @ 71:58f9d2a4df38

Reorganize everything again??? - Splits ffi/memory stuff into a bunch of stuff in the pam_ffi module. - Builds infrastructure for passing Messages and Responses. - Adds tests for some things at least.
author Paul Fisher <paul@pfish.zone>
date Tue, 03 Jun 2025 21:54:58 -0400
parents src/pam_ffi.rs@9f8381a1c09c
children 47eb242a4f88
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;
pub use message::Message;
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 Handle {
    _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 [`Conversation`] we were passed.
pub type ConversationCallback = extern "C" fn(
    num_msg: c_int,
    messages: &OwnedMessages,
    responses: &mut *mut RawResponse,
    appdata: *const AppData,
) -> c_int;

/// A callback and the associated [`AppData`] pointer that needs to be passed back to it.
#[repr(C)]
pub struct Conversation {
    callback: ConversationCallback,
    appdata: *const AppData,
}

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

    pub fn pam_set_data(
        pamh: *mut Handle,
        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: *const Handle, item_type: c_int, item: &mut *const c_void) -> c_int;

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

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

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

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