comparison src/handle.rs @ 153:3036f2e6a022

Add module-specific data support. This adds support for a safe form of `pam_get_data` and `pam_set_data`, where data is (as best as humanly possible) type-safe and restricted to only the module where it was created.
author Paul Fisher <paul@pfish.zone>
date Tue, 08 Jul 2025 00:31:54 -0400
parents 1bc52025156b
children
comparison
equal deleted inserted replaced
152:4d11b2e7da83 153:3036f2e6a022
233 /// ``` 233 /// ```
234 /// 234 ///
235 #[doc = stdlinks!(3 pam_get_authtok)] 235 #[doc = stdlinks!(3 pam_get_authtok)]
236 fn old_authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString>; 236 fn old_authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString>;
237 237
238 /// Gets an item of module-specific data stored over the transaction.
239 ///
240 /// This gives you a reference to the data that was earlier set with
241 /// [`Self::set_module_data`]. If not present, you get `None`.
242 ///
243 /// Data is in a module-specific, type-specific namespace.
244 ///
245 /// ```
246 /// # use nonstick::ModuleClient;
247 /// # use std::path::PathBuf;
248 /// # fn test(client: &impl ModuleClient) {
249 /// // These two can coexist and do not overlap.
250 /// let str_data: Option<&String> = client.get_module_data("the_key");
251 /// let num_data: Option<&u64> = client.get_module_data("the_key");
252 /// // ...
253 /// let nothing_data: Option<&PathBuf> = client.get_module_data("this does not exist");
254 /// # }
255 /// ```
256 ///
257 /// # References
258 ///
259 #[doc = linklist!(pam_get_data: mwg, _std)]
260 ///
261 #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_get_data")]
262 #[doc = stdlinks!(3 pam_get_data)]
263
264 fn get_module_data<T: 'static>(&self, key: &str) -> Option<&T>;
265
266 /// Sets module-specific data.
267 ///
268 /// A PAM module may need to store data across multiple invocations within
269 /// the same PAM transaction. For instance, a module that stores credentials
270 /// would need to know where those credentials were stored in order to
271 /// update or destroy them later. Also see [`Self::get_module_data`].
272 ///
273 /// Module-specific data gives a module a way to store such data.
274 /// Data are stored in a module-specific, type-specific namespace.
275 ///
276 /// PAM takes ownership of the data passed in. See the **Cleanup** section
277 /// below for details on how cleanup is handled.
278 ///
279 /// # Examples
280 ///
281 /// Each type of data is in a separate namespace:
282 ///
283 /// ```
284 /// # use nonstick::{ModuleClient, Result};
285 /// # fn test(client: &mut impl ModuleClient) -> Result<()> {
286 /// client.set_module_data("count", 999i32)?;
287 ///
288 /// let count_int: Option<&i32> = client.get_module_data("count");
289 /// // count_int = Some(&999i32)
290 /// let count_string: Option<&String> = client.get_module_data("count");
291 /// // count_string = None
292 /// # Ok(())
293 /// # }
294 /// ```
295 ///
296 /// Data persist across invocations of the same module:
297 ///
298 /// ```
299 /// # use nonstick::{ModuleClient, Result};
300 /// // In a pam_authenticate call, this function is called:
301 /// fn authenticate(client: &mut impl ModuleClient) -> Result<()> {
302 /// client.set_module_data::<u64>("TOKEN_ID", 0x0fa1afe10000beef)?;
303 /// Ok(())
304 /// }
305 ///
306 /// // Later, in a pam_session_start call:
307 /// fn start_session(client: &mut impl ModuleClient) -> Result<()> {
308 /// match client.get_module_data::<u64>("TOKEN_ID") {
309 /// Some(&tid) => {
310 /// // This will execute and tid will be 0x0fa1afe10000beef.
311 /// },
312 /// None => { /* This will not execute. */ },
313 /// }
314 /// Ok(())
315 /// }
316 /// ```
317 ///
318 /// Each module has its own set of data:
319 ///
320 /// ```
321 /// # use nonstick::{ModuleClient, Result};
322 /// // This function is called somewhere in pam_module_a.so.
323 /// fn in_pam_module_a(client: &mut impl ModuleClient) -> Result<()> {
324 /// client.set_module_data("value", String::from("pam_module_a data"))?;
325 /// Ok(())
326 /// }
327 ///
328 /// // This function is called later in pam_module_b.so.
329 /// fn in_pam_module_b(client: &mut impl ModuleClient) -> Result<()> {
330 /// match client.get_module_data::<String>("value") {
331 /// Some(value) => {
332 /// // This will match, because pam_module_a's data
333 /// // is completely unrelated to pam_module_b's data.
334 /// },
335 /// None => {
336 /// // This branch will execute.
337 /// },
338 /// }
339 /// // ...
340 /// # Ok(())
341 /// }
342 /// ```
343 ///
344 /// # Cleanup
345 ///
346 /// PAM modules should be careful about cleaning up data outside their own
347 /// address space, because PAM applications may `fork()`:
348 ///
349 /// ```plain
350 /// ┃ let tx = start_pam_transaction();
351 /// ┃
352 /// ┃ tx.authenticate();
353 /// ┃ │ // PAM calls into your module where you set data:
354 /// ┃ │ handle.set_module_data("key", the_data);
355 /// ┃
356 /// ┃ fork();
357 /// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━┓
358 /// Parent process Child process
359 /// ┃ wait(child); ┃ setuid(user_to_login);
360 /// ┃ ┆ ┃ // ... do other stuff ...
361 /// ┃ ┆ ┃ drop(tx);
362 /// ┃ ┆ ┃ │ // PAM cleans up your data.
363 /// ┃ ┆ ┃ │ drop(the_data);
364 /// ┃ ┆ ┗ exec(user's shell)
365 /// ┃ ┆ ┃ // user does stuff over their session
366 /// ┃ ┆ ┃ // ...
367 /// ┃ ┆ X
368 /// ┃
369 /// ┃ drop(tx);
370 /// ┃ │ // Parent PAM cleans up your data.
371 /// ┃ │ drop(the_data); // Called again, but in this process instead!
372 /// ```
373 ///
374 /// While LibPAM offers a way to customize the action taken on cleanup,
375 /// we do not (yet) offer this.
376 ///
377 /// # References
378 ///
379 #[doc = linklist!(pam_set_data: mwg, _std)]
380 ///
381 #[doc = guide!(mwg: "mwg-expected-by-module-item.html#mwg-pam_set_data")]
382 #[doc = stdlinks!(3 pam_set_data)]
383 fn set_module_data<T: 'static>(&mut self, key: &str, data: T) -> Result<()>;
384
238 getter!( 385 getter!(
239 /// Gets the user's authentication token (e.g., password). 386 /// Gets the user's authentication token (e.g., password).
240 /// 387 ///
241 /// This is normally set automatically by PAM through [`Self::authtok`], 388 /// This is normally set automatically by PAM through [`Self::authtok`],
242 /// but this will get its value (if set) without prompting the user. 389 /// but this will get its value (if set) without prompting the user.