Mercurial > crates > nonstick
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 | a674799a5cd3 |
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 |
