Mercurial > crates > nonstick
changeset 66:a674799a5cd3
Make `PamHandle` and `PamModuleHandle` traits.
This creates traits for PAM functionality and pulls the definitions
of that functionality out of the original `PamHandle` (renamed to
`LibPamHandle`) and into those traits. This supports testing PAM
module implementations using mock PAM library implementations.
Also uses a better representation of opaque pointers.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Tue, 27 May 2025 14:37:28 -0400 |
parents | 8e507c7af9cf |
children | 71e432a213ee |
files | Cargo.toml src/handle.rs src/items.rs src/lib.rs src/module.rs src/pam_ffi.rs |
diffstat | 6 files changed, 219 insertions(+), 121 deletions(-) [+] |
line wrap: on
line diff
--- a/Cargo.toml Thu May 22 02:08:10 2025 -0400 +++ b/Cargo.toml Tue May 27 14:37:28 2025 -0400 @@ -1,7 +1,7 @@ [package] name = "nonstick" description = "PAM bindings for Rust" -version = "0.0.5" +version = "0.0.6-dev0" authors = ["Paul Fisher <paul@pfish.zone>", "Anthony Nowell <anowell@gmail.com>" ] repository = "https://hg.pfish.zone/crates/nonstick/" readme = "README.md"
--- a/src/handle.rs Thu May 22 02:08:10 2025 -0400 +++ b/src/handle.rs Tue May 27 14:37:28 2025 -0400 @@ -1,18 +1,17 @@ -//! Where [PamHandle] lives. +//! The wrapper types and traits for handles into the PAM library. +use crate::constants::{ErrorCode, Result}; use crate::items::{Item, ItemType}; -use crate::{memory, pam_ffi, ErrorCode}; +use crate::{memory, pam_ffi}; use libc::c_char; use secure_string::SecureString; use std::ffi::{c_int, CString}; +use std::mem; -/// Your interface to a PAM handle. +/// Features of a PAM handle that are available to applications and modules. /// -/// This structure wraps an opaque PAM-provided pointer and gives you -/// a safe and familiar struct-based API to interact with PAM. -#[repr(transparent)] -pub struct PamHandle(*mut libc::c_void); - -impl PamHandle { +/// You probably want [`LibPamHandle`]. This trait is intended to allow creating +/// mock PAM handle types used for testing PAM modules and applications. +pub trait PamHandle { /// Retrieves the name of the user who is authenticating or logging in. /// /// This is effectively like `handle.get_item::<Item::User>()`. @@ -23,7 +22,7 @@ /// /// ```no_run /// # use nonstick::PamHandle; - /// # fn _doc(handle: &PamHandle) -> Result<(), Box<dyn std::error::Error>> { + /// # fn _doc(handle: &impl PamHandle) -> Result<(), Box<dyn std::error::Error>> { /// // Get the username using the default prompt. /// let user = handle.get_user(None)?; /// // Get the username using a custom prompt. @@ -31,18 +30,10 @@ /// # Ok(()) /// # } /// ``` - /// + /// /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_user.3.html /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_user - pub fn get_user(&self, prompt: Option<&str>) -> crate::Result<String> { - let prompt = memory::option_cstr(prompt)?; - let mut output: *const c_char = std::ptr::null_mut(); - let ret = unsafe { - pam_ffi::pam_get_user(self.0, &mut output, memory::prompt_ptr(prompt.as_ref())) - }; - ErrorCode::result_from(ret)?; - memory::copy_pam_string(output) - } + fn get_user(&self, prompt: Option<&str>) -> Result<String>; /// Retrieves the authentication token from the user. /// @@ -55,7 +46,7 @@ /// /// ```no_run /// # use nonstick::PamHandle; - /// # fn _doc(handle: &PamHandle) -> Result<(), Box<dyn std::error::Error>> { + /// # fn _doc(handle: &impl PamHandle) -> Result<(), Box<dyn std::error::Error>> { /// // Get the user's password using the default prompt. /// let pass = handle.get_authtok(None)?; /// // Get the user's password using a custom prompt. @@ -63,23 +54,10 @@ /// Ok(()) /// # } /// ``` - /// + /// /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_authtok.3.html /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_item - pub fn get_authtok(&self, prompt: Option<&str>) -> crate::Result<SecureString> { - let prompt = memory::option_cstr(prompt)?; - let mut output: *const c_char = std::ptr::null_mut(); - let res = unsafe { - pam_ffi::pam_get_authtok( - self.0, - ItemType::AuthTok.into(), - &mut output, - memory::prompt_ptr(prompt.as_ref()), - ) - }; - ErrorCode::result_from(res)?; - memory::copy_pam_string(output).map(SecureString::from) - } + fn get_authtok(&self, prompt: Option<&str>) -> Result<SecureString>; /// Retrieves an [Item] that has been set, possibly by the PAM client. /// @@ -96,7 +74,7 @@ /// # use nonstick::PamHandle; /// use nonstick::items::Service; /// - /// # fn _doc(pam_handle: &PamHandle) -> Result<(), Box<dyn std::error::Error>> { + /// # fn _doc(pam_handle: &impl PamHandle) -> Result<(), Box<dyn std::error::Error>> { /// let svc: Option<Service> = pam_handle.get_item()?; /// match svc { /// Some(name) => eprintln!("The calling service name is {:?}", name.to_string_lossy()), @@ -108,19 +86,7 @@ /// /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_item.3.html /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_item - pub fn get_item<T: Item>(&self) -> crate::Result<Option<T>> { - let mut ptr: *const libc::c_void = std::ptr::null(); - let out = unsafe { - let ret = pam_ffi::pam_get_item(self.0, T::type_id().into(), &mut ptr); - ErrorCode::result_from(ret)?; - let typed_ptr: *const T::Raw = ptr.cast(); - match typed_ptr.is_null() { - true => None, - false => Some(T::from_raw(typed_ptr)), - } - }; - Ok(out) - } + fn get_item<T: Item>(&self) -> Result<Option<T>>; /// Sets an item in the PAM context. It can be retrieved using [`get_item`](Self::get_item). /// @@ -129,12 +95,40 @@ /// /// [man]: https://www.man7.org/linux/man-pages/man3/pam_set_item.3.html /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_set_item - pub fn set_item<T: Item>(&mut self, item: T) -> crate::Result<()> { - let ret = - unsafe { pam_ffi::pam_set_item(self.0, T::type_id().into(), item.into_raw().cast()) }; - ErrorCode::result_from(ret) - } + fn set_item<T: Item>(&mut self, item: T) -> Result<()>; + /// Closes the PAM session on an owned PAM handle. + /// + /// This should be called with the result of the application's last call + /// into PAM services. Since this is only applicable to *owned* PAM handles, + /// a PAM module should never call this (and it will never be handed + /// an owned `PamHandle` that it can `close`). + /// + /// See the [`pam_end` manual page][man] for more information. + /// + /// ```no_run + /// # use nonstick::PamHandle; + /// # use std::error::Error; + /// # fn _doc(handle: impl PamHandle, auth_result: nonstick::Result<()>) -> Result<(), Box<dyn Error>> { + /// // Earlier: authentication was performed and the result was stored + /// // into auth_result. + /// handle.close(auth_result)?; + /// # Ok(()) + /// # } + /// ``` + /// + /// [man]: https://www.man7.org/linux/man-pages/man3/pam_end.3.html + fn close(self, status: Result<()>) -> Result<()>; +} + +/// Functionality of a PAM handle that can be expected by a PAM module. +/// +/// If you are not writing a PAM module (e.g., you are writing an application), +/// you should not use any of the functionality exposed by this trait. +/// +/// Like [`PamHandle`], this is intended to allow creating mock implementations +/// of PAM for testing PAM modules. +pub trait PamModuleHandle: PamHandle { /// Gets some pointer, identified by `key`, that has been set previously /// using [`set_data`](Self::set_data). /// @@ -151,18 +145,7 @@ /// /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_data.3.html /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_data - pub unsafe fn get_data<T>(&self, key: &str) -> crate::Result<Option<&T>> { - let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; - let mut ptr: *const libc::c_void = std::ptr::null(); - ErrorCode::result_from(pam_ffi::pam_get_data(self.0, c_key.as_ptr(), &mut ptr))?; - match ptr.is_null() { - true => Ok(None), - false => { - let typed_ptr = ptr.cast(); - Ok(Some(&*typed_ptr)) - } - } - } + unsafe fn get_data<T>(&self, key: &str) -> Result<Option<&T>>; /// Stores a pointer that can be retrieved later with [`get_data`](Self::get_data). /// @@ -176,33 +159,126 @@ /// /// [man]: https://www.man7.org/linux/man-pages/man3/pam_set_data.3.html /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_set_data - pub fn set_data<T>(&mut self, key: &str, data: Box<T>) -> crate::Result<()> { - let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; + fn set_data<T>(&mut self, key: &str, data: Box<T>) -> Result<()>; +} + +/// A [`PamHandle`] backed by `libpam`, i.e., a real PAM handle. +/// +/// This structure wraps an opaque PAM handle and gives you a nice Rusty +/// interface to use PAM. +#[repr(C)] +pub struct LibPamHandle(pam_ffi::Handle); + +impl LibPamHandle { + /// Converts a pointer passed from PAM into a borrowed handle. + /// + /// # Safety + /// + /// It is your responsibility to provide a valid pointer. + pub unsafe fn from_ptr<'a>(ptr: *mut libc::c_void) -> &'a mut LibPamHandle { + &mut *(ptr as *mut LibPamHandle) + } +} + +impl Drop for LibPamHandle { + /// Ends the PAM session with a zero error code. + fn drop(&mut self) { + unsafe { + pam_ffi::pam_end(&mut self.0, 0); + } + } +} + +impl PamHandle for LibPamHandle { + fn get_user(&self, prompt: Option<&str>) -> crate::Result<String> { + let prompt = memory::option_cstr(prompt)?; + let mut output: *const c_char = std::ptr::null_mut(); let ret = unsafe { - pam_ffi::pam_set_data( - self.0, - c_key.as_ptr(), - Box::into_raw(data).cast(), - Self::set_data_cleanup::<T>, + pam_ffi::pam_get_user(&self.0, &mut output, memory::prompt_ptr(prompt.as_ref())) + }; + ErrorCode::result_from(ret)?; + memory::copy_pam_string(output) + } + + fn get_authtok(&self, prompt: Option<&str>) -> crate::Result<SecureString> { + let prompt = memory::option_cstr(prompt)?; + let mut output: *const c_char = std::ptr::null_mut(); + let res = unsafe { + pam_ffi::pam_get_authtok( + &self.0, + ItemType::AuthTok.into(), + &mut output, + memory::prompt_ptr(prompt.as_ref()), ) }; + ErrorCode::result_from(res)?; + memory::copy_pam_string(output).map(SecureString::from) + } + + fn get_item<T: Item>(&self) -> crate::Result<Option<T>> { + let mut ptr: *const libc::c_void = std::ptr::null(); + let out = unsafe { + let ret = pam_ffi::pam_get_item(&self.0, T::type_id().into(), &mut ptr); + ErrorCode::result_from(ret)?; + let typed_ptr: *const T::Raw = ptr.cast(); + match typed_ptr.is_null() { + true => None, + false => Some(T::from_raw(typed_ptr)), + } + }; + Ok(out) + } + + fn set_item<T: Item>(&mut self, item: T) -> crate::Result<()> { + let ret = unsafe { + pam_ffi::pam_set_item(&mut self.0, T::type_id().into(), item.into_raw().cast()) + }; ErrorCode::result_from(ret) } - /// Function called at the end of a PAM session that is called to clean up - /// a value previously provided to PAM in a `pam_set_data` call. - /// - /// You should never call this yourself. - extern "C" fn set_data_cleanup<T>(_: *const libc::c_void, c_data: *mut libc::c_void, _: c_int) { - unsafe { - let _data: Box<T> = Box::from_raw(c_data.cast()); - } + fn close(mut self, status: Result<()>) -> Result<()> { + let result = unsafe { pam_ffi::pam_end(&mut self.0, ErrorCode::result_to_c(status)) }; + // Since we've already `pam_end`ed this session, we don't want it to be + // double-freed on drop. + mem::forget(self); + ErrorCode::result_from(result) } } -impl From<*mut libc::c_void> for PamHandle { - /// Wraps an internal Handle pointer. - fn from(value: *mut libc::c_void) -> Self { - Self(value) +impl PamModuleHandle for LibPamHandle { + unsafe fn get_data<T>(&self, key: &str) -> crate::Result<Option<&T>> { + let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; + let mut ptr: *const libc::c_void = std::ptr::null(); + ErrorCode::result_from(pam_ffi::pam_get_data(&self.0, c_key.as_ptr(), &mut ptr))?; + match ptr.is_null() { + true => Ok(None), + false => { + let typed_ptr = ptr.cast(); + Ok(Some(&*typed_ptr)) + } + } + } + + fn set_data<T>(&mut self, key: &str, data: Box<T>) -> crate::Result<()> { + let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?; + let ret = unsafe { + pam_ffi::pam_set_data( + &mut self.0, + c_key.as_ptr(), + Box::into_raw(data).cast(), + set_data_cleanup::<T>, + ) + }; + ErrorCode::result_from(ret) } } + +/// Function called at the end of a PAM session that is called to clean up +/// a value previously provided to PAM in a `pam_set_data` call. +/// +/// You should never call this yourself. +extern "C" fn set_data_cleanup<T>(_: *const libc::c_void, c_data: *mut libc::c_void, _: c_int) { + unsafe { + let _data: Box<T> = Box::from_raw(c_data.cast()); + } +}
--- a/src/items.rs Thu May 22 02:08:10 2025 -0400 +++ b/src/items.rs Tue May 27 14:37:28 2025 -0400 @@ -54,7 +54,7 @@ } } -/// A type that can be requested by [`PamHandle::get_item`](crate::PamHandle::get_item). +/// A type that can be requested by [`PamHandle::get_item`](crate::LibPamHandle::get_item). pub trait Item { /// The `repr(C)` type that is returned (by pointer) by the underlying `pam_get_item` function. /// This memory is owned by the PAM session.
--- a/src/lib.rs Thu May 22 02:08:10 2025 -0400 +++ b/src/lib.rs Tue May 27 14:37:28 2025 -0400 @@ -35,6 +35,6 @@ #[doc(inline)] pub use crate::{ constants::{ErrorCode, Flags, Result}, - handle::PamHandle, + handle::{LibPamHandle, PamHandle, PamModuleHandle}, module::PamModule, };
--- a/src/module.rs Thu May 22 02:08:10 2025 -0400 +++ b/src/module.rs Tue May 27 14:37:28 2025 -0400 @@ -1,7 +1,7 @@ //! Functions and types useful for implementing a PAM module. use crate::constants::{ErrorCode, Flags, Result}; -use crate::handle::PamHandle; +use crate::handle::PamModuleHandle; use std::ffi::CStr; /// A trait for a PAM module to implement. @@ -18,14 +18,14 @@ /// [manpage]: https://www.man7.org/linux/man-pages/man3/pam.3.html /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/Linux-PAM_MWG.html #[allow(unused_variables)] -pub trait PamModule { +pub trait PamModule<T: PamModuleHandle> { // Functions for auth modules. /// Authenticate the user. /// /// This is probably the first thing you want to implement. /// In most cases, you will want to get the user and password, - /// using [`PamHandle::get_user`] and [`PamHandle::get_authtok`], + /// using [`LibPamHandle::get_user`] and [`LibPamHandle::get_authtok`], /// and verify them against something. /// /// See [the Module Writer's Guide entry for `pam_sm_authenticate`][mwg] @@ -55,7 +55,7 @@ /// They should not try again. /// /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-auth.html#mwg-pam_sm_authenticate - fn authenticate(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { + fn authenticate(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> Result<()> { Err(ErrorCode::Ignore) } @@ -98,7 +98,7 @@ /// - [`ErrorCode::UserUnknown`]: The supplied username is not known by this service. /// /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-acct.html#mwg-pam_sm_acct_mgmt - fn account_management(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { + fn account_management(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> Result<()> { Err(ErrorCode::Ignore) } @@ -134,7 +134,7 @@ /// - [`ErrorCode::UserUnknown`]: The supplied username is not known by this service. /// /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-auth.html#mwg-pam_sm_setcred - fn set_credentials(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { + fn set_credentials(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> Result<()> { Err(ErrorCode::Ignore) } @@ -182,7 +182,7 @@ /// - [`ErrorCode::UserUnknown`]: The supplied username is not known by this service. /// /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-chauthtok.html#mwg-pam_sm_chauthtok - fn change_authtok(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { + fn change_authtok(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> Result<()> { Err(ErrorCode::Ignore) } @@ -206,7 +206,7 @@ /// - [`ErrorCode::SessionError`]: Cannot make an entry for this session. /// /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-session.html#mwg-pam_sm_open_session - fn open_session(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { + fn open_session(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> Result<()> { Err(ErrorCode::Ignore) } @@ -228,7 +228,7 @@ /// - [`ErrorCode::SessionError`]: Cannot remove an entry for this session. /// /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-session.html#mwg-pam_sm_close_session - fn close_session(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { + fn close_session(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> Result<()> { Err(ErrorCode::Ignore) } } @@ -244,21 +244,21 @@ /// Here is full example of a PAM module that would authenticate and authorize everybody: /// /// ```no_run -/// use nonstick::{Flags, PamHandle, PamModule, Result as PamResult, pam_hooks}; +/// use nonstick::{Flags, LibPamHandle, PamModule, PamModuleHandle, Result as PamResult, pam_hooks}; /// use std::ffi::CStr; /// # fn main() {} /// /// struct MyPamModule; /// pam_hooks!(MyPamModule); /// -/// impl PamModule for MyPamModule { -/// fn authenticate(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { +/// impl<T: PamModuleHandle> PamModule<T> for MyPamModule { +/// fn authenticate(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { /// let password = handle.get_authtok(Some("what's your password?"))?; /// eprintln!("If you say your password is {:?}, who am I to disagree!", password.unsecure()); /// Ok(()) /// } /// -/// fn account_management(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { +/// fn account_management(handle: &mut T, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { /// let username = handle.get_user(None)?; /// // You should use a Conversation to communicate with the user /// // instead of writing to the console, but this is just an example. @@ -272,7 +272,7 @@ ($ident:ident) => { mod _pam_hooks_scope { use std::ffi::{c_char, c_int, CStr}; - use $crate::{ErrorCode, Flags, PamModule}; + use $crate::{ErrorCode, Flags, LibPamHandle, PamModule}; #[no_mangle] extern "C" fn pam_sm_acct_mgmt( @@ -283,7 +283,7 @@ ) -> c_int { let args = extract_argv(argc, argv); ErrorCode::result_to_c(super::$ident::account_management( - &mut pamh.into(), + unsafe { LibPamHandle::from_ptr(pamh) }, args, flags, )) @@ -297,7 +297,11 @@ argv: *const *const c_char, ) -> c_int { let args = extract_argv(argc, argv); - ErrorCode::result_to_c(super::$ident::authenticate(&mut pamh.into(), args, flags)) + ErrorCode::result_to_c(super::$ident::authenticate( + unsafe { LibPamHandle::from_ptr(pamh) }, + args, + flags, + )) } #[no_mangle] @@ -308,7 +312,11 @@ argv: *const *const c_char, ) -> c_int { let args = extract_argv(argc, argv); - ErrorCode::result_to_c(super::$ident::change_authtok(&mut pamh.into(), args, flags)) + ErrorCode::result_to_c(super::$ident::change_authtok( + unsafe { LibPamHandle::from_ptr(pamh) }, + args, + flags, + )) } #[no_mangle] @@ -319,7 +327,11 @@ argv: *const *const c_char, ) -> c_int { let args = extract_argv(argc, argv); - ErrorCode::result_to_c(super::$ident::close_session(&mut pamh.into(), args, flags)) + ErrorCode::result_to_c(super::$ident::close_session( + unsafe { LibPamHandle::from_ptr(pamh) }, + args, + flags, + )) } #[no_mangle] @@ -330,7 +342,11 @@ argv: *const *const c_char, ) -> c_int { let args = extract_argv(argc, argv); - ErrorCode::result_to_c(super::$ident::open_session(&mut pamh.into(), args, flags)) + ErrorCode::result_to_c(super::$ident::open_session( + unsafe { LibPamHandle::from_ptr(pamh) }, + args, + flags, + )) } #[no_mangle] @@ -342,7 +358,7 @@ ) -> c_int { let args = extract_argv(argc, argv); ErrorCode::result_to_c(super::$ident::set_credentials( - &mut pamh.into(), + unsafe { LibPamHandle::from_ptr(pamh) }, args, flags, )) @@ -364,10 +380,10 @@ #[cfg(test)] pub mod test { - use crate::module::PamModule; + use crate::module::{PamModule, PamModuleHandle}; struct Foo; - impl PamModule for Foo {} + impl<T: PamModuleHandle> PamModule<T> for Foo {} pam_hooks!(Foo); }
--- a/src/pam_ffi.rs Thu May 22 02:08:10 2025 -0400 +++ b/src/pam_ffi.rs Tue May 27 14:37:28 2025 -0400 @@ -2,17 +2,25 @@ use libc::c_char; use std::ffi::c_int; +use std::marker::{PhantomData, PhantomPinned}; + +/// An opaque pointer given to us by PAM. +#[repr(C)] +pub struct Handle { + _data: (), + _marker: PhantomData<(*mut u8, PhantomPinned)>, +} #[link(name = "pam")] extern "C" { pub fn pam_get_data( - pamh: *const libc::c_void, + pamh: *const Handle, module_data_name: *const c_char, data: &mut *const libc::c_void, ) -> c_int; pub fn pam_set_data( - pamh: *mut libc::c_void, + pamh: *mut Handle, module_data_name: *const c_char, data: *const libc::c_void, cleanup: extern "C" fn( @@ -23,27 +31,25 @@ ) -> c_int; pub fn pam_get_item( - pamh: *const libc::c_void, + pamh: *const Handle, item_type: c_int, item: &mut *const libc::c_void, ) -> c_int; - pub fn pam_set_item( - pamh: *mut libc::c_void, - item_type: c_int, - item: *const libc::c_void, - ) -> c_int; + pub fn pam_set_item(pamh: *mut Handle, item_type: c_int, item: *const libc::c_void) -> c_int; pub fn pam_get_user( - pamh: *const libc::c_void, + pamh: *const Handle, user: &mut *const c_char, prompt: *const c_char, ) -> c_int; pub fn pam_get_authtok( - pamh: *const libc::c_void, + 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; }