comparison src/module.rs @ 64:bbe84835d6db v0.0.5

More organization; add lots of docs. - moves `PamHandle` to its own module, since it will be used by both modules and clients. - adds a ton of documentation to the `PamModule` trait and reorders methods to most-interesting-first. - adds more flag values from pam_modules.h. - other misc cleanup.
author Paul Fisher <paul@pfish.zone>
date Thu, 22 May 2025 01:52:32 -0400
parents 05cc2c27334f
children
comparison
equal deleted inserted replaced
63:a7aa5ca0d00d 64:bbe84835d6db
1 //! Functions and types useful for implementing a PAM module. 1 //! Functions and types useful for implementing a PAM module.
2 2
3 use crate::constants::{ErrorCode, Flags, Result}; 3 use crate::constants::{ErrorCode, Flags, Result};
4 use crate::items::{Item, ItemType}; 4 use crate::handle::PamHandle;
5 use crate::memory; 5 use std::ffi::CStr;
6 use libc::c_char; 6
7 use secure_string::SecureString; 7 /// A trait for a PAM module to implement.
8 use std::ffi::{c_int, CStr, CString}; 8 ///
9 9 /// The default implementations of all these hooks tell PAM to ignore them
10 use crate::pam_ffi; 10 /// (i.e., behave as if this module does not exist) by returning [`ErrorCode::Ignore`].
11 11 /// Override any functions you wish to handle in your module.
12 /// Function called at the end of a PAM session that is called to clean up 12 /// After implementing this trait, use the [`pam_hooks!`](crate::pam_hooks!) macro
13 /// a value previously provided to PAM in a `pam_set_data` call. 13 /// to make the functions available to PAM.
14 ///
15 /// You should never call this yourself.
16 extern "C" fn cleanup<T>(_: *const libc::c_void, c_data: *mut libc::c_void, _: c_int) {
17 unsafe {
18 let _data: Box<T> = Box::from_raw(c_data.cast());
19 }
20 }
21
22 /// An opaque structure pointing to a PAM handle.
23 #[repr(transparent)]
24 pub struct PamHandle(*mut libc::c_void);
25
26 impl PamHandle {
27 /// Gets some value, identified by `key`, that has been set by the module
28 /// previously.
29 ///
30 /// See the [`pam_get_data` manual page](
31 /// https://www.man7.org/linux/man-pages/man3/pam_get_data.3.html).
32 ///
33 /// # Safety
34 ///
35 /// The data stored under the provided key must be of type `T` otherwise the
36 /// behaviour of this function is undefined.
37 ///
38 /// The data, if present, is owned by the current PAM conversation.
39 pub unsafe fn get_data<T>(&self, key: &str) -> Result<Option<&T>> {
40 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?;
41 let mut ptr: *const libc::c_void = std::ptr::null();
42 ErrorCode::result_from(pam_ffi::pam_get_data(self.0, c_key.as_ptr(), &mut ptr))?;
43 match ptr.is_null() {
44 true => Ok(None),
45 false => {
46 let typed_ptr = ptr.cast();
47 Ok(Some(&*typed_ptr))
48 }
49 }
50 }
51
52 /// Stores a value that can be retrieved later with `get_data`.
53 /// The conversation takes ownership of the data.
54 ///
55 /// See the [`pam_set_data` manual page](
56 /// https://www.man7.org/linux/man-pages/man3/pam_set_data.3.html).
57 pub fn set_data<T>(&mut self, key: &str, data: Box<T>) -> Result<()> {
58 let c_key = CString::new(key).map_err(|_| ErrorCode::ConversationError)?;
59 let ret = unsafe {
60 pam_ffi::pam_set_data(
61 self.0,
62 c_key.as_ptr(),
63 Box::into_raw(data).cast(),
64 cleanup::<T>,
65 )
66 };
67 ErrorCode::result_from(ret)
68 }
69
70 /// Retrieves a value that has been set, possibly by the pam client.
71 /// This is particularly useful for getting a `PamConv` reference.
72 ///
73 /// These items are *references to PAM memory*
74 /// which are *owned by the conversation*.
75 ///
76 /// See the [`pam_get_item` manual page](
77 /// https://www.man7.org/linux/man-pages/man3/pam_get_item.3.html).
78 pub fn get_item<T: crate::items::Item>(&self) -> Result<Option<T>> {
79 let mut ptr: *const libc::c_void = std::ptr::null();
80 let out = unsafe {
81 let ret = pam_ffi::pam_get_item(self.0, T::type_id().into(), &mut ptr);
82 ErrorCode::result_from(ret)?;
83 let typed_ptr: *const T::Raw = ptr.cast();
84 match typed_ptr.is_null() {
85 true => None,
86 false => Some(T::from_raw(typed_ptr)),
87 }
88 };
89 Ok(out)
90 }
91
92 /// Sets an item in the pam context. It can be retrieved using `get_item`.
93 ///
94 /// See the [`pam_set_item` manual page](
95 /// https://www.man7.org/linux/man-pages/man3/pam_set_item.3.html).
96 pub fn set_item<T: Item>(&mut self, item: T) -> Result<()> {
97 let ret =
98 unsafe { pam_ffi::pam_set_item(self.0, T::type_id().into(), item.into_raw().cast()) };
99 ErrorCode::result_from(ret)
100 }
101
102 /// Retrieves the name of the user who is authenticating or logging in.
103 ///
104 /// This is really a specialization of `get_item`.
105 ///
106 /// See the [`pam_get_user` manual page](
107 /// https://www.man7.org/linux/man-pages/man3/pam_get_user.3.html).
108 pub fn get_user(&self, prompt: Option<&str>) -> Result<String> {
109 let prompt = memory::option_cstr(prompt)?;
110 let mut output: *const c_char = std::ptr::null_mut();
111 let ret = unsafe {
112 pam_ffi::pam_get_user(self.0, &mut output, memory::prompt_ptr(prompt.as_ref()))
113 };
114 ErrorCode::result_from(ret)?;
115 memory::copy_pam_string(output)
116 }
117
118 /// Retrieves the authentication token from the user.
119 ///
120 /// This is really a specialization of `get_item`.
121 ///
122 /// See the [`pam_get_authtok` manual page](
123 /// https://www.man7.org/linux/man-pages/man3/pam_get_authtok.3.html).
124 pub fn get_authtok(&self, prompt: Option<&str>) -> Result<SecureString> {
125 let prompt = memory::option_cstr(prompt)?;
126 let mut output: *const c_char = std::ptr::null_mut();
127 let res = unsafe {
128 pam_ffi::pam_get_authtok(
129 self.0,
130 ItemType::AuthTok.into(),
131 &mut output,
132 memory::prompt_ptr(prompt.as_ref()),
133 )
134 };
135 ErrorCode::result_from(res)?;
136 memory::copy_pam_string(output).map(SecureString::from)
137 }
138 }
139
140 impl From<*mut libc::c_void> for PamHandle {
141 /// Wraps an internal Handle pointer.
142 fn from(value: *mut libc::c_void) -> Self {
143 Self(value)
144 }
145 }
146
147 /// Trait representing what a PAM module can do.
148 ///
149 /// By default, all the functions in this trait are ignored.
150 /// Implement any functions you wish to handle in your module.
151 /// After implementing this trait, use the [crate::pam_hooks!] macro
152 /// to export your functions.
153 /// 14 ///
154 /// For more information, see [`pam(3)`’s root manual page][manpage] 15 /// For more information, see [`pam(3)`’s root manual page][manpage]
155 /// and the [PAM Module Writer’s Guide][module-guide]. 16 /// and the [PAM Module Writer’s Guide][mwg].
156 /// 17 ///
157 /// [manpage]: https://www.man7.org/linux/man-pages/man3/pam.3.html 18 /// [manpage]: https://www.man7.org/linux/man-pages/man3/pam.3.html
158 /// [module-guide]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/Linux-PAM_MWG.html 19 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/Linux-PAM_MWG.html
159 #[allow(unused_variables)] 20 #[allow(unused_variables)]
160 pub trait PamModule { 21 pub trait PamModule {
161 /// This function performs the task of establishing whether the user is permitted to gain access at 22 // Functions for auth modules.
162 /// this time. It should be understood that the user has previously been validated by an 23
163 /// authentication module. This function checks for other things. Such things might be: the time of 24 /// Authenticate the user.
164 /// day or the date, the terminal line, remote hostname, etc. This function may also determine 25 ///
165 /// things like the expiration on passwords, and respond that the user change it before continuing. 26 /// This is probably the first thing you want to implement.
166 fn acct_mgmt(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { 27 /// In most cases, you will want to get the user and password,
167 Err(ErrorCode::Ignore) 28 /// using [`PamHandle::get_user`] and [`PamHandle::get_authtok`],
168 } 29 /// and verify them against something.
169 30 ///
170 /// This function performs the task of authenticating the user. 31 /// See [the Module Writer's Guide entry for `pam_sm_authenticate`][mwg]
171 fn sm_authenticate(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { 32 /// for more information.
172 Err(ErrorCode::Ignore) 33 ///
173 } 34 /// # Valid flags
174 35 ///
175 /// This function is used to (re-)set the authentication token of the user. 36 /// This function may be called with the following flags set:
176 /// 37 ///
177 /// The PAM library calls this function twice in succession. The first time with 38 /// - [`Flags::SILENT`]
178 /// `PAM_PRELIM_CHECK` and then, if the module does not return `PAM_TRY_AGAIN`, subsequently with 39 /// - [`Flags::DISALLOW_NULL_AUTHTOK`]
179 /// `PAM_UPDATE_AUTHTOK`. It is only on the second call that the authorization token is 40 ///
180 /// (possibly) changed. 41 /// # Returns
181 fn sm_chauthtok(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { 42 ///
182 Err(ErrorCode::Ignore) 43 /// If the password check was successful, return `Ok(())`.
183 } 44 ///
184 45 /// Sensible error codes to return include:
185 /// This function is called to terminate a session. 46 ///
186 fn sm_close_session(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { 47 /// - [`ErrorCode::AuthenticationError`]: Generic authentication error
187 Err(ErrorCode::Ignore) 48 /// (like an incorrect password).
188 } 49 /// - [`ErrorCode::CredentialsInsufficient`]: The application does not have
189 50 /// sufficient credentials to authenticate the user.
190 /// This function is called to commence a session. 51 /// - [`ErrorCode::AuthInfoUnavailable`]: The module was not able to access
191 fn sm_open_session(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { 52 /// the authentication information, for instance due to a network failure.
192 Err(ErrorCode::Ignore) 53 /// - [`ErrorCode::UserUnknown`]: The supplied username is not known by this service.
193 } 54 /// - [`ErrorCode::MaxTries`]: The user has tried authenticating too many times.
194 55 /// They should not try again.
195 /// This function performs the task of altering the credentials of the user with respect to the 56 ///
196 /// corresponding authorization scheme. Generally, an authentication module may have access to more 57 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-auth.html#mwg-pam_sm_authenticate
197 /// information about a user than their authentication token. This function is used to make such 58 fn authenticate(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> {
198 /// information available to the application. It should only be called after the user has been 59 Err(ErrorCode::Ignore)
199 /// authenticated but before a session has been established. 60 }
200 fn sm_setcred(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> { 61
62 /// Perform "account management".
63 ///
64 /// When PAM calls this function, the user has already been authenticated
65 /// by an authentication module (either this one or some other module).
66 /// This hook can check for other things, for instance:
67 ///
68 /// - Date/time (keep your kids off the computer at night)
69 /// - Remote host (only let employees log in from the office)
70 ///
71 /// You can also check things like, e.g., password expiration,
72 /// and alert that the user change it before continuing,
73 /// or really do whatever you want.
74 ///
75 /// See [the Module Writer's Guide entry for `pam_sm_acct_mgmt`][mwg]
76 /// for more information.
77 ///
78 ///
79 /// # Valid flags
80 ///
81 /// This function may be called with the following flags set:
82 ///
83 /// - [`Flags::SILENT`]
84 /// - [`Flags::DISALLOW_NULL_AUTHTOK`]
85 ///
86 /// # Returns
87 ///
88 /// If the user should be allowed to log in, return `Ok(())`.
89 ///
90 /// Sensible error codes to return include:
91 ///
92 /// - [`ErrorCode::AccountExpired`]: The user's account has expired.
93 /// - [`ErrorCode::AuthenticationError`]: Generic authentication error.
94 /// - [`ErrorCode::NewAuthTokRequired`]: The user's authentication token has expired.
95 /// PAM will ask the user to set a new authentication token, which may be handled by
96 /// this module in [`Self::change_authtok`].
97 /// - [`ErrorCode::PermissionDenied`]: This one is pretty self-explanatory.
98 /// - [`ErrorCode::UserUnknown`]: The supplied username is not known by this service.
99 ///
100 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-acct.html#mwg-pam_sm_acct_mgmt
101 fn account_management(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> {
102 Err(ErrorCode::Ignore)
103 }
104
105 /// Set credentials on this session.
106 ///
107 /// If an authentication module knows more about the user than just
108 /// their authentication token, then it uses this function to provide
109 /// that information to the application. It should only be called after
110 /// authentication but before a session is established.
111 ///
112 /// See [the Module Writer's Guide entry for `pam_sm_setcred`][mwg]
113 /// for more information.
114 ///
115 /// # Valid flags
116 ///
117 /// This function may be called with the following flags set:
118 ///
119 /// - [`Flags::SILENT`]
120 /// - [`Flags::ESTABLISH_CREDENTIALS`]: Initialize credentials for the user.
121 /// - [`Flags::DELETE_CREDENTIALS`]: Delete the credentials associated with this module.
122 /// - [`Flags::REINITIALIZE_CREDENTIALS`]: Re-initialize credentials for this user.
123 /// - [`Flags::REFRESH_CREDENTIALS`]: Extend the lifetime of the user's credentials.
124 ///
125 /// # Returns
126 ///
127 /// If credentials were set successfully, return `Ok(())`.
128 ///
129 /// Sensible error codes to return include:
130 ///
131 /// - [`ErrorCode::CredentialsUnavailable`]: The credentials cannot be retrieved.
132 /// - [`ErrorCode::CredentialsExpired`]: The credentials have expired.
133 /// - [`ErrorCode::CredentialsError`]: Some other error occurred when setting credentials.
134 /// - [`ErrorCode::UserUnknown`]: The supplied username is not known by this service.
135 ///
136 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-auth.html#mwg-pam_sm_setcred
137 fn set_credentials(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> {
138 Err(ErrorCode::Ignore)
139 }
140
141 // Function for chauthtok modules.
142
143 /// Called to set or reset the user's authentication token.
144 ///
145 /// PAM calls this function twice in succession.
146 /// 1. The first time, [`Flags::PRELIMINARY_CHECK`] will be set.
147 /// If the new token is acceptable, return success;
148 /// if not, return [`ErrorCode::TryAgain`] to re-prompt the user.
149 /// 2. After the preliminary check succeeds, [`Flags::UPDATE_AUTHTOK`]
150 /// will be set. On this call, actually update the stored auth token.
151 ///
152 /// See [the Module Writer's Guide entry for `pam_sm_chauthtok`][mwg]
153 /// for more information.
154 ///
155 /// # Valid flags
156 ///
157 /// This function may be called with the following flags set:
158 ///
159 /// - [`Flags::SILENT`]
160 /// - [`Flags::CHANGE_EXPIRED_AUTHTOK`]: This module should only change
161 /// any expired passwords, and leave non-expired passwords alone.
162 /// If present, it _must_ be combined with one of the following.
163 /// - [`Flags::PRELIMINARY_CHECK`]: Don't actually change the password,
164 /// just check if the new one is valid.
165 /// - [`Flags::UPDATE_AUTHTOK`]: Do actually change the password.
166 ///
167 /// # Returns
168 ///
169 /// If the authentication token was changed successfully
170 /// (or the check passed), return `Ok(())`.
171 ///
172 /// Sensible error codes to return include:
173 ///
174 /// - [`ErrorCode::AuthTokError`]: The service could not get the authentication token.
175 /// - [`ErrorCode::AuthTokRecoveryError`]: The service could not get the old token.
176 /// - [`ErrorCode::AuthTokLockBusy`]: The password cannot be changed because
177 /// the authentication token is currently locked.
178 /// - [`ErrorCode::AuthTokDisableAging`]: Aging (expiration) is disabled.
179 /// - [`ErrorCode::PermissionDenied`]: What it says on the tin.
180 /// - [`ErrorCode::TryAgain`]: When the preliminary check is unsuccessful,
181 /// ask the user for a new authentication token.
182 /// - [`ErrorCode::UserUnknown`]: The supplied username is not known by this service.
183 ///
184 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-chauthtok.html#mwg-pam_sm_chauthtok
185 fn change_authtok(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> {
186 Err(ErrorCode::Ignore)
187 }
188
189 // Functions for session modules.
190
191 /// Called when a session is opened.
192 ///
193 /// See [the Module Writer's Guide entry for `pam_sm_open_session`][mwg]
194 /// for more information.
195 ///
196 /// # Valid flags
197 ///
198 /// The only valid flag is [`Flags::SILENT`].
199 ///
200 /// # Returns
201 ///
202 /// If the session was opened successfully, return `Ok(())`.
203 ///
204 /// A sensible error code to return is:
205 ///
206 /// - [`ErrorCode::SessionError`]: Cannot make an entry for this session.
207 ///
208 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-session.html#mwg-pam_sm_open_session
209 fn open_session(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> {
210 Err(ErrorCode::Ignore)
211 }
212
213 /// Called when a session is being terminated.
214 ///
215 /// See [the Module Writer's Guide entry for `pam_sm_close_session`][mwg]
216 /// for more information.
217 ///
218 /// # Valid flags
219 ///
220 /// The only valid flag is [`Flags::SILENT`].
221 ///
222 /// # Returns
223 ///
224 /// If the session was closed successfully, return `Ok(())`.
225 ///
226 /// A sensible error code to return is:
227 ///
228 /// - [`ErrorCode::SessionError`]: Cannot remove an entry for this session.
229 ///
230 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-of-module-session.html#mwg-pam_sm_close_session
231 fn close_session(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> Result<()> {
201 Err(ErrorCode::Ignore) 232 Err(ErrorCode::Ignore)
202 } 233 }
203 } 234 }
204 235
205 /// Generates the dynamic library entry points for a [PamModule] implementation. 236 /// Generates the dynamic library entry points for a [PamModule] implementation.
210 /// 241 ///
211 /// ## Examples: 242 /// ## Examples:
212 /// 243 ///
213 /// Here is full example of a PAM module that would authenticate and authorize everybody: 244 /// Here is full example of a PAM module that would authenticate and authorize everybody:
214 /// 245 ///
215 /// ``` 246 /// ```no_run
216 /// use nonstick::{Flags, PamHandle, PamModule, Result as PamResult, pam_hooks}; 247 /// use nonstick::{Flags, PamHandle, PamModule, Result as PamResult, pam_hooks};
217 /// use std::ffi::CStr; 248 /// use std::ffi::CStr;
218 ///
219 /// # fn main() {} 249 /// # fn main() {}
250 ///
220 /// struct MyPamModule; 251 /// struct MyPamModule;
221 /// pam_hooks!(MyPamModule); 252 /// pam_hooks!(MyPamModule);
222 /// 253 ///
223 /// impl PamModule for MyPamModule { 254 /// impl PamModule for MyPamModule {
224 /// fn acct_mgmt(pamh: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> { 255 /// fn authenticate(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> {
256 /// let password = handle.get_authtok(Some("what's your password?"))?;
257 /// eprintln!("If you say your password is {:?}, who am I to disagree!", password.unsecure());
258 /// Ok(())
259 /// }
260 ///
261 /// fn account_management(handle: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> {
262 /// let username = handle.get_user(None)?;
225 /// // You should use a Conversation to communicate with the user 263 /// // You should use a Conversation to communicate with the user
226 /// // instead of writing to the console, but this is just an example. 264 /// // instead of writing to the console, but this is just an example.
227 /// eprintln!("Everybody is authorized!"); 265 /// eprintln!("Hello {username}! I trust you unconditionally!");
228 /// Ok(())
229 /// }
230 ///
231 /// fn sm_authenticate(pamh: &mut PamHandle, args: Vec<&CStr>, flags: Flags) -> PamResult<()> {
232 /// eprintln!("Everybody is authenticated!");
233 /// Ok(()) 266 /// Ok(())
234 /// } 267 /// }
235 /// } 268 /// }
236 /// ``` 269 /// ```
237 #[macro_export] 270 #[macro_export]
247 flags: Flags, 280 flags: Flags,
248 argc: c_int, 281 argc: c_int,
249 argv: *const *const c_char, 282 argv: *const *const c_char,
250 ) -> c_int { 283 ) -> c_int {
251 let args = extract_argv(argc, argv); 284 let args = extract_argv(argc, argv);
252 ErrorCode::result_to_c(super::$ident::acct_mgmt(&mut pamh.into(), args, flags)) 285 ErrorCode::result_to_c(super::$ident::account_management(
253 }
254
255 #[no_mangle]
256 extern "C" fn pam_sm_authenticate(
257 pamh: *mut libc::c_void,
258 flags: Flags,
259 argc: c_int,
260 argv: *const *const c_char,
261 ) -> c_int {
262 let args = extract_argv(argc, argv);
263 ErrorCode::result_to_c(super::$ident::sm_authenticate(
264 &mut pamh.into(), 286 &mut pamh.into(),
265 args, 287 args,
266 flags, 288 flags,
267 )) 289 ))
268 } 290 }
269 291
270 #[no_mangle] 292 #[no_mangle]
293 extern "C" fn pam_sm_authenticate(
294 pamh: *mut libc::c_void,
295 flags: Flags,
296 argc: c_int,
297 argv: *const *const c_char,
298 ) -> c_int {
299 let args = extract_argv(argc, argv);
300 ErrorCode::result_to_c(super::$ident::authenticate(&mut pamh.into(), args, flags))
301 }
302
303 #[no_mangle]
271 extern "C" fn pam_sm_chauthtok( 304 extern "C" fn pam_sm_chauthtok(
272 pamh: *mut libc::c_void, 305 pamh: *mut libc::c_void,
273 flags: Flags, 306 flags: Flags,
274 argc: c_int, 307 argc: c_int,
275 argv: *const *const c_char, 308 argv: *const *const c_char,
276 ) -> c_int { 309 ) -> c_int {
277 let args = extract_argv(argc, argv); 310 let args = extract_argv(argc, argv);
278 ErrorCode::result_to_c(super::$ident::sm_chauthtok(&mut pamh.into(), args, flags)) 311 ErrorCode::result_to_c(super::$ident::change_authtok(&mut pamh.into(), args, flags))
279 } 312 }
280 313
281 #[no_mangle] 314 #[no_mangle]
282 extern "C" fn pam_sm_close_session( 315 extern "C" fn pam_sm_close_session(
283 pamh: *mut libc::c_void, 316 pamh: *mut libc::c_void,
284 flags: Flags, 317 flags: Flags,
285 argc: c_int, 318 argc: c_int,
286 argv: *const *const c_char, 319 argv: *const *const c_char,
287 ) -> c_int { 320 ) -> c_int {
288 let args = extract_argv(argc, argv); 321 let args = extract_argv(argc, argv);
289 ErrorCode::result_to_c(super::$ident::sm_close_session( 322 ErrorCode::result_to_c(super::$ident::close_session(&mut pamh.into(), args, flags))
323 }
324
325 #[no_mangle]
326 extern "C" fn pam_sm_open_session(
327 pamh: *mut libc::c_void,
328 flags: Flags,
329 argc: c_int,
330 argv: *const *const c_char,
331 ) -> c_int {
332 let args = extract_argv(argc, argv);
333 ErrorCode::result_to_c(super::$ident::open_session(&mut pamh.into(), args, flags))
334 }
335
336 #[no_mangle]
337 extern "C" fn pam_sm_setcred(
338 pamh: *mut libc::c_void,
339 flags: Flags,
340 argc: c_int,
341 argv: *const *const c_char,
342 ) -> c_int {
343 let args = extract_argv(argc, argv);
344 ErrorCode::result_to_c(super::$ident::set_credentials(
290 &mut pamh.into(), 345 &mut pamh.into(),
291 args, 346 args,
292 flags, 347 flags,
293 )) 348 ))
294 }
295
296 #[no_mangle]
297 extern "C" fn pam_sm_open_session(
298 pamh: *mut libc::c_void,
299 flags: Flags,
300 argc: c_int,
301 argv: *const *const c_char,
302 ) -> c_int {
303 let args = extract_argv(argc, argv);
304 ErrorCode::result_to_c(super::$ident::sm_open_session(
305 &mut pamh.into(),
306 args,
307 flags,
308 ))
309 }
310
311 #[no_mangle]
312 extern "C" fn pam_sm_setcred(
313 pamh: *mut libc::c_void,
314 flags: Flags,
315 argc: c_int,
316 argv: *const *const c_char,
317 ) -> c_int {
318 let args = extract_argv(argc, argv);
319 ErrorCode::result_to_c(super::$ident::sm_setcred(&mut pamh.into(), args, flags))
320 } 349 }
321 350
322 /// Turns `argc`/`argv` into a [Vec] of [CStr]s. 351 /// Turns `argc`/`argv` into a [Vec] of [CStr]s.
323 /// 352 ///
324 /// # Safety 353 /// # Safety