Mercurial > crates > nonstick
diff libpam-sys/src/ffi.rs @ 127:c77846f3a979
GET CTEST WORKING.
This will verify that the functions we're exporting are correct.
It has been a nightmare.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Mon, 30 Jun 2025 22:56:26 -0400 |
parents | libpam-sys/src/structs.rs@2b255c92417b |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpam-sys/src/ffi.rs Mon Jun 30 22:56:26 2025 -0400 @@ -0,0 +1,224 @@ +#![allow(non_camel_case_types)] + +use std::ffi::{c_char, c_int, c_void}; +use std::fmt; +use std::marker::{PhantomData, PhantomPinned}; + +/// A marker struct to make whatever it's in `!Sync`, `!Send`, and `!Unpin`. +#[derive(Default, PartialOrd, PartialEq, Ord, Eq)] +#[repr(C)] +struct ExtremelyUnsafe { + _value: (), + _marker: PhantomData<(PhantomPinned, *mut c_void)>, +} + +impl fmt::Debug for ExtremelyUnsafe { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("ExtremelyUnsafe") + } +} + +/// An opaque structure that PAM uses to communicate. +/// +/// This is only ever returned in pointer form and cannot be constructed. +#[repr(C)] +pub struct pam_handle(ExtremelyUnsafe); + +impl fmt::Debug for pam_handle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "PamHandle({self:p}") + } +} + +/// An opaque structure that is passed through PAM in a conversation. +#[repr(C)] +pub struct AppData(ExtremelyUnsafe); + +impl fmt::Debug for AppData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "AppData({self:p}") + } +} + +/// Just an alias for the type of [`pam_conv::conv`]. +/// +/// For important details about the format of `messages`, +/// see the [`helpers`](crate::helpers) module. +/// +/// ```no_run +/// # use libpam_sys::{ConversationCallback, pam_conv}; +/// fn convo() -> ConversationCallback { +/// // ... +/// # unimplemented!() +/// } +/// let conv = pam_conv{conv: convo(), appdata_ptr: std::ptr::null_mut()}; +/// ``` +pub type ConversationCallback = unsafe extern "C" fn( + num_msg: c_int, + msg: *const *const pam_message, + resp: *mut *mut pam_response, + appdata: *mut AppData, +) -> c_int; + +/// Alias for the callback to [`pam_set_data`](crate::pam_set_data). +/// +/// ```no_run +/// # use std::ffi::CString; +/// use libpam_sys::{CleanupCallback, pam_set_data}; +/// # use libpam_sys::pam_handle; +/// # let handle: *mut pam_handle = std::ptr::null_mut(); +/// # let mut my_data = 100; +/// # let data_ptr = &mut my_data as *mut i32; +/// fn cleanup() -> CleanupCallback { +/// // ... +/// # unimplemented!() +/// } +/// let name = CString::new("name").unwrap(); +/// unsafe { +/// pam_set_data(handle, name.as_ptr().cast_mut(), data_ptr.cast(), cleanup()); +/// } +/// ``` +pub type CleanupCallback = unsafe extern "C" fn( + pamh: *mut pam_handle, + data: *mut c_void, + pam_end_status: c_int, +); + +/// Used by PAM to communicate between the module and the application. +#[repr(C)] +pub struct pam_conv { + pub conv: unsafe extern "C" fn( + num_msg: c_int, + msg: *const *const pam_message, + resp: *mut *mut pam_response, + appdata: *mut AppData, + ) -> c_int, + pub appdata_ptr: *mut AppData, +} + +/// A message sent into a PAM conversation. +#[repr(C)] +pub struct pam_message { + pub msg_style: c_int, + pub msg: *const c_char, +} + +/// A response returned from a PAM conversation. +#[repr(C)] +pub struct pam_response { + pub resp: *mut c_char, + /// Completely unused. + pub resp_retcode: c_int, +} + + +// These are the functions specified in X/SSO. Everybody exports them. +extern "C" { + /// Account validation. + pub fn pam_acct_mgmt(pamh: *mut pam_handle, flags: c_int) -> c_int; + + /// Authenticate a user. + pub fn pam_authenticate(pamh: *mut pam_handle, flags: c_int) -> c_int; + + // Nobody implements pam_authenticate_secondary. + + /// Manage authentication tokens. + pub fn pam_chauthtok(pamh: *mut pam_handle, flags: c_int) -> c_int; + + /// Close an opened user session. + pub fn pam_close_session(pamh: *mut pam_handle, flags: c_int) -> c_int; + + /// Ends the PAM transaction. + pub fn pam_end(pamh: *mut pam_handle, flags: c_int) -> c_int; + + /// Gets module-specific data. PAM still owns the data. + pub fn pam_get_data( + pamh: *mut pam_handle, + module_data_name: *const c_char, + data: *mut *const c_void, + ) -> c_int; + + /// Gets an environment variable. You own the return value. + pub fn pam_getenv(pamh: *mut pam_handle, name: *const c_char) -> *mut c_char; + + /// Gets all the environment variables. You own everything it points to. + pub fn pam_getenvlist(pamh: *mut pam_handle) -> *mut *mut c_char; + + /// Get information about the transaction. + /// + /// The item is owned by PAM. + pub fn pam_get_item( + pamh: *mut pam_handle, + item_type: c_int, + item: *mut *const c_void, + ) -> c_int; + + // Nobody implements pam_get_mapped_authtok. + // Nobody implements pam_get_mapped_username. + + /// Get the username. PAM owns it. + pub fn pam_get_user( + pamh: *mut pam_handle, + user: *mut *const c_char, + prompt: *const c_char, + ) -> c_int; + + /// Opens a user session. + pub fn pam_open_session(pamh: *mut pam_handle, flags: c_int) -> c_int; + + /// Sets the value of an environment variable. `namevalue` is copied. + pub fn pam_putenv(pamh: *mut pam_handle, namevalue: *const c_char) -> c_int; + + /// Update or delete user credentials. + pub fn pam_setcred(pamh: *mut pam_handle, flags: c_int) -> c_int; + + /// Set module-specific data. PAM will call `cleanup` when completed. + pub fn pam_set_data( + pamh: *mut pam_handle, + module_data_name: *const c_char, + data: *mut c_void, + cleanup: unsafe extern "C" fn( + pamh: *mut pam_handle, + data: *mut c_void, + pam_end_status: c_int, + ), + ) -> c_int; + + /// Set information about the transaction. The `item` is copied. + pub fn pam_set_item(pamh: *mut pam_handle, item_type: c_int, item: *const c_void) -> c_int; + + // Nobody implements pam_set_mapped_authtok. + // Nobody implements pam_set_mapped_username. + + // The pam_sm_whatever functions are prototypes for the functions that + // a PAM module should implement, not symbols provided by PAM. + + // Nobody implements pam_authenticate_secondary. + + /// Starts a PAM transaction. The `conv` may or may not be copied. + pub fn pam_start( + service: *const c_char, + user: *const c_char, + pam_conv: *mut pam_conv, + pamh: *mut *mut pam_handle, + ) -> c_int; + + /// Gets a statically-allocated error string. + /// + /// All implementations of PAM known to this library (Linux-PAM, OpenPAM, + /// and Sun) ignore `pamh` and will accept a null pointer. + pub fn pam_strerror(pamh: *const pam_handle, error_number: c_int) -> *mut c_char; +} + +// We use `_private_pam_impl_hack` because ctest loses its mind +// when it comes across the `cfg_pam_impl` macro. +// This is a custom cfg variable set in our build.rs. Don't do this; just use +// cfg_pam_impl. +#[cfg(_private_pam_impl_hack = "LinuxPam")] +extern "C" { + pub fn pam_get_authtok(pamh: *mut pam_handle, x: c_int, token: *mut *const c_char, prompt: *const c_char) -> c_int; +} + + +// int (*)(struct pam_handle *, char *, void *, void (*)(struct pam_handle *, void *, int)) +// int (*)(struct pam_handle *, char *, void *, int (*)(struct pam_handle *, void *, int)) \ No newline at end of file