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