comparison src/handle.rs @ 103:dfcd96a74ac4 default tip

write a truly prodigious amount of documentation adds a bunch of links to the OpenPAM man pages and the XSSO spec as well as just a bunch of prose and stuff.
author Paul Fisher <paul@pfish.zone>
date Wed, 25 Jun 2025 00:59:24 -0400
parents 3f11b8d30f63
children
comparison
equal deleted inserted replaced
102:94eb11cb1798 103:dfcd96a74ac4
2 2
3 use crate::constants::{Flags, Result}; 3 use crate::constants::{Flags, Result};
4 use crate::conv::Conversation; 4 use crate::conv::Conversation;
5 use crate::environ::{EnvironMap, EnvironMapMut}; 5 use crate::environ::{EnvironMap, EnvironMapMut};
6 use crate::logging::Level; 6 use crate::logging::Level;
7 use crate::{_guide, _linklist, _man7, _manbsd, _stdlinks};
7 8
8 macro_rules! trait_item { 9 macro_rules! trait_item {
9 ($(#[$md:meta])* get = $getter:ident, item = $item:literal $(, see = $see:path)?) => { 10 ($(#[$md:meta])* get = $getter:ident, item = $item:literal $(, see = $see:path)?) => {
10 $(#[$md])* 11 $(#[$md])*
11 #[doc = ""] 12 #[doc = ""]
16 /// 17 ///
17 /// Returns a reference to the item's value, owned by PAM. 18 /// Returns a reference to the item's value, owned by PAM.
18 /// The item is assumed to be valid UTF-8 text. 19 /// The item is assumed to be valid UTF-8 text.
19 /// If it is not, `ConversationError` is returned. 20 /// If it is not, `ConversationError` is returned.
20 /// 21 ///
21 /// See the [`pam_get_item`][man] manual page, 22 /// # References
22 /// [`pam_get_item` in the Module Writers' Guide][mwg], or 23 ///
23 /// [`pam_get_item` in the Application Developers' Guide][adg]. 24 #[doc = _linklist!(pam_get_item: mwg, adg, _std)]
24 /// 25 ///
25 /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_item.3.html 26 #[doc = _guide!(adg: "adg-interface-by-app-expected.html#adg-pam_get_item")]
26 /// [adg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/adg-interface-by-app-expected.html#adg-pam_get_item 27 #[doc = _guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_get_item")]
27 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_item 28 #[doc = _stdlinks!(3 pam_get_item)]
28 fn $getter(&self) -> Result<Option<String>>; 29 fn $getter(&self) -> Result<Option<String>>;
29 }; 30 };
30 ($(#[$md:meta])* set = $setter:ident, item = $item:literal $(, see = $see:path)?) => { 31 ($(#[$md:meta])* set = $setter:ident, item = $item:literal $(, see = $see:path)?) => {
31 $(#[$md])* 32 $(#[$md])*
33 #[doc = ""]
32 #[doc = concat!("Sets the `", $item, "` from the PAM handle.")] 34 #[doc = concat!("Sets the `", $item, "` from the PAM handle.")]
33 $( 35 $(
34 #[doc = concat!("See [`", stringify!($see), "`].")] 36 #[doc = concat!("See [`", stringify!($see), "`].")]
35 )? 37 )?
36 /// 38 ///
37 /// Sets the item's value. PAM copies the string's contents. 39 /// Sets the item's value. PAM copies the string's contents.
38 /// If the string contains a null byte, this will return 40 /// If the string contains a null byte, this will return
39 /// a `ConversationError`. 41 /// a `ConversationError`.
40 /// 42 ///
41 /// See the [`pam_set_item`][man] manual page, 43 /// # References
42 /// [`pam_set_item` in the Module Writers' Guide][mwg], or 44 ///
43 /// [`pam_set_item` in the Application Developers' Guide][adg]. 45 #[doc = _linklist!(pam_set_item: mwg, adg, _std)]
44 /// 46 ///
45 /// [man]: https://www.man7.org/linux/man-pages/man3/pam_set_item.3.html 47 #[doc = _guide!(adg: "adg-interface-by-app-expected.html#adg-pam_set_item")]
46 /// [adg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/adg-interface-by-app-expected.html#adg-pam_set_item 48 #[doc = _guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_set_item")]
47 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_set_item 49 #[doc = _stdlinks!(3 pam_set_item)]
48 fn $setter(&mut self, value: Option<&str>) -> Result<()>; 50 fn $setter(&mut self, value: Option<&str>) -> Result<()>;
49 }; 51 };
50 } 52 }
51 53
52 /// Functionality for both PAM applications and PAM modules. 54 /// Functionality for both PAM applications and PAM modules.
59 /// to test PAM modules and applications. 61 /// to test PAM modules and applications.
60 pub trait PamShared { 62 pub trait PamShared {
61 /// Logs something via this PAM handle. 63 /// Logs something via this PAM handle.
62 /// 64 ///
63 /// You probably want to use one of the logging macros, 65 /// You probably want to use one of the logging macros,
64 /// like [`error!`], [`warning!`], [`info!`], or [`debug!`]. 66 /// like [`error!`](crate::error!),
67 /// [`warn!`](crate::warn!),
68 /// [`info!`](crate::info!),
69 /// or [`debug!`](crate::debug!).
65 /// 70 ///
66 /// In most PAM implementations, this will go to syslog. 71 /// In most PAM implementations, this will go to syslog.
72 /// See [Linux-PAM's `pam_syslog`][man7] or
73 /// [OpenPAM's `openpam_log`][manbsd] for more details.
67 /// 74 ///
68 /// # Example 75 /// # Example
69 /// 76 ///
70 /// ```no_run 77 /// ```no_run
71 /// # use nonstick::{PamShared}; 78 /// # use nonstick::{PamShared};
80 /// nonstick::debug!(pam_hdl, "sending GET request to {url}"); 87 /// nonstick::debug!(pam_hdl, "sending GET request to {url}");
81 /// // But if you really want to, you can call this yourself: 88 /// // But if you really want to, you can call this yourself:
82 /// pam_hdl.log(Level::Warning, "this is unnecessarily verbose"); 89 /// pam_hdl.log(Level::Warning, "this is unnecessarily verbose");
83 /// # } 90 /// # }
84 /// ``` 91 /// ```
92 #[doc = _man7!(3 pam_syslog)]
93 #[doc = _manbsd!(3 openpam_log)]
85 fn log(&self, level: Level, entry: &str); 94 fn log(&self, level: Level, entry: &str);
86 95
87 /// Retrieves the name of the user who is authenticating or logging in. 96 /// Retrieves the name of the user who is authenticating or logging in.
88 /// 97 ///
89 /// If the username has previously been obtained, this uses that username; 98 /// If the username has previously been obtained, this uses that username;
91 /// 100 ///
92 /// 1. The prompt string passed to this function. 101 /// 1. The prompt string passed to this function.
93 /// 2. The string returned by `get_user_prompt_item`. 102 /// 2. The string returned by `get_user_prompt_item`.
94 /// 3. The default prompt, `login: `. 103 /// 3. The default prompt, `login: `.
95 /// 104 ///
96 /// See the [`pam_get_user` manual page][man] 105 /// # References
97 /// or [`pam_get_user` in the Module Writer's Guide][mwg]. 106 #[doc = _linklist!(pam_get_user: mwg, _std)]
98 /// 107 ///
99 /// # Example 108 /// # Example
100 /// 109 ///
101 /// ```no_run 110 /// ```no_run
102 /// # use nonstick::PamShared; 111 /// # use nonstick::PamShared;
108 /// // both user and user_2 would have the same value. 117 /// // both user and user_2 would have the same value.
109 /// let user_2 = handle.username(Some("who ARE you even???"))?; 118 /// let user_2 = handle.username(Some("who ARE you even???"))?;
110 /// # Ok(()) 119 /// # Ok(())
111 /// # } 120 /// # }
112 /// ``` 121 /// ```
113 /// 122 #[doc = _stdlinks!(3 pam_get_user)]
114 /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_user.3.html 123 #[doc = _guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_get_user")]
115 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_user
116 fn username(&mut self, prompt: Option<&str>) -> Result<String>; 124 fn username(&mut self, prompt: Option<&str>) -> Result<String>;
117 125
118 /// The contents of the environment to set, read-only. 126 /// The contents of the environment to set, read-only.
119 fn environ(&self) -> impl EnvironMap; 127 fn environ(&self) -> impl EnvironMap;
120 128
149 /// to perform authentication. 157 /// to perform authentication.
150 get = service, 158 get = service,
151 item = "PAM_SERVICE" 159 item = "PAM_SERVICE"
152 ); 160 );
153 trait_item!( 161 trait_item!(
154 /// The service name, which identifies the PAM stack which is used 162 /// Sets the service name. It's probably a bad idea to change this.
155 /// to perform authentication. It's probably a bad idea to change this.
156 set = set_service, 163 set = set_service,
157 item = "PAM_SERVICE", 164 item = "PAM_SERVICE",
158 see = Self::service 165 see = Self::service
159 ); 166 );
160 167
189 196
190 trait_item!( 197 trait_item!(
191 /// If set, the identity of the remote user logging in. 198 /// If set, the identity of the remote user logging in.
192 /// 199 ///
193 /// This is only as trustworthy as the application calling PAM. 200 /// This is only as trustworthy as the application calling PAM.
194 /// Also see [`remote_host`](Self::remote_host).
195 get = remote_user, 201 get = remote_user,
196 item = "PAM_RUSER" 202 item = "PAM_RUSER",
203 see = Self::remote_host
197 ); 204 );
198 trait_item!( 205 trait_item!(
199 /// Sets the identity of the remote user logging in. 206 /// Sets the identity of the remote user logging in.
200 /// 207 ///
201 /// This may be set by the application before making calls 208 /// This may be set by the application before making calls
202 /// into a PAM transaction. 209 /// into a PAM transaction.
203 set = set_remote_user, 210 set = set_remote_user,
204 item = "PAM_RUSER" 211 item = "PAM_RUSER",
212 see = Self::remote_user
205 ); 213 );
206 214
207 trait_item!( 215 trait_item!(
208 /// If set, the remote location where the user is coming from. 216 /// If set, the remote location where the user is coming from.
209 /// 217 ///
213 /// with `remote_user@remote_host`. 221 /// with `remote_user@remote_host`.
214 /// 222 ///
215 /// If unset, "it is unclear where the authentication request 223 /// If unset, "it is unclear where the authentication request
216 /// is originating from." 224 /// is originating from."
217 get = remote_host, 225 get = remote_host,
218 item = "PAM_RHOST" 226 item = "PAM_RHOST",
227 see = Self::remote_user
219 ); 228 );
220 trait_item!( 229 trait_item!(
221 /// Sets the location where the user is coming from. 230 /// Sets the location where the user is coming from.
222 /// 231 ///
223 /// This may be set by the application before making calls 232 /// This may be set by the application before making calls
238 see = PamHandleModule::authtok_item 247 see = PamHandleModule::authtok_item
239 ); 248 );
240 249
241 trait_item!( 250 trait_item!(
242 /// Sets the user's "old authentication token" when changing passwords. 251 /// Sets the user's "old authentication token" when changing passwords.
243 // 252 ///
244 /// This is usually set automatically by PAM. 253 /// This is usually set automatically by PAM.
245 set = set_old_authtok_item, 254 set = set_old_authtok_item,
246 item = "PAM_OLDAUTHTOK", 255 item = "PAM_OLDAUTHTOK",
247 see = PamHandleModule::old_authtok_item 256 see = PamHandleModule::old_authtok_item
248 ); 257 );
255 /// 264 ///
256 /// Like [`PamShared`], this is intended to allow creating mock implementations 265 /// Like [`PamShared`], this is intended to allow creating mock implementations
257 /// of PAM for testing PAM applications. 266 /// of PAM for testing PAM applications.
258 pub trait PamHandleApplication: PamShared { 267 pub trait PamHandleApplication: PamShared {
259 /// Starts the authentication process for the user. 268 /// Starts the authentication process for the user.
269 ///
270 /// The application calls this to find out who the user is, and verify that
271 /// they are really that person. If authentication is successful,
272 /// this will return an `Ok(())` [`Result`].
273 ///
274 /// A PAM module may change the caller's [username](PamShared::username)
275 /// as part of the login process, so be sure to check it after making
276 /// any PAM application call.
277 ///
278 /// # References
279 #[doc = _linklist!(pam_authenticate: adg, _std)]
280 ///
281 #[doc = _guide!(adg: "adg-interface-by-app-expected.html#adg-pam_authenticate")]
282 #[doc = _stdlinks!(3 pam_authenticate)]
260 fn authenticate(&mut self, flags: Flags) -> Result<()>; 283 fn authenticate(&mut self, flags: Flags) -> Result<()>;
261 284
262 /// Does "account management". 285 /// Verifies the validity of the user's account (and other stuff).
286 ///
287 /// After [authentication](Self::authenticate), an application should call
288 /// this to ensure that the user's account is still valid. This may check
289 /// for token expiration or that the user's account is not locked.
290 ///
291 /// # References
292 #[doc = _linklist!(pam_acct_mgmt: adg, _std)]
293 ///
294 #[doc = _guide!(adg: "adg-interface-by-app-expected.html#adg-pam_acct_mgmt")]
295 #[doc = _stdlinks!(3 pam_acct_mgmt)]
263 fn account_management(&mut self, flags: Flags) -> Result<()>; 296 fn account_management(&mut self, flags: Flags) -> Result<()>;
264 297
265 /// Changes the authentication token. 298 /// Changes the authentication token.
299 ///
300 /// # References
301 #[doc = _linklist!(pam_chauthtok: adg, _std)]
302 ///
303 #[doc = _guide!(adg: "adg-interface-by-app-expected.html#adg-pam_chauthtok")]
304 #[doc = _stdlinks!(3 pam_chauthtok)]
266 fn change_authtok(&mut self, flags: Flags) -> Result<()>; 305 fn change_authtok(&mut self, flags: Flags) -> Result<()>;
267 } 306 }
268 307
269 /// Functionality of a PAM handle that can be expected by a PAM module. 308 /// Functionality of a PAM handle that can be expected by a PAM module.
270 /// 309 ///
275 /// of PAM for testing PAM modules. 314 /// of PAM for testing PAM modules.
276 pub trait PamHandleModule: Conversation + PamShared { 315 pub trait PamHandleModule: Conversation + PamShared {
277 /// Retrieves the authentication token from the user. 316 /// Retrieves the authentication token from the user.
278 /// 317 ///
279 /// This should only be used by *authentication* and *password-change* 318 /// This should only be used by *authentication* and *password-change*
280 /// PAM modules. 319 /// PAM modules. This is an extension provided by
281 /// 320 /// both Linux-PAM and OpenPAM.
282 /// See the [`pam_get_authtok` manual page][man] 321 ///
283 /// or [`pam_get_item` in the Module Writer's Guide][mwg]. 322 /// # References
323 ///
324 #[doc = _linklist!(pam_get_authtok: man7, manbsd)]
284 /// 325 ///
285 /// # Example 326 /// # Example
286 /// 327 ///
287 /// ```no_run 328 /// ```no_run
288 /// # use nonstick::handle::PamHandleModule; 329 /// # use nonstick::handle::PamHandleModule;
292 /// // Get the user's password using a custom prompt. 333 /// // Get the user's password using a custom prompt.
293 /// let pass = handle.authtok(Some("Reveal your secrets!"))?; 334 /// let pass = handle.authtok(Some("Reveal your secrets!"))?;
294 /// Ok(()) 335 /// Ok(())
295 /// # } 336 /// # }
296 /// ``` 337 /// ```
297 /// 338 #[doc = _man7!(3 pam_get_authtok)]
298 /// [man]: https://www.man7.org/linux/man-pages/man3/pam_get_authtok.3.html 339 #[doc = _manbsd!(3 pam_get_authtok)]
299 /// [mwg]: https://www.chiark.greenend.org.uk/doc/libpam-doc/html/mwg-expected-by-module-item.html#mwg-pam_get_item
300 fn authtok(&mut self, prompt: Option<&str>) -> Result<String>; 340 fn authtok(&mut self, prompt: Option<&str>) -> Result<String>;
301 341
302 trait_item!( 342 trait_item!(
303 /// Gets the user's authentication token (e.g., password). 343 /// Gets the user's authentication token (e.g., password).
304 /// 344 ///