Mercurial > crates > nonstick
comparison 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 |
comparison
equal
deleted
inserted
replaced
145:8f964b701652 | 146:1bc52025156b |
---|---|
1 //! The wrapper types and traits for handles into the PAM library. | 1 //! The wrapper types and traits for handles into the PAM library. |
2 | 2 |
3 use crate::_doc::{guide, linklist, man7, manbsd, stdlinks}; | |
3 use crate::constants::{Flags, Result}; | 4 use crate::constants::{Flags, Result}; |
4 use crate::conv::Conversation; | 5 use crate::conv::Conversation; |
5 use crate::environ::{EnvironMap, EnvironMapMut}; | 6 use crate::environ::{EnvironMap, EnvironMapMut}; |
7 use crate::items::{getter, Items, ItemsMut}; | |
6 use crate::logging::{Level, Location}; | 8 use crate::logging::{Level, Location}; |
7 use crate::{guide, linklist, man7, manbsd, stdlinks}; | |
8 use std::ffi::{OsStr, OsString}; | 9 use std::ffi::{OsStr, OsString}; |
9 | |
10 macro_rules! trait_item { | |
11 ($(#[$md:meta])* get = $getter:ident, item = $item:literal $(, see = $see:path)?) => { | |
12 $(#[$md])* | |
13 #[doc = ""] | |
14 #[doc = concat!("Gets the `", $item, "` of the PAM handle.")] | |
15 $( | |
16 #[doc = concat!("See [`", stringify!($see), "`].")] | |
17 )? | |
18 /// | |
19 /// Returns a reference to the item's value, owned by PAM. | |
20 /// The item is assumed to be valid UTF-8 text. | |
21 /// If it is not, `ConversationError` is returned. | |
22 /// | |
23 /// # References | |
24 /// | |
25 #[doc = linklist!(pam_get_item: mwg, adg, _std)] | |
26 /// | |
27 #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_get_item")] | |
28 #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_get_item")] | |
29 #[doc = stdlinks!(3 pam_get_item)] | |
30 fn $getter(&self) -> Result<Option<OsString>>; | |
31 }; | |
32 ($(#[$md:meta])* set = $setter:ident, item = $item:literal $(, see = $see:path)?) => { | |
33 $(#[$md])* | |
34 #[doc = ""] | |
35 #[doc = concat!("Sets the `", $item, "` from the PAM handle.")] | |
36 $( | |
37 #[doc = concat!("See [`", stringify!($see), "`].")] | |
38 )? | |
39 /// | |
40 /// Sets the item's value. PAM copies the string's contents. | |
41 /// | |
42 /// # Panics | |
43 /// | |
44 /// If the string contains a nul byte, this will panic. | |
45 /// | |
46 /// # References | |
47 /// | |
48 #[doc = linklist!(pam_set_item: mwg, adg, _std)] | |
49 /// | |
50 #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_set_item")] | |
51 #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_set_item")] | |
52 #[doc = stdlinks!(3 pam_set_item)] | |
53 fn $setter(&mut self, value: Option<&OsStr>) -> Result<()>; | |
54 }; | |
55 } | |
56 | 10 |
57 /// Functionality for both PAM applications and PAM modules. | 11 /// Functionality for both PAM applications and PAM modules. |
58 /// | 12 /// |
59 /// This base trait includes features of a PAM handle that are available | 13 /// This base trait includes features of a PAM handle that are available |
60 /// to both applications and modules. | 14 /// to both applications and modules. |
125 /// ``` | 79 /// ``` |
126 #[doc = stdlinks!(3 pam_get_user)] | 80 #[doc = stdlinks!(3 pam_get_user)] |
127 #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_get_user")] | 81 #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_get_user")] |
128 fn username(&mut self, prompt: Option<&OsStr>) -> Result<OsString>; | 82 fn username(&mut self, prompt: Option<&OsStr>) -> Result<OsString>; |
129 | 83 |
130 /// The contents of the environment to set, read-only. | 84 /// The contents of the environment to set for the logged-in user. |
85 /// | |
86 /// # References | |
87 /// | |
88 #[doc = linklist!(pam_getenv: adg, mwg, _std)] | |
89 /// | |
90 #[doc = stdlinks!(3 pam_getenv)] | |
91 #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_getenv")] | |
92 #[doc = guide!(mwg: "mwg-expected-by-module-item.html#adg-pam_getenv")] | |
131 fn environ(&self) -> impl EnvironMap; | 93 fn environ(&self) -> impl EnvironMap; |
132 | 94 |
133 /// A writable version of the environment. | 95 /// A writable map of the environment to set for the logged-in user. |
96 /// | |
97 /// # References | |
98 /// | |
99 #[doc = linklist!(pam_putenv: adg, mwg, _std)] | |
100 /// | |
101 #[doc = stdlinks!(3 pam_putenv)] | |
102 #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_putenv")] | |
103 #[doc = guide!(mwg: "mwg-expected-by-module-item.html#adg-pam_putenv")] | |
134 fn environ_mut(&mut self) -> impl EnvironMapMut; | 104 fn environ_mut(&mut self) -> impl EnvironMapMut; |
135 | 105 |
136 trait_item!( | 106 /// Gets Items, data shared by PAM, the application, and modules. |
137 /// The identity of the user for whom service is being requested. | 107 /// |
138 /// | 108 /// Certain Items should not be accessed by a PAM application; |
139 /// Unlike [`username`](Self::username), this will simply get | 109 /// those are available directly on [`ModuleClient`] for use |
140 /// the current state of the user item, and not request the username. | 110 /// by PAM modules only. |
141 /// While PAM usually sets this automatically in the `username` call, | 111 /// |
142 /// it may be changed by a module during the PAM transaction. | 112 /// # References |
143 /// Applications should check it after each step of the PAM process. | 113 /// |
144 get = user_item, | 114 #[doc = linklist!(pam_get_item: mwg, adg, _std)] |
145 item = "PAM_USER", | 115 /// |
146 see = Self::username | 116 #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_get_item")] |
147 ); | 117 #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_get_item")] |
148 trait_item!( | 118 #[doc = stdlinks!(3 pam_get_item)] |
149 /// Sets the identity of the logging-in user. | 119 fn items(&self) -> impl Items; |
150 /// | 120 |
151 /// Usually this will be set during the course of | 121 /// Read-write access to PAM Items. |
152 /// a [`username`](Self::username) call, but you may set it manually | 122 /// |
153 /// or change it during the PAM process. | 123 /// # References |
154 set = set_user_item, | 124 /// |
155 item = "PAM_USER", | 125 #[doc = linklist!(pam_set_item: mwg, adg, _std)] |
156 see = Self::user_item | 126 /// |
157 ); | 127 #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_set_item")] |
158 | 128 #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_set_item")] |
159 trait_item!( | 129 #[doc = stdlinks!(3 pam_set_item)] |
160 /// The service name, which identifies the PAM stack which is used | 130 fn items_mut(&mut self) -> impl ItemsMut; |
161 /// to perform authentication. | |
162 get = service, | |
163 item = "PAM_SERVICE" | |
164 ); | |
165 trait_item!( | |
166 /// Sets the service name. It's probably a bad idea to change this. | |
167 set = set_service, | |
168 item = "PAM_SERVICE", | |
169 see = Self::service | |
170 ); | |
171 | |
172 trait_item!( | |
173 /// The string used to prompt for a user's name. | |
174 /// By default, this is a localized version of `login: `. | |
175 get = user_prompt, | |
176 item = "PAM_USER_PROMPT" | |
177 ); | |
178 trait_item!( | |
179 /// Sets the string used to prompt for a user's name. | |
180 set = set_user_prompt, | |
181 item = "PAM_USER_PROMPT", | |
182 see = Self::user_prompt | |
183 ); | |
184 | |
185 trait_item!( | |
186 /// The device path of the TTY being used to log in. | |
187 /// | |
188 /// This is the terminal the user is logging in on, | |
189 /// specified as the full device path (e.g. `/dev/tty0`). | |
190 /// Very old applications may use this instead of `PAM_XDISPLAY`. | |
191 get = tty_name, | |
192 item = "PAM_TTY" | |
193 ); | |
194 trait_item!( | |
195 /// Sets the path to the terminal where the user is logging on. | |
196 set = set_tty_name, | |
197 item = "PAM_TTY", | |
198 see = Self::tty_name | |
199 ); | |
200 | |
201 trait_item!( | |
202 /// If set, the identity of the remote user logging in. | |
203 /// | |
204 /// This is only as trustworthy as the application calling PAM. | |
205 get = remote_user, | |
206 item = "PAM_RUSER", | |
207 see = Self::remote_host | |
208 ); | |
209 trait_item!( | |
210 /// Sets the identity of the remote user logging in. | |
211 /// | |
212 /// This may be set by the application before making calls | |
213 /// into a PAM transaction. | |
214 set = set_remote_user, | |
215 item = "PAM_RUSER", | |
216 see = Self::remote_user | |
217 ); | |
218 | |
219 trait_item!( | |
220 /// If set, the remote location where the user is coming from. | |
221 /// | |
222 /// This is only as trustworthy as the application calling PAM. | |
223 /// This can be combined with [`Self::remote_user`] to identify | |
224 /// the account the user is attempting to log in from, | |
225 /// with `remote_user@remote_host`. | |
226 /// | |
227 /// If unset, "it is unclear where the authentication request | |
228 /// is originating from." | |
229 get = remote_host, | |
230 item = "PAM_RHOST", | |
231 see = Self::remote_user | |
232 ); | |
233 trait_item!( | |
234 /// Sets the location where the user is coming from. | |
235 /// | |
236 /// This may be set by the application before making calls | |
237 /// into a PAM transaction. | |
238 set = set_remote_host, | |
239 item = "PAM_RHOST", | |
240 see = Self::remote_host | |
241 ); | |
242 | |
243 trait_item!( | |
244 /// Gets the user's authentication token (e.g., password). | |
245 /// | |
246 /// This is usually set automatically when | |
247 /// [`authtok`](PamHandleModule::authtok) is called, | |
248 /// but can be manually set. | |
249 set = set_authtok_item, | |
250 item = "PAM_AUTHTOK", | |
251 see = PamHandleModule::authtok_item | |
252 ); | |
253 | |
254 trait_item!( | |
255 /// Sets the user's "old authentication token" when changing passwords. | |
256 /// | |
257 /// This is usually set automatically by PAM. | |
258 set = set_old_authtok_item, | |
259 item = "PAM_OLDAUTHTOK", | |
260 see = PamHandleModule::old_authtok_item | |
261 ); | |
262 } | 131 } |
263 | 132 |
264 /// Functionality of a PAM handle that can be expected by a PAM application. | 133 /// Functionality of a PAM handle that can be expected by a PAM application. |
265 /// | 134 /// |
266 /// If you are not writing a PAM client application (e.g., you are writing | 135 /// If you are not writing a PAM client application (e.g., you are writing |
314 /// If you are not writing a PAM module (e.g., you are writing an application), | 183 /// If you are not writing a PAM module (e.g., you are writing an application), |
315 /// you should not use any of the functionality exposed by this trait. | 184 /// you should not use any of the functionality exposed by this trait. |
316 /// | 185 /// |
317 /// Like [`PamShared`], this is intended to allow creating mock implementations | 186 /// Like [`PamShared`], this is intended to allow creating mock implementations |
318 /// of PAM for testing PAM modules. | 187 /// of PAM for testing PAM modules. |
319 pub trait PamHandleModule: Conversation + PamShared { | 188 pub trait ModuleClient: Conversation + PamShared { |
320 /// Retrieves the authentication token from the user. | 189 /// Retrieves the authentication token from the user. |
321 /// | 190 /// |
322 /// This should only be used by *authentication* and *password-change* | 191 /// This should only be used by *authentication* and *password-change* |
323 /// PAM modules. | 192 /// PAM modules. |
324 /// | 193 /// |
327 #[doc = linklist!(pam_get_authtok: man7, manbsd)] | 196 #[doc = linklist!(pam_get_authtok: man7, manbsd)] |
328 /// | 197 /// |
329 /// # Example | 198 /// # Example |
330 /// | 199 /// |
331 /// ```no_run | 200 /// ```no_run |
332 /// # use nonstick::handle::PamHandleModule; | 201 /// # use nonstick::handle::ModuleClient; |
333 /// # fn _doc(handle: &mut impl PamHandleModule) -> Result<(), Box<dyn std::error::Error>> { | 202 /// # fn _doc(handle: &mut impl ModuleClient) -> Result<(), Box<dyn std::error::Error>> { |
334 /// // Get the user's password using the default prompt. | 203 /// // Get the user's password using the default prompt. |
335 /// let pass = handle.authtok(None)?; | 204 /// let pass = handle.authtok(None)?; |
336 /// // Get the user's password using a custom prompt. | 205 /// // Get the user's password using a custom prompt. |
337 /// let pass = handle.authtok(Some("Reveal your secrets!".as_ref()))?; | 206 /// let pass = handle.authtok(Some("Reveal your secrets!".as_ref()))?; |
338 /// Ok(()) | 207 /// Ok(()) |
342 #[doc = manbsd!(3 pam_get_authtok)] | 211 #[doc = manbsd!(3 pam_get_authtok)] |
343 fn authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString>; | 212 fn authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString>; |
344 | 213 |
345 /// Retrieves the user's old authentication token when changing passwords. | 214 /// Retrieves the user's old authentication token when changing passwords. |
346 /// | 215 /// |
347 /// | 216 /// This should only be used by a *password-change* module. |
217 /// | |
218 /// # References | |
219 /// | |
220 #[doc = linklist!(pam_get_authtok: man7, manbsd)] | |
221 /// | |
222 /// # Example | |
223 /// | |
224 /// ```no_run | |
225 /// # use nonstick::handle::ModuleClient; | |
226 /// # fn _doc(handle: &mut impl ModuleClient) -> Result<(), Box<dyn std::error::Error>> { | |
227 /// // Get the user's password using the default prompt. | |
228 /// let pass = handle.old_authtok(None)?; | |
229 /// // Get the user's password using a custom prompt. | |
230 /// let pass = handle.old_authtok(Some("Reveal your secrets!".as_ref()))?; | |
231 /// Ok(()) | |
232 /// # } | |
233 /// ``` | |
234 /// | |
235 #[doc = stdlinks!(3 pam_get_authtok)] | |
348 fn old_authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString>; | 236 fn old_authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString>; |
349 | 237 |
350 trait_item!( | 238 getter!( |
351 /// Gets the user's authentication token (e.g., password). | 239 /// Gets the user's authentication token (e.g., password). |
352 /// | 240 /// |
353 /// This is normally set automatically by PAM when calling | 241 /// This is normally set automatically by PAM through [`Self::authtok`], |
354 /// [`authtok`](Self::authtok), but can be set explicitly. | 242 /// but this will get its value (if set) without prompting the user. |
355 /// | 243 /// |
356 /// Like `authtok`, this should only ever be called | 244 /// Like `authtok`, this should only ever be called |
357 /// by *authentication* and *password-change* PAM modules. | 245 /// by *authentication* and *password-change* PAM modules. |
358 get = authtok_item, | 246 /// |
359 item = "PAM_AUTHTOK", | 247 /// # References |
360 see = Self::authtok | 248 /// |
249 #[doc = linklist!(pam_set_item: mwg, adg, _std)] | |
250 /// | |
251 #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_set_item")] | |
252 #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_set_item")] | |
253 #[doc = stdlinks!(3 pam_set_item)] | |
254 authtok_item("PAM_AUTHTOK", see = Self::authtok) | |
361 ); | 255 ); |
362 | 256 |
363 trait_item!( | 257 getter!( |
364 /// Gets the user's old authentication token when changing passwords. | 258 /// Gets the user's old authentication token when changing passwords. |
365 /// | 259 /// |
366 /// This is normally set automatically by PAM when calling | 260 /// This is normally set automatically by PAM through |
367 /// [`old_authtok`](Self::old_authtok), but can be set explicitly. | 261 /// [`Self::old_authtok`], but this will get its value (if set) |
262 /// without prompting the user. | |
368 /// | 263 /// |
369 /// This should only ever be called by *password-change* PAM modules. | 264 /// This should only ever be called by *password-change* PAM modules. |
370 get = old_authtok_item, | 265 /// |
371 item = "PAM_OLDAUTHTOK", | 266 /// # References |
372 see = PamShared::set_old_authtok_item | 267 /// |
268 #[doc = linklist!(pam_set_item: mwg, adg, _std)] | |
269 /// | |
270 #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_set_item")] | |
271 #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_set_item")] | |
272 #[doc = stdlinks!(3 pam_set_item)] | |
273 old_authtok_item("PAM_OLDAUTHTOK", see = ItemsMut::set_old_authtok) | |
373 ); | 274 ); |
374 } | 275 } |