Mercurial > crates > nonstick
diff src/handle.rs @ 146:1bc52025156b
Split PAM items into their own separate struct.
To trim down the number of methods on `PamShared`, this puts all the
Items into their own struct(s). This also makes the split between
authtok/authtok_item easier to understand.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sun, 06 Jul 2025 19:10:26 -0400 |
parents | 56b559b7ecea |
children | 3036f2e6a022 |
line wrap: on
line diff
--- a/src/handle.rs Sun Jul 06 19:04:57 2025 -0400 +++ b/src/handle.rs Sun Jul 06 19:10:26 2025 -0400 @@ -1,59 +1,13 @@ //! The wrapper types and traits for handles into the PAM library. +use crate::_doc::{guide, linklist, man7, manbsd, stdlinks}; use crate::constants::{Flags, Result}; use crate::conv::Conversation; use crate::environ::{EnvironMap, EnvironMapMut}; +use crate::items::{getter, Items, ItemsMut}; use crate::logging::{Level, Location}; -use crate::{guide, linklist, man7, manbsd, stdlinks}; use std::ffi::{OsStr, OsString}; -macro_rules! trait_item { - ($(#[$md:meta])* get = $getter:ident, item = $item:literal $(, see = $see:path)?) => { - $(#[$md])* - #[doc = ""] - #[doc = concat!("Gets the `", $item, "` of the PAM handle.")] - $( - #[doc = concat!("See [`", stringify!($see), "`].")] - )? - /// - /// Returns a reference to the item's value, owned by PAM. - /// The item is assumed to be valid UTF-8 text. - /// If it is not, `ConversationError` is returned. - /// - /// # References - /// - #[doc = linklist!(pam_get_item: mwg, adg, _std)] - /// - #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_get_item")] - #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_get_item")] - #[doc = stdlinks!(3 pam_get_item)] - fn $getter(&self) -> Result<Option<OsString>>; - }; - ($(#[$md:meta])* set = $setter:ident, item = $item:literal $(, see = $see:path)?) => { - $(#[$md])* - #[doc = ""] - #[doc = concat!("Sets the `", $item, "` from the PAM handle.")] - $( - #[doc = concat!("See [`", stringify!($see), "`].")] - )? - /// - /// Sets the item's value. PAM copies the string's contents. - /// - /// # Panics - /// - /// If the string contains a nul byte, this will panic. - /// - /// # References - /// - #[doc = linklist!(pam_set_item: mwg, adg, _std)] - /// - #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_set_item")] - #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_set_item")] - #[doc = stdlinks!(3 pam_set_item)] - fn $setter(&mut self, value: Option<&OsStr>) -> Result<()>; - }; -} - /// Functionality for both PAM applications and PAM modules. /// /// This base trait includes features of a PAM handle that are available @@ -127,138 +81,53 @@ #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_get_user")] fn username(&mut self, prompt: Option<&OsStr>) -> Result<OsString>; - /// The contents of the environment to set, read-only. + /// The contents of the environment to set for the logged-in user. + /// + /// # References + /// + #[doc = linklist!(pam_getenv: adg, mwg, _std)] + /// + #[doc = stdlinks!(3 pam_getenv)] + #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_getenv")] + #[doc = guide!(mwg: "mwg-expected-by-module-item.html#adg-pam_getenv")] fn environ(&self) -> impl EnvironMap; - /// A writable version of the environment. + /// A writable map of the environment to set for the logged-in user. + /// + /// # References + /// + #[doc = linklist!(pam_putenv: adg, mwg, _std)] + /// + #[doc = stdlinks!(3 pam_putenv)] + #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_putenv")] + #[doc = guide!(mwg: "mwg-expected-by-module-item.html#adg-pam_putenv")] fn environ_mut(&mut self) -> impl EnvironMapMut; - trait_item!( - /// The identity of the user for whom service is being requested. - /// - /// Unlike [`username`](Self::username), this will simply get - /// the current state of the user item, and not request the username. - /// While PAM usually sets this automatically in the `username` call, - /// it may be changed by a module during the PAM transaction. - /// Applications should check it after each step of the PAM process. - get = user_item, - item = "PAM_USER", - see = Self::username - ); - trait_item!( - /// Sets the identity of the logging-in user. - /// - /// Usually this will be set during the course of - /// a [`username`](Self::username) call, but you may set it manually - /// or change it during the PAM process. - set = set_user_item, - item = "PAM_USER", - see = Self::user_item - ); - - trait_item!( - /// The service name, which identifies the PAM stack which is used - /// to perform authentication. - get = service, - item = "PAM_SERVICE" - ); - trait_item!( - /// Sets the service name. It's probably a bad idea to change this. - set = set_service, - item = "PAM_SERVICE", - see = Self::service - ); - - trait_item!( - /// The string used to prompt for a user's name. - /// By default, this is a localized version of `login: `. - get = user_prompt, - item = "PAM_USER_PROMPT" - ); - trait_item!( - /// Sets the string used to prompt for a user's name. - set = set_user_prompt, - item = "PAM_USER_PROMPT", - see = Self::user_prompt - ); + /// Gets Items, data shared by PAM, the application, and modules. + /// + /// Certain Items should not be accessed by a PAM application; + /// those are available directly on [`ModuleClient`] for use + /// by PAM modules only. + /// + /// # References + /// + #[doc = linklist!(pam_get_item: mwg, adg, _std)] + /// + #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_get_item")] + #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_get_item")] + #[doc = stdlinks!(3 pam_get_item)] + fn items(&self) -> impl Items; - trait_item!( - /// The device path of the TTY being used to log in. - /// - /// This is the terminal the user is logging in on, - /// specified as the full device path (e.g. `/dev/tty0`). - /// Very old applications may use this instead of `PAM_XDISPLAY`. - get = tty_name, - item = "PAM_TTY" - ); - trait_item!( - /// Sets the path to the terminal where the user is logging on. - set = set_tty_name, - item = "PAM_TTY", - see = Self::tty_name - ); - - trait_item!( - /// If set, the identity of the remote user logging in. - /// - /// This is only as trustworthy as the application calling PAM. - get = remote_user, - item = "PAM_RUSER", - see = Self::remote_host - ); - trait_item!( - /// Sets the identity of the remote user logging in. - /// - /// This may be set by the application before making calls - /// into a PAM transaction. - set = set_remote_user, - item = "PAM_RUSER", - see = Self::remote_user - ); - - trait_item!( - /// If set, the remote location where the user is coming from. - /// - /// This is only as trustworthy as the application calling PAM. - /// This can be combined with [`Self::remote_user`] to identify - /// the account the user is attempting to log in from, - /// with `remote_user@remote_host`. - /// - /// If unset, "it is unclear where the authentication request - /// is originating from." - get = remote_host, - item = "PAM_RHOST", - see = Self::remote_user - ); - trait_item!( - /// Sets the location where the user is coming from. - /// - /// This may be set by the application before making calls - /// into a PAM transaction. - set = set_remote_host, - item = "PAM_RHOST", - see = Self::remote_host - ); - - trait_item!( - /// Gets the user's authentication token (e.g., password). - /// - /// This is usually set automatically when - /// [`authtok`](PamHandleModule::authtok) is called, - /// but can be manually set. - set = set_authtok_item, - item = "PAM_AUTHTOK", - see = PamHandleModule::authtok_item - ); - - trait_item!( - /// Sets the user's "old authentication token" when changing passwords. - /// - /// This is usually set automatically by PAM. - set = set_old_authtok_item, - item = "PAM_OLDAUTHTOK", - see = PamHandleModule::old_authtok_item - ); + /// Read-write access to PAM Items. + /// + /// # References + /// + #[doc = linklist!(pam_set_item: mwg, adg, _std)] + /// + #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_set_item")] + #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_set_item")] + #[doc = stdlinks!(3 pam_set_item)] + fn items_mut(&mut self) -> impl ItemsMut; } /// Functionality of a PAM handle that can be expected by a PAM application. @@ -316,7 +185,7 @@ /// /// Like [`PamShared`], this is intended to allow creating mock implementations /// of PAM for testing PAM modules. -pub trait PamHandleModule: Conversation + PamShared { +pub trait ModuleClient: Conversation + PamShared { /// Retrieves the authentication token from the user. /// /// This should only be used by *authentication* and *password-change* @@ -329,8 +198,8 @@ /// # Example /// /// ```no_run - /// # use nonstick::handle::PamHandleModule; - /// # fn _doc(handle: &mut impl PamHandleModule) -> Result<(), Box<dyn std::error::Error>> { + /// # use nonstick::handle::ModuleClient; + /// # fn _doc(handle: &mut impl ModuleClient) -> Result<(), Box<dyn std::error::Error>> { /// // Get the user's password using the default prompt. /// let pass = handle.authtok(None)?; /// // Get the user's password using a custom prompt. @@ -344,31 +213,63 @@ /// Retrieves the user's old authentication token when changing passwords. /// + /// This should only be used by a *password-change* module. /// + /// # References + /// + #[doc = linklist!(pam_get_authtok: man7, manbsd)] + /// + /// # Example + /// + /// ```no_run + /// # use nonstick::handle::ModuleClient; + /// # fn _doc(handle: &mut impl ModuleClient) -> Result<(), Box<dyn std::error::Error>> { + /// // Get the user's password using the default prompt. + /// let pass = handle.old_authtok(None)?; + /// // Get the user's password using a custom prompt. + /// let pass = handle.old_authtok(Some("Reveal your secrets!".as_ref()))?; + /// Ok(()) + /// # } + /// ``` + /// + #[doc = stdlinks!(3 pam_get_authtok)] fn old_authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString>; - trait_item!( + getter!( /// Gets the user's authentication token (e.g., password). /// - /// This is normally set automatically by PAM when calling - /// [`authtok`](Self::authtok), but can be set explicitly. + /// This is normally set automatically by PAM through [`Self::authtok`], + /// but this will get its value (if set) without prompting the user. /// /// Like `authtok`, this should only ever be called /// by *authentication* and *password-change* PAM modules. - get = authtok_item, - item = "PAM_AUTHTOK", - see = Self::authtok + /// + /// # References + /// + #[doc = linklist!(pam_set_item: mwg, adg, _std)] + /// + #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_set_item")] + #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_set_item")] + #[doc = stdlinks!(3 pam_set_item)] + authtok_item("PAM_AUTHTOK", see = Self::authtok) ); - trait_item!( + getter!( /// Gets the user's old authentication token when changing passwords. /// - /// This is normally set automatically by PAM when calling - /// [`old_authtok`](Self::old_authtok), but can be set explicitly. + /// This is normally set automatically by PAM through + /// [`Self::old_authtok`], but this will get its value (if set) + /// without prompting the user. /// /// This should only ever be called by *password-change* PAM modules. - get = old_authtok_item, - item = "PAM_OLDAUTHTOK", - see = PamShared::set_old_authtok_item + /// + /// # References + /// + #[doc = linklist!(pam_set_item: mwg, adg, _std)] + /// + #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_set_item")] + #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_set_item")] + #[doc = stdlinks!(3 pam_set_item)] + old_authtok_item("PAM_OLDAUTHTOK", see = ItemsMut::set_old_authtok) ); }