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