changeset 125:2b255c92417b

Introduce base PAM functions; use the real X/SSO PAM header for tests.
author Paul Fisher <paul@pfish.zone>
date Mon, 30 Jun 2025 17:47:32 -0400
parents f469b8d9ad78
children 57c812e308bd
files libpam-sys/Cargo.toml libpam-sys/README.md libpam-sys/libpam-sys-test/Cargo.toml libpam-sys/libpam-sys-test/build.rs libpam-sys/libpam-sys-test/xsso_constants.h libpam-sys/libpam-sys-test/xsso_pam_appl.h libpam-sys/src/constants.rs libpam-sys/src/funcs/xsso_base.rs libpam-sys/src/functions.rs libpam-sys/src/helpers.rs libpam-sys/src/lib.rs libpam-sys/src/structs.rs
diffstat 12 files changed, 314 insertions(+), 109 deletions(-) [+]
line wrap: on
line diff
--- a/libpam-sys/Cargo.toml	Mon Jun 30 04:54:38 2025 -0400
+++ b/libpam-sys/Cargo.toml	Mon Jun 30 17:47:32 2025 -0400
@@ -8,6 +8,10 @@
 edition.workspace = true
 rust-version.workspace = true
 
+[features]
+default = ["helpers"]
+helpers = []
+
 [dependencies]
 libpam-sys-impls = { path = "libpam-sys-impls" }
 
--- a/libpam-sys/README.md	Mon Jun 30 04:54:38 2025 -0400
+++ b/libpam-sys/README.md	Mon Jun 30 17:47:32 2025 -0400
@@ -12,7 +12,16 @@
 - Unknown: `XSso`
 
 Each implementation exports all the functionality available in its respective PAM library.
-`XSso` exports only what is in the [X/SSO specification][xsso]. 
+`XSso` exports only what is in the [X/SSO specification][xsso].
+
+## Features
+
+The `helpers` feature (optional, but on by default) exports two helpers for PAM memory management.
+
+- A struct for managing the difference in memory management between Linux-PAM and all other implementations.
+- A struct for handling the Linux-PAM–specific binary data payload structure.
+
+Neither are directly referenced elsewhere, and both allow you to bring your own storage abstractions.
 
 ## References
 
--- a/libpam-sys/libpam-sys-test/Cargo.toml	Mon Jun 30 04:54:38 2025 -0400
+++ b/libpam-sys/libpam-sys-test/Cargo.toml	Mon Jun 30 17:47:32 2025 -0400
@@ -11,6 +11,5 @@
 [build-dependencies]
 bindgen = "0.72.0"
 libpam-sys-impls = { path = "../libpam-sys-impls" }
-libpam-sys = { path = ".." }
 quote = "1.0.40"
-syn = { version = "2.0.104", default-features = false }
+syn = { version = "2.0.104", features = ["full"] }
--- a/libpam-sys/libpam-sys-test/build.rs	Mon Jun 30 04:54:38 2025 -0400
+++ b/libpam-sys/libpam-sys-test/build.rs	Mon Jun 30 17:47:32 2025 -0400
@@ -1,10 +1,13 @@
 use bindgen::MacroTypeVariation;
-use libpam_sys::PamImpl;
+use libpam_sys_impls::__pam_impl_enum__;
 use quote::{format_ident, ToTokens};
 use std::path::PathBuf;
 use std::{env, fs};
 use syn::{Item, ItemConst, Type, TypePath};
 
+// We're using the macro directly so we can match exhaustively.
+__pam_impl_enum__!();
+
 fn main() {
     let config = match PamImpl::CURRENT {
         PamImpl::LinuxPam => TestConfig {
@@ -37,11 +40,10 @@
             ..Default::default()
         },
         PamImpl::XSso => TestConfig {
-            headers: vec!["\"xsso_constants.h\""],
+            headers: vec!["\"xsso_pam_appl.h\""],
             ignore_consts: vec!["PAM_CRED_PRELIM_CHECK"],
             ..Default::default()
         },
-        other => panic!("Unknown PAM implementation {other:?}"),
     };
     generate_const_test(&config);
 }
--- a/libpam-sys/libpam-sys-test/xsso_constants.h	Mon Jun 30 04:54:38 2025 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-// This list of constants was literally cut-and-pasted from:
-// https://pubs.opengroup.org/onlinepubs/8329799/chap5.htm
-
-#define PAM_SUCCESS 0
-#define PAM_OPEN_ERR 1
-#define PAM_SYMBOL_ERR 2
-#define PAM_SERVICE_ERR 3
-#define PAM_SYSTEM_ERR 4
-#define PAM_BUF_ERR 5
-#define PAM_CONV_ERR 6
-#define PAM_PERM_DENIED 7
-#define PAM_MAXTRIES 8
-#define PAM_AUTH_ERR 9
-#define PAM_NEW_AUTHTOK_REQD 10
-#define PAM_CRED_INSUFFICIENT 11
-#define PAM_AUTHINFO_UNAVAIL 12
-#define PAM_USER_UNKNOWN 13
-#define PAM_CRED_UNAVAIL 14
-#define PAM_CRED_EXPIRED 15
-#define PAM_CRED_ERR 16
-#define PAM_ACCT_EXPIRED 17
-#define PAM_AUTHTOK_EXPIRED 18
-#define PAM_SESSION_ERR 19
-#define PAM_AUTHTOK_ERR 20
-#define PAM_AUTHTOK_RECOVERY_ERR 21
-#define PAM_AUTHTOK_LOCK_BUSY 22
-#define PAM_AUTHTOK_DISABLE_AGING 23
-#define PAM_NO_MODULE_DATA 24
-#define PAM_IGNORE 25
-#define PAM_ABORT 26
-#define PAM_TRY_AGAIN 27
-#define PAM_PROMPT_ECHO_OFF 1
-#define PAM_PROMPT_ECHO_ON 2
-#define PAM_ERROR_MSG 3
-#define PAM_TEXT_INFO 4
-#define PAM_MAX_NUM_MSG 32
-#define PAM_MAX_MSG_SIZE 512
-#define PAM_MAX_RESP_SIZE 512
-
-#define PAM_SILENT 0x80000000
-#define PAM_DISALLOW_NULL_AUTHTOK 0x1
-#define PAM_ESTABLISH_CRED 0x1
-#define PAM_DELETE_CRED 0x2
-#define PAM_REINITIALISE_CRED 0x4
-#define PAM_REFRESH_CRED 0x8
-#define PAM_CRED_PRELIM_CHECK 0x1
-#define PAM_UPDATE_AUTHTOK 0x2
-#define PAM_CHANGE_EXPIRED_AUTHTOK 0x4
-
-#define PAM_SERVICE 1
-#define PAM_USER 2
-#define PAM_TTY 3
-#define PAM_RHOST 4
-#define PAM_CONV 5
-#define PAM_AUTHTOK 6
-#define PAM_OLDAUTHTOK 7
-#define PAM_RUSER 8
-#define PAM_USER_PROMPT 9
-
-// Some of the names in here aren't used by anybody, though.
-// These aliases are, though.
-#define PAM_REINITIALIZE_CRED PAM_REINITIALISE_CRED
-#define PAM_PRELIM_CHECK PAM_CRED_PRELIM_CHECK
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpam-sys/libpam-sys-test/xsso_pam_appl.h	Mon Jun 30 17:47:32 2025 -0400
@@ -0,0 +1,139 @@
+/*
+ * The contents of this header are copied directly from the X/SSO PAM spec,
+ * with comments and unpopular functions removed.
+ *
+ * https://pubs.opengroup.org/onlinepubs/8329799/apdxa.htm
+ */
+#define PAM_SUCCESS 0
+#define PAM_OPEN_ERR 1
+#define PAM_SYMBOL_ERR 2
+#define PAM_SERVICE_ERR 3
+#define PAM_SYSTEM_ERR 4
+#define PAM_BUF_ERR 5
+#define PAM_CONV_ERR 6
+#define PAM_PERM_DENIED 7
+#define PAM_MAXTRIES 8
+#define PAM_AUTH_ERR 9
+#define PAM_NEW_AUTHTOK_REQD 10
+#define PAM_CRED_INSUFFICIENT 11
+#define PAM_AUTHINFO_UNAVAIL 12
+#define PAM_USER_UNKNOWN 13
+#define PAM_CRED_UNAVAIL 14
+#define PAM_CRED_EXPIRED 15
+#define PAM_CRED_ERR 16
+#define PAM_ACCT_EXPIRED 17
+#define PAM_AUTHTOK_EXPIRED 18
+#define PAM_SESSION_ERR 19
+#define PAM_AUTHTOK_ERR 20
+#define PAM_AUTHTOK_RECOVERY_ERR 21
+#define PAM_AUTHTOK_LOCK_BUSY 22
+#define PAM_AUTHTOK_DISABLE_AGING 23
+#define PAM_NO_MODULE_DATA 24
+#define PAM_IGNORE 25
+#define PAM_ABORT 26
+#define PAM_TRY_AGAIN 27
+/* PAM_MODULE_UNKNOWN and PAM_DOMAIN_UNKNOWN are not universal. */
+
+struct pam_message {
+  int msg_style;
+  char *msg;
+};
+
+#define PAM_PROMPT_ECHO_OFF 1
+#define PAM_PROMPT_ECHO_ON 2
+#define PAM_ERROR_MSG 3
+#define PAM_TEXT_INFO 4
+
+#define PAM_MAX_NUM_MSG 32
+#define PAM_MAX_MSG_SIZE 512
+#define PAM_MAX_RESP_SIZE 512
+
+struct pam_response {
+  char *resp;
+  int resp_retcode;
+};
+
+struct pam_conv {
+  int (*conv)(int, struct pam_message **, struct pam_response **, void *);
+  void *appdata_ptr;
+};
+
+typedef struct pam_handle pam_handle_t;
+
+extern int pam_start(const char *service_name,
+                     const char *user,
+                     const struct pam_conv *pam_conv,
+                     pam_handle_t **pamh);
+
+extern int pam_end(pam_handle_t *pamh, int status);
+
+extern int pam_set_item(pam_handle_t *pamh, int item_type, const void *item);
+
+extern int pam_get_item(const pam_handle_t *pamh, int item_type, void **item);
+
+#define PAM_SERVICE 1
+#define PAM_USER 2
+#define PAM_TTY 3
+#define PAM_RHOST 4
+#define PAM_CONV 5
+#define PAM_AUTHTOK 6
+#define PAM_OLDAUTHTOK 7
+#define PAM_RUSER 8
+#define PAM_USER_PROMPT 9
+
+extern int pam_get_user(pam_handle_t *pamh, char **user, const char *prompt);
+
+extern int pam_set_data(pam_handle_t *pamh,
+                        const char *module_data_name,
+                        const void *data,
+                        void (*cleanup)(pam_handle_t *pamh,
+                                        void *data,
+                                        int pam_end_status));
+
+extern int pam_get_data(const pam_handle_t *pamh,
+                        const char *module_data_name,
+                        void **data);
+
+extern char *pam_strerror(pam_handle_t *pamh, int errnum);
+
+#define PAM_SILENT 0x80000000
+
+extern int pam_authenticate(pam_handle_t *pamh, int flags);
+
+#define PAM_DISALLOW_NULL_AUTHTOK 0x1
+
+/* Nobody implements pam_authenticate_secondary. */
+
+extern int pam_acct_mgmt(pam_handle_t *pamh, int flags);
+
+extern int pam_open_session(pam_handle_t *pamh, int flags);
+
+extern int pam_close_session(pam_handle_t *pamh, int flags);
+
+extern int pam_setcred(pam_handle_t *pamh, int flags);
+
+#define PAM_ESTABLISH_CRED 0x1
+#define PAM_DELETE_CRED 0x2
+#define PAM_REINITIALIZE_CRED 0x4
+
+#define PAM_REFRESH_CRED 0x8
+
+extern int pam_chauthtok(pam_handle_t *pamh, int flags);
+
+#define PAM_CHANGE_EXPIRED_AUTHTOK 0x4
+
+extern char *pam_getenv(pam_handle_t *pamh, const char *name);
+
+extern char **pam_getenvlist(pam_handle_t *pamh);
+
+extern int pam_putenv(pam_handle_t *pamh, const char *namevalue);
+
+/* Nobody implements the _mapped functions. */
+
+extern int pam_get_user(pam_handle_t *pamh, char **user, const char *prompt);
+
+/* The following constants come from the `pam_module.h` part of the page. */
+#define PAM_PRELIM_CHECK 0x1
+#define PAM_UPDATE_AUTHTOK 0x2
+
+/* The _sm functions are not exported symbols, but prototypes for modules. */
--- a/libpam-sys/src/constants.rs	Mon Jun 30 04:54:38 2025 -0400
+++ b/libpam-sys/src/constants.rs	Mon Jun 30 17:47:32 2025 -0400
@@ -194,8 +194,6 @@
         PAM_REINITIALIZE_CRED = 0b0100;
         PAM_REFRESH_CRED = 0b1000;
     );
-    #[deprecated = "everybody spells it with a Z nowadays"]
-    pub const PAM_REINITIALISE_CRED: i32 = 0b0100;
 
     define!(
         /// A flag for `pam_sm_chauthtok`.
@@ -203,8 +201,6 @@
         PAM_UPDATE_AUTHTOK = 0b0010;
         PAM_CHANGE_EXPIRED_AUTHTOK = 0b0100;
     );
-    #[deprecated = "modern PAM implementations use PAM_PRELIM_CHECK"]
-    pub const PAM_CRED_PRELIM_CHECK: i32 = 0b0001;
 }
 
 #[cfg_pam_impl("OpenPam")]
@@ -272,4 +268,3 @@
     /// A flag for `pam_chauthtok`.
     pub const PAM_NO_AUTHTOK_CHECK: i32 = 0b1000;
 }
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpam-sys/src/funcs/xsso_base.rs	Mon Jun 30 17:47:32 2025 -0400
@@ -0,0 +1,97 @@
+//! Only the very base functions described in the X/SSO specification.
+
+use crate::pam_conv;
+use crate::structs::{pam_handle_t, CleanupCallback};
+use std::ffi::{c_char, c_int, c_void};
+
+extern "C" {
+    /// Account validation.
+    pub fn pam_acct_mgmt(pamh: *mut pam_handle_t, flags: c_int) -> c_int;
+
+    /// Authenticate a user.
+    pub fn pam_authenticate(pamh: *mut pam_handle_t, flags: c_int) -> c_int;
+
+    // Nobody implements pam_authenticate_secondary.
+
+    /// Manage authentication tokens.
+    pub fn pam_chauthtok(pamh: *mut pam_handle_t, flags: c_int) -> c_int;
+
+    /// Close an opened user session.
+    pub fn pam_close_session(pamh: *mut pam_handle_t, flags: c_int) -> c_int;
+
+    /// Ends the PAM transaction.
+    pub fn pam_end(pamh: *mut pam_handle_t, flags: c_int) -> c_int;
+
+    /// Gets module-specific data. PAM still owns the data.
+    pub fn pam_get_data(
+        pamh: *mut pam_handle_t,
+        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_t, 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_t) -> *mut *mut c_char;
+
+    /// Get information about the transaction.
+    pub fn pam_get_item(
+        pamh: *mut pam_handle_t,
+        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.
+    pub fn pam_get_user(
+        pamh: *mut pam_handle_t,
+        user: &mut *const c_char,
+        prompt: *const c_char,
+    ) -> c_int;
+
+    /// Opens a user session.
+    pub fn pam_open_session(pamh: *mut pam_handle_t, flags: c_int) -> c_int;
+
+    /// Sets the value of an environment variable. `namevalue` is copied.
+    pub fn pam_putenv(pamh: *mut pam_handle_t, namevalue: *const c_char) -> c_int;
+
+    /// Update or delete user credentials.
+    pub fn pam_setcred(pamh: *mut pam_handle_t, flags: c_int) -> c_int;
+
+    /// Set module-specific data.
+    pub fn pam_set_data(
+        pamh: *mut pam_handle_t,
+        module_data_name: *const c_char,
+        data: *mut c_void,
+        cleanup: CleanupCallback,
+    ) -> c_int;
+
+    /// Set information about the transaction.  The `item` is copied.
+    pub fn pam_set_item(pamh: *mut pam_handle_t, 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_t,
+    );
+
+    /// 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_t, error_number: c_int) -> *const c_char;
+
+}
--- a/libpam-sys/src/functions.rs	Mon Jun 30 04:54:38 2025 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-
--- a/libpam-sys/src/helpers.rs	Mon Jun 30 04:54:38 2025 -0400
+++ b/libpam-sys/src/helpers.rs	Mon Jun 30 17:47:32 2025 -0400
@@ -57,13 +57,21 @@
 /// ```
 ///
 /// [conversation callback]: crate::ConversationCallback
-/// [message]: crate::Message
+/// [message]: crate::pam_message
 #[derive(Debug)]
 pub struct PtrPtrVec<T> {
     data: Vec<T>,
     pointers: Vec<*const T>,
 }
 
+// Since this is a wrapper around a Vec with no dangerous functionality*,
+// this can be Send and Sync provided the original Vec is.
+//
+// * It will only become unsafe when the user dereferences a pointer or sends it
+// to an unsafe function.
+unsafe impl<T> Send for PtrPtrVec<T> where Vec<T>: Send {}
+unsafe impl<T> Sync for PtrPtrVec<T> where Vec<T>: Sync {}
+
 impl<T> PtrPtrVec<T> {
     /// Takes ownership of the given Vec and creates a vec of pointers to it.
     pub fn new(data: Vec<T>) -> Self {
@@ -509,14 +517,16 @@
     fn test_iter_ptr_ptr() {
         let strs = vec![Box::new("a"), Box::new("b"), Box::new("c"), Box::new("D")];
         let ptr: *const *const &str = strs.as_ptr().cast();
-        let got: Vec<&str> = unsafe {
-            PtrPtrVec::iter_over_linux(ptr, 4)
-        }.cloned().collect();
+        let got: Vec<&str> = unsafe { PtrPtrVec::iter_over_linux(ptr, 4) }
+            .cloned()
+            .collect();
         assert_eq!(vec!["a", "b", "c", "D"], got);
 
         let nums = [-1i8, 2, 3];
         let ptr = nums.as_ptr();
-        let got: Vec<u8> = unsafe { PtrPtrVec::iter_over_xsso(&ptr, 3)}.cloned().collect();
+        let got: Vec<u8> = unsafe { PtrPtrVec::iter_over_xsso(&ptr, 3) }
+            .cloned()
+            .collect();
         assert_eq!(vec![255, 2, 3], got);
     }
 }
--- a/libpam-sys/src/lib.rs	Mon Jun 30 04:54:38 2025 -0400
+++ b/libpam-sys/src/lib.rs	Mon Jun 30 17:47:32 2025 -0400
@@ -6,11 +6,6 @@
 
 use libpam_sys_impls::{__pam_impl_enum__, __pam_impl_name__};
 
-mod constants;
-mod functions;
-pub mod helpers;
-mod structs;
-
 /// A `cfg`-like attribute macro for code specific to one PAM implementation.
 ///
 /// Different versions of PAM export different functions and have some
@@ -48,9 +43,17 @@
 #[doc(inline)]
 pub use libpam_sys_impls::cfg_pam_impl;
 
+mod constants;
+// We get `funcs` from different places depending upon the PAM implementation.
+// This is because
+#[path = "funcs/xsso_base.rs"]
+mod funcs;
+pub mod helpers;
+mod structs;
+
+#[doc(inline)]
+pub use crate::{constants::*, funcs::*, structs::*};
+
 // Looking for the actual code defining this enum?
 // It's in the build.rs file for libpam_sys_impls.
 __pam_impl_enum__!(#[non_exhaustive]);
-
-#[doc(inline)]
-pub use crate::{constants::*, structs::*};
--- a/libpam-sys/src/structs.rs	Mon Jun 30 04:54:38 2025 -0400
+++ b/libpam-sys/src/structs.rs	Mon Jun 30 17:47:32 2025 -0400
@@ -1,11 +1,17 @@
+//! Structs and wrappers that PAM is made of.
+#![allow(non_camel_case_types)]
+
 use std::ffi::{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(transparent)]
-struct ExtremelyUnsafe(PhantomData<(PhantomPinned, *mut c_void)>);
+#[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 {
@@ -17,20 +23,17 @@
 ///
 /// This is only ever returned in pointer form and cannot be constructed.
 #[repr(C)]
-pub struct PamHandle {
-    _marker: ExtremelyUnsafe,
-}
+pub struct pam_handle_t(ExtremelyUnsafe);
 
-impl fmt::Debug for PamHandle {
+impl fmt::Debug for pam_handle_t {
     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.
-pub struct AppData {
-    _marker: ExtremelyUnsafe,
-}
+#[repr(C)]
+pub struct AppData(ExtremelyUnsafe);
 
 impl fmt::Debug for AppData {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -47,30 +50,38 @@
     // This is a *const *const because accessing memory from a reference
     // outside its bounds is undefined behavior, and *messages is an array
     // in X/SSO PAM impls.
-    messages: *const *const Message,
-    // This is a &mut *mut because the caller sets the pointer in `responses`
+    msg: *const *const pam_message,
+    // This is a &mut *mut because the caller sets the pointer in `resp`
     // but does not mess around outside its memory space.
-    responses: &mut *mut Response,
+    resp: &mut *mut pam_response,
     appdata: *const AppData,
 ) -> c_int;
 
+/// Called to clean up data set using [`pam_set_data`](crate::pam_set_data).
+pub type CleanupCallback = unsafe extern "C" fn(
+    pamh: *mut pam_handle_t,
+    data: *mut c_void,
+    pam_end_status: c_int,
+) -> c_int;
+
 /// Used by PAM to communicate between the module and the application.
 #[repr(C)]
-pub struct Conversation {
-    pub callback: ConversationCallback,
-    pub appdata: *const AppData,
+pub struct pam_conv {
+    pub conv: ConversationCallback,
+    pub appdata_ptr: *const AppData,
 }
 
 /// A message sent into a PAM conversation.
 #[repr(C)]
-pub struct Message {
-    pub style: c_int,
-    pub data: *const c_void,
+pub struct pam_message {
+    pub msg_style: c_int,
+    pub msg: *const c_void,
 }
 
 /// A response returned from a PAM conversation.
 #[repr(C)]
-pub struct Response {
-    pub data: *mut c_void,
-    pub _unused: c_int,
+pub struct pam_response {
+    pub resp: *mut c_void,
+    /// Completely unused.
+    pub resp_retcode: c_int,
 }