Mercurial > crates > nonstick
changeset 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 | 57c812e308bd |
children | ad77f2af5ff4 |
files | Cargo.lock libpam-sys/Cargo.toml libpam-sys/build.rs libpam-sys/libpam-sys-impls/build.rs libpam-sys/libpam-sys-test/Cargo.toml libpam-sys/libpam-sys-test/build.rs libpam-sys/libpam-sys-test/tests/ctest.rs libpam-sys/libpam-sys-test/tests/runner.rs libpam-sys/libpam-sys-test/tests/test_constants.rs libpam-sys/src/constants.rs libpam-sys/src/ffi.rs libpam-sys/src/funcs/xsso_base.rs libpam-sys/src/helpers.rs libpam-sys/src/lib.rs libpam-sys/src/structs.rs testharness/src/lib.rs |
diffstat | 16 files changed, 555 insertions(+), 216 deletions(-) [+] |
line wrap: on
line diff
--- a/Cargo.lock Mon Jun 30 21:52:10 2025 -0400 +++ b/Cargo.lock Mon Jun 30 22:56:26 2025 -0400 @@ -29,7 +29,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f72209734318d0b619a5e0f5129918b848c416e122a3c4ce054e03cb87b726f" dependencies = [ - "bitflags", + "bitflags 2.9.1", "cexpr", "clang-sys", "itertools", @@ -45,6 +45,12 @@ [[package]] name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" @@ -55,13 +61,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" dependencies = [ - "semver", + "semver 0.9.0", "serde", "serde_derive", "serde_json", ] [[package]] +name = "cc" +version = "1.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +dependencies = [ + "shlex", +] + +[[package]] name = "cexpr" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -72,6 +87,12 @@ [[package]] name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" @@ -88,6 +109,39 @@ ] [[package]] +name = "ctest" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f18c94d081f9a0355affbeee3f8e677ce206e9aea89b952421f0be6bc588dde" +dependencies = [ + "cc", + "garando_syntax", + "indoc", + "rustc_version", +] + +[[package]] +name = "dirs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" +dependencies = [ + "cfg-if 0.1.10", + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] name = "dlopen" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -123,6 +177,54 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] +name = "garando_errors" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18495ec4aced5922809efe4d2862918ff0e8d75e122bde57bba9bae45965256a" +dependencies = [ + "garando_pos", + "libc", + "serde", + "term", + "unicode-xid 0.2.6", +] + +[[package]] +name = "garando_pos" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9386fc75dca486daefbbf5a8d2ea6f379237f95c9b982776159cd66f220aaf" +dependencies = [ + "serde", +] + +[[package]] +name = "garando_syntax" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8a383861d12fc78c251bbcb1ec252dd8338714ce02ab0cc393cfd02f40d32b" +dependencies = [ + "bitflags 1.3.2", + "garando_errors", + "garando_pos", + "log", + "serde", + "serde_json", + "unicode-xid 0.2.6", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if 1.0.1", + "libc", + "wasi", +] + +[[package]] name = "glob" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -151,6 +253,12 @@ ] [[package]] +name = "indoc" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" + +[[package]] name = "itertools" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -183,7 +291,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ - "cfg-if", + "cfg-if 1.0.1", "windows-targets", ] @@ -192,6 +300,7 @@ version = "0.1.0" dependencies = [ "libpam-sys-impls", + "strum", ] [[package]] @@ -211,13 +320,26 @@ version = "0.0.0" dependencies = [ "bindgen", + "ctest", + "libc", "libpam-sys", "libpam-sys-impls", + "proc-macro2 1.0.95", "quote 1.0.40", "syn 2.0.104", ] [[package]] +name = "libredox" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" +dependencies = [ + "bitflags 2.9.1", + "libc", +] + +[[package]] name = "log" version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -259,7 +381,7 @@ version = "0.0.8-alpha0" dependencies = [ "bindgen", - "bitflags", + "bitflags 2.9.1", "libc", "libpam-sys", "memoffset", @@ -274,7 +396,7 @@ "anyhow", "nonstick", "test-cdylib", - "thiserror", + "thiserror 2.0.12", ] [[package]] @@ -324,7 +446,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" dependencies = [ - "unicode-xid", + "unicode-xid 0.1.0", ] [[package]] @@ -355,6 +477,17 @@ ] [[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror 1.0.69", +] + +[[package]] name = "regex" version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -390,6 +523,15 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.26", +] + +[[package]] name = "rustversion" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -412,6 +554,12 @@ ] [[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -485,7 +633,7 @@ dependencies = [ "proc-macro2 0.4.30", "quote 0.6.13", - "unicode-xid", + "unicode-xid 0.1.0", ] [[package]] @@ -500,6 +648,16 @@ ] [[package]] +name = "term" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" +dependencies = [ + "dirs", + "winapi", +] + +[[package]] name = "test-cdylib" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -513,11 +671,31 @@ [[package]] name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2 1.0.95", + "quote 1.0.40", + "syn 2.0.104", ] [[package]] @@ -570,6 +748,18 @@ checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" [[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index"
--- a/libpam-sys/Cargo.toml Mon Jun 30 21:52:10 2025 -0400 +++ b/libpam-sys/Cargo.toml Mon Jun 30 22:56:26 2025 -0400 @@ -17,3 +17,4 @@ [build-dependencies] libpam-sys-impls = { path = "libpam-sys-impls" } +strum = { version = "0.27.1", features = ["derive"] }
--- a/libpam-sys/build.rs Mon Jun 30 21:52:10 2025 -0400 +++ b/libpam-sys/build.rs Mon Jun 30 22:56:26 2025 -0400 @@ -1,3 +1,13 @@ +use libpam_sys_impls::__pam_impl_enum__; +use strum::{EnumIter, IntoEnumIterator}; + +__pam_impl_enum__!(#[derive(EnumIter)]); + fn main() { println!("cargo:rustc-link-lib=pam"); + let pam_impl_strs: Vec<_> = PamImpl::iter().map(|e| format!("\"{:?}\"", e)).collect(); + let pam_impls = pam_impl_strs.join(","); + // We use this for ctest. Don't do what we've done; just use cfg_pam_impl. + println!("cargo:check-cfg=cfg(_private_pam_impl_hack, values({pam_impls}))"); + println!("cargo:rustc-cfg=_private_pam_impl_hack=\"{:?}\"", PamImpl::CURRENT); }
--- a/libpam-sys/libpam-sys-impls/build.rs Mon Jun 30 21:52:10 2025 -0400 +++ b/libpam-sys/libpam-sys-impls/build.rs Mon Jun 30 22:56:26 2025 -0400 @@ -5,6 +5,9 @@ //! into the `__pam_impl_enum__` macro. //! 2. It detects the current PAM implementation and sets an env var for //! the macros in `libpam-sys-impl`. +//! +//! We need to have this detection here for `#[cfg_pam_impl]` to work properly +//! when exported to downstream crates. use dlopen::raw::Library; use proc_macro2::TokenStream;
--- a/libpam-sys/libpam-sys-test/Cargo.toml Mon Jun 30 21:52:10 2025 -0400 +++ b/libpam-sys/libpam-sys-test/Cargo.toml Mon Jun 30 22:56:26 2025 -0400 @@ -6,10 +6,13 @@ publish = false [dependencies] +libc = "0.2.174" libpam-sys = { path = ".." } [build-dependencies] bindgen = "0.72.0" +ctest = "0.4.11" libpam-sys-impls = { path = "../libpam-sys-impls" } +proc-macro2 = "1.0.95" quote = "1.0.40" syn = { version = "2.0.104", features = ["full"] }
--- a/libpam-sys/libpam-sys-test/build.rs Mon Jun 30 21:52:10 2025 -0400 +++ b/libpam-sys/libpam-sys-test/build.rs Mon Jun 30 22:56:26 2025 -0400 @@ -1,7 +1,10 @@ use bindgen::MacroTypeVariation; use libpam_sys_impls::__pam_impl_enum__; +use proc_macro2::{Group, TokenStream, TokenTree}; use quote::{format_ident, ToTokens}; -use std::path::PathBuf; +use std::path::Path; +use std::process::Command; +use std::str::FromStr; use std::{env, fs}; use syn::{Item, ItemConst, Type, TypePath}; @@ -46,6 +49,7 @@ }, }; generate_const_test(&config); + generate_ctest(&config); } fn generate_const_test(config: &TestConfig) { @@ -63,8 +67,15 @@ let generated = builder.generate().unwrap().to_string(); let file = syn::parse_file(&generated).unwrap(); - let mut tests = vec![]; - tests.push("{".into()); + let mut tests = vec![ + "use libpam_sys::*;".into(), + "#[allow(deprecated, overflowing_literals)]".into(), + "fn main() {".into(), + format!( + "assert_eq!(PamImpl::CURRENT, PamImpl::{:?});", + PamImpl::CURRENT + ), + ]; tests.extend( file.items .iter() @@ -83,18 +94,97 @@ path: format_ident!("i32").into(), })); format!( - "assert_eq!({tokens}, libpam_sys::{name});", + "assert_eq!({tokens}, {name});", tokens = item.expr.to_token_stream(), name = item.ident ) }), ); tests.push("}".into()); - fs::write( - PathBuf::from(env::var("OUT_DIR").unwrap()).join("constant_test.rs"), - tests.join("\n"), + let const_test = test_file("constant_test.rs"); + fs::write(&const_test, tests.join("\n")).unwrap(); + rustfmt(&const_test); +} + +fn generate_ctest(config: &TestConfig) { + let mut test = ctest::TestGenerator::new(); + + for header in config.headers.iter() { + if header.starts_with('"') { + test.include(env::var("CARGO_MANIFEST_DIR").unwrap()); + } + test.header(&header[1..header.len() - 1]); + } + // These are opaque structs. + test.skip_struct(|name| matches!(name, "pam_handle" | "AppData")); + test.skip_type(|name| matches!(name, "ConversationCallback" | "CleanupCallback")); + test.type_name(|name, _is_struct, is_union| { + assert!(!is_union); // we scabbin' + match name { + "pam_handle" => "struct pam_handle", + "pam_conv" => "struct pam_conv", + "pam_message" => "struct pam_message", + "pam_response" => "struct pam_response", + "AppData" => "void", + other => other, + } + .into() + }); + + // + // Welcome to THE HACK ZONE. + // + + // Define away constness because the various PAM implementations + // have different const annotations and this will surely drive you crazy. + test.define("const", Some("")); + + // Also replace all the `const`s with `mut`s in the ffi.rs file. + let file_contents = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../src/ffi.rs")); + let deconsted_file = test_file("ffi.rs"); + remove_consts(file_contents, &deconsted_file); + + test.generate(&deconsted_file, "ctest.rs"); +} + +fn remove_consts(file_contents: &str, out_file: impl AsRef<Path>) { + let deconstified = deconstify( + TokenStream::from_str(file_contents).unwrap(), + &TokenStream::from_str("mut") + .unwrap() + .into_iter() + .next() + .unwrap(), ) - .unwrap(); + .to_string(); + let out_file = out_file.as_ref(); + fs::write(out_file, deconstified).unwrap(); + rustfmt(out_file) +} + +fn rustfmt(file: impl AsRef<Path>) { + let status = Command::new(env!("CARGO")) + .args(["fmt", "--", file.as_ref().to_str().unwrap()]) + .status() + .unwrap(); + assert!(status.success(), "rustfmt exited with code {status}"); +} + +fn deconstify(stream: TokenStream, mut_token: &TokenTree) -> TokenStream { + TokenStream::from_iter(stream.into_iter().map(|token| { + match token { + TokenTree::Group(g) => { + TokenTree::Group(Group::new(g.delimiter(), deconstify(g.stream(), mut_token))) + .into_token_stream() + } + TokenTree::Ident(id) if id == "const" => mut_token.into_token_stream(), + other => other.into_token_stream(), + } + })) +} + +fn test_file(name: impl AsRef<str>) -> String { + format!("{}/{}", env::var("OUT_DIR").unwrap(), name.as_ref()) } #[derive(Default)]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpam-sys/libpam-sys-test/tests/ctest.rs Mon Jun 30 22:56:26 2025 -0400 @@ -0,0 +1,4 @@ +#![allow(unused_imports, clippy::all)] +use libpam_sys::*; + +include!(concat!(env!("OUT_DIR"), "/ctest.rs"));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpam-sys/libpam-sys-test/tests/runner.rs Mon Jun 30 22:56:26 2025 -0400 @@ -0,0 +1,1 @@ +include!(concat!(env!("OUT_DIR"), "/constant_test.rs"));
--- a/libpam-sys/libpam-sys-test/tests/test_constants.rs Mon Jun 30 21:52:10 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -#[allow(deprecated, overflowing_literals)] -#[test] -fn check_constants() { - include!(concat!(env!("OUT_DIR"), "/constant_test.rs")) -}
--- a/libpam-sys/src/constants.rs Mon Jun 30 21:52:10 2025 -0400 +++ b/libpam-sys/src/constants.rs Mon Jun 30 22:56:26 2025 -0400 @@ -127,6 +127,7 @@ ); c_enum!( + /// An item type (Linux-only). PAM_FAIL_DELAY = 10, PAM_XDISPLAY, PAM_XAUTHDATA,
--- /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
--- a/libpam-sys/src/funcs/xsso_base.rs Mon Jun 30 21:52:10 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -//! 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/helpers.rs Mon Jun 30 21:52:10 2025 -0400 +++ b/libpam-sys/src/helpers.rs Mon Jun 30 22:56:26 2025 -0400 @@ -1,6 +1,7 @@ //! This module contains a few non-required helpers to deal with some of the //! more annoying memory management in the PAM API. +use super::cfg_pam_impl; use std::error::Error; use std::marker::{PhantomData, PhantomPinned}; use std::mem::ManuallyDrop; @@ -132,7 +133,7 @@ slice::from_raw_parts(*ptr_ptr.cast(), count).iter() } - #[crate::cfg_pam_impl("LinuxPam")] + #[cfg_pam_impl("LinuxPam")] unsafe fn _iter_over<'a, Src>( ptr_ptr: *const *const Src, count: usize, @@ -144,7 +145,7 @@ Self::iter_over_linux(ptr_ptr, count) } - #[crate::cfg_pam_impl(not("LinuxPam"))] + #[cfg_pam_impl(not("LinuxPam"))] unsafe fn _iter_over<'a, Src>( ptr_ptr: *const *const Src, count: usize, @@ -478,7 +479,7 @@ #[should_panic] fn test_iter_xsso_wrong_size() { unsafe { - _ = PtrPtrVec::<u8>::iter_over_xsso::<f64>(ptr::null(), 1); + let _ = PtrPtrVec::<u8>::iter_over_xsso::<f64>(ptr::null(), 1); } } @@ -488,7 +489,7 @@ #[should_panic] fn test_iter_linux_wrong_size() { unsafe { - _ = PtrPtrVec::<u128>::iter_over_linux::<()>(ptr::null(), 1); + let _ = PtrPtrVec::<u128>::iter_over_linux::<()>(ptr::null(), 1); } }
--- a/libpam-sys/src/lib.rs Mon Jun 30 21:52:10 2025 -0400 +++ b/libpam-sys/src/lib.rs Mon Jun 30 22:56:26 2025 -0400 @@ -44,15 +44,11 @@ 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; +mod ffi; pub mod helpers; -mod structs; #[doc(inline)] -pub use crate::{constants::*, funcs::*, structs::*}; +pub use crate::{constants::*, ffi::*}; // Looking for the actual code defining this enum? // It's in the build.rs file for libpam_sys_impls.
--- a/libpam-sys/src/structs.rs Mon Jun 30 21:52:10 2025 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -//! 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(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_t(ExtremelyUnsafe); - -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. -#[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}") - } -} - -/// The callback that PAM uses to get information in a conversation. -/// -/// For important details about the format of `messages`, -/// see the [`helpers`](crate::helpers) module. -pub type ConversationCallback = unsafe extern "C" fn( - num_msg: c_int, - // 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. - 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. - 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 pam_conv { - pub conv: ConversationCallback, - pub appdata_ptr: *const AppData, -} - -/// A message sent into a PAM conversation. -#[repr(C)] -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 pam_response { - pub resp: *mut c_void, - /// Completely unused. - pub resp_retcode: c_int, -}
--- a/testharness/src/lib.rs Mon Jun 30 21:52:10 2025 -0400 +++ b/testharness/src/lib.rs Mon Jun 30 22:56:26 2025 -0400 @@ -11,7 +11,11 @@ Ok(()) } - fn account_management(_handle: &mut M, _args: Vec<&CStr>, _flags: Flags) -> nonstick::Result<()> { + fn account_management( + _handle: &mut M, + _args: Vec<&CStr>, + _flags: Flags, + ) -> nonstick::Result<()> { Ok(()) } }