Mercurial > crates > nonstick
comparison src/libpam/handle.rs @ 144:56b559b7ecea
Big rename: separate concepts of Transaction from Handle.
- An application that uses PAM creates a Transaction.
- The Transaction has a Handle.
Currently, a module still get something called a "handle",
but that's probably going to change soon.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sun, 06 Jul 2025 11:59:26 -0400 |
parents | ebb71a412b58 |
children | 1bc52025156b |
comparison
equal
deleted
inserted
replaced
143:ebb71a412b58 | 144:56b559b7ecea |
---|---|
5 use crate::handle::PamShared; | 5 use crate::handle::PamShared; |
6 use crate::libpam::environ::{LibPamEnviron, LibPamEnvironMut}; | 6 use crate::libpam::environ::{LibPamEnviron, LibPamEnvironMut}; |
7 use crate::libpam::memory; | 7 use crate::libpam::memory; |
8 use crate::logging::{Level, Location}; | 8 use crate::logging::{Level, Location}; |
9 use crate::{ | 9 use crate::{ |
10 guide, linklist, stdlinks, Conversation, EnvironMap, Flags, PamHandleApplication, | 10 guide, linklist, stdlinks, Conversation, EnvironMap, Flags, PamHandleModule, Transaction, |
11 PamHandleModule, | |
12 }; | 11 }; |
13 use libpam_sys_helpers::constants; | 12 use libpam_sys_helpers::constants; |
14 use num_enum::{IntoPrimitive, TryFromPrimitive}; | 13 use num_enum::{IntoPrimitive, TryFromPrimitive}; |
15 use std::cell::Cell; | 14 use std::cell::Cell; |
16 use std::ffi::{c_char, c_int, CString, OsStr, OsString}; | 15 use std::ffi::{c_char, c_int, CString, OsStr, OsString}; |
18 use std::os::unix::ffi::OsStrExt; | 17 use std::os::unix::ffi::OsStrExt; |
19 use std::ptr; | 18 use std::ptr; |
20 use std::ptr::NonNull; | 19 use std::ptr::NonNull; |
21 | 20 |
22 /// An owned PAM handle. | 21 /// An owned PAM handle. |
23 pub struct OwnedLibPamHandle<C: Conversation> { | 22 pub struct LibPamTransaction<C: Conversation> { |
24 /// The handle itself. | 23 /// The handle itself. |
25 handle: ManuallyDrop<RawPamHandle>, | 24 handle: ManuallyDrop<LibPamHandle>, |
26 /// The last return value from the handle. | 25 /// The last return value from the handle. |
27 last_return: Cell<Result<()>>, | 26 last_return: Cell<Result<()>>, |
28 /// If set, the Conversation that this PAM handle owns. | 27 /// If set, the Conversation that this PAM handle owns. |
29 /// | 28 /// |
30 /// We have to hold on to this because the PAM specification doesn't | 29 /// We have to hold on to this because the PAM specification doesn't |
34 /// so you have to keep it in one place. | 33 /// so you have to keep it in one place. |
35 conversation: Box<OwnedConversation<C>>, | 34 conversation: Box<OwnedConversation<C>>, |
36 } | 35 } |
37 | 36 |
38 #[derive(Debug, PartialEq)] | 37 #[derive(Debug, PartialEq)] |
39 pub struct HandleBuilder { | 38 pub struct TransactionBuilder { |
40 service_name: OsString, | 39 service_name: OsString, |
41 username: Option<OsString>, | 40 username: Option<OsString>, |
42 } | 41 } |
43 | 42 |
44 impl HandleBuilder { | 43 impl TransactionBuilder { |
45 /// Updates the service name. | 44 /// Updates the service name. |
46 pub fn service_name(mut self, service_name: OsString) -> Self { | 45 pub fn service_name(mut self, service_name: OsString) -> Self { |
47 self.service_name = service_name; | 46 self.service_name = service_name; |
48 self | 47 self |
49 } | 48 } |
53 pub fn username(mut self, username: OsString) -> Self { | 52 pub fn username(mut self, username: OsString) -> Self { |
54 self.username = Some(username); | 53 self.username = Some(username); |
55 self | 54 self |
56 } | 55 } |
57 /// Builds a PAM handle and starts the transaction. | 56 /// Builds a PAM handle and starts the transaction. |
58 pub fn build(self, conv: impl Conversation) -> Result<OwnedLibPamHandle<impl Conversation>> { | 57 pub fn build(self, conv: impl Conversation) -> Result<LibPamTransaction<impl Conversation>> { |
59 OwnedLibPamHandle::start(self.service_name, self.username, conv) | 58 LibPamTransaction::start(self.service_name, self.username, conv) |
60 } | 59 } |
61 } | 60 } |
62 | 61 |
63 impl<C: Conversation> OwnedLibPamHandle<C> { | 62 impl<C: Conversation> LibPamTransaction<C> { |
64 /// Creates a builder to start a PAM transaction for the given service. | 63 /// Creates a builder to start a PAM transaction for the given service. |
65 /// | 64 /// |
66 /// The service name is what controls the steps and checks PAM goes through | 65 /// The service name is what controls the steps and checks PAM goes through |
67 /// when authenticating a user. This corresponds to the configuration file | 66 /// when authenticating a user. This corresponds to the configuration file |
68 /// named <code>/etc/pam.d/<var>service_name</var></code>. | 67 /// named <code>/etc/pam.d/<var>service_name</var></code>. |
70 /// # References | 69 /// # References |
71 #[doc = linklist!(pam_start: adg, _std)] | 70 #[doc = linklist!(pam_start: adg, _std)] |
72 /// | 71 /// |
73 #[doc = stdlinks!(3 pam_start)] | 72 #[doc = stdlinks!(3 pam_start)] |
74 #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_start")] | 73 #[doc = guide!(adg: "adg-interface-by-app-expected.html#adg-pam_start")] |
75 pub fn build_with_service(service_name: OsString) -> HandleBuilder { | 74 pub fn build_with_service(service_name: OsString) -> TransactionBuilder { |
76 HandleBuilder { | 75 TransactionBuilder { |
77 service_name, | 76 service_name, |
78 username: None, | 77 username: None, |
79 } | 78 } |
80 } | 79 } |
81 | 80 |
99 ) | 98 ) |
100 }; | 99 }; |
101 ErrorCode::result_from(result)?; | 100 ErrorCode::result_from(result)?; |
102 let handle = NonNull::new(handle).ok_or(ErrorCode::BufferError)?; | 101 let handle = NonNull::new(handle).ok_or(ErrorCode::BufferError)?; |
103 Ok(Self { | 102 Ok(Self { |
104 handle: ManuallyDrop::new(RawPamHandle(handle)), | 103 handle: ManuallyDrop::new(LibPamHandle(handle)), |
105 last_return: Cell::new(Ok(())), | 104 last_return: Cell::new(Ok(())), |
106 conversation: conv, | 105 conversation: conv, |
107 }) | 106 }) |
108 } | 107 } |
109 | 108 |
126 ErrorCode::result_from(unsafe { libpam_sys::$pam_func(self.0.as_mut(), flags.bits()) }) | 125 ErrorCode::result_from(unsafe { libpam_sys::$pam_func(self.0.as_mut(), flags.bits()) }) |
127 } | 126 } |
128 }; | 127 }; |
129 } | 128 } |
130 | 129 |
131 impl PamHandleApplication for RawPamHandle { | 130 impl Transaction for LibPamHandle { |
132 wrap!(fn authenticate { pam_authenticate }); | 131 wrap!(fn authenticate { pam_authenticate }); |
133 wrap!(fn account_management { pam_acct_mgmt }); | 132 wrap!(fn account_management { pam_acct_mgmt }); |
134 wrap!(fn change_authtok { pam_chauthtok }); | 133 wrap!(fn change_authtok { pam_chauthtok }); |
135 } | 134 } |
136 | 135 |
142 // pam_close_session - app | 141 // pam_close_session - app |
143 // pam_putenv - shared | 142 // pam_putenv - shared |
144 // pam_getenv - shared | 143 // pam_getenv - shared |
145 // pam_getenvlist - shared | 144 // pam_getenvlist - shared |
146 | 145 |
147 impl<C: Conversation> Drop for OwnedLibPamHandle<C> { | 146 impl<C: Conversation> Drop for LibPamTransaction<C> { |
148 /// Closes the PAM session on an owned PAM handle. | 147 /// Closes the PAM session on an owned PAM handle. |
149 /// | 148 /// |
150 /// This internally calls `pam_end` with the appropriate error code. | 149 /// This internally calls `pam_end` with the appropriate error code. |
151 /// | 150 /// |
152 /// # References | 151 /// # References |
203 | 202 |
204 fn split<T>(result: &Result<T>) -> Result<()> { | 203 fn split<T>(result: &Result<T>) -> Result<()> { |
205 result.as_ref().map(drop).map_err(|&e| e) | 204 result.as_ref().map(drop).map_err(|&e| e) |
206 } | 205 } |
207 | 206 |
208 impl<C: Conversation> PamShared for OwnedLibPamHandle<C> { | 207 impl<C: Conversation> PamShared for LibPamTransaction<C> { |
209 delegate!(fn log(&self, level: Level, location: Location<'_>, entry: &str) -> ()); | 208 delegate!(fn log(&self, level: Level, location: Location<'_>, entry: &str) -> ()); |
210 delegate!(fn environ(&self) -> impl EnvironMap); | 209 delegate!(fn environ(&self) -> impl EnvironMap); |
211 delegate!(fn environ_mut(&mut self) -> impl EnvironMapMut); | 210 delegate!(fn environ_mut(&mut self) -> impl EnvironMapMut); |
212 delegate!(fn username(&mut self, prompt: Option<&OsStr>) -> Result<OsString>); | 211 delegate!(fn username(&mut self, prompt: Option<&OsStr>) -> Result<OsString>); |
213 delegate!(get = user_item, set = set_user_item); | 212 delegate!(get = user_item, set = set_user_item); |
235 } | 234 } |
236 | 235 |
237 /// An owned variation of a basic PAM handle. | 236 /// An owned variation of a basic PAM handle. |
238 /// | 237 /// |
239 /// This is the most basic version of a wrapped PAM handle. It's mostly used | 238 /// This is the most basic version of a wrapped PAM handle. It's mostly used |
240 /// as the inside of the [`OwnedLibPamHandle`], but can also be used to "adopt" | 239 /// as the inside of the [`LibPamTransaction`], but can also be used to "adopt" |
241 /// a PAM handle created by another library. | 240 /// a PAM handle created by another library. |
242 /// | 241 /// |
243 /// If [`Self::end`] is not called, this will always call `pam_end` reporting | 242 /// If [`Self::end`] is not called, this will always call `pam_end` reporting |
244 /// successful completion. | 243 /// successful completion. |
245 pub struct RawPamHandle(NonNull<libpam_sys::pam_handle>); | 244 #[repr(transparent)] |
246 | 245 pub struct LibPamHandle(NonNull<libpam_sys::pam_handle>); |
247 impl RawPamHandle { | 246 |
247 impl LibPamHandle { | |
248 /// Takes ownership of the pointer to the given PAM handle. | 248 /// Takes ownership of the pointer to the given PAM handle. |
249 /// | 249 /// |
250 /// **Do not use this just to get a reference to a PAM handle.** | 250 /// **Do not use this just to get a reference to a PAM handle.** |
251 /// | 251 /// |
252 /// # Safety | 252 /// # Safety |
315 pub fn raw_mut(&mut self) -> &mut libpam_sys::pam_handle { | 315 pub fn raw_mut(&mut self) -> &mut libpam_sys::pam_handle { |
316 unsafe { self.0.as_mut() } | 316 unsafe { self.0.as_mut() } |
317 } | 317 } |
318 } | 318 } |
319 | 319 |
320 impl Drop for RawPamHandle { | 320 impl Drop for LibPamHandle { |
321 fn drop(&mut self) { | 321 fn drop(&mut self) { |
322 unsafe { libpam_sys::pam_end(self.0.as_mut(), 0) }; | 322 unsafe { libpam_sys::pam_end(self.0.as_mut(), 0) }; |
323 } | 323 } |
324 } | 324 } |
325 | 325 |
326 impl PamShared for RawPamHandle { | 326 impl PamShared for LibPamHandle { |
327 #[cfg(any())] | 327 #[cfg(any())] |
328 fn log(&self, level: Level, loc: Location<'_>, entry: &str) { | 328 fn log(&self, level: Level, loc: Location<'_>, entry: &str) { |
329 let entry = match CString::new(entry).or_else(|_| CString::new(dbg!(entry))) { | 329 let entry = match CString::new(entry).or_else(|_| CString::new(dbg!(entry))) { |
330 Ok(cstr) => cstr, | 330 Ok(cstr) => cstr, |
331 _ => return, | 331 _ => return, |
391 cstr_item!(set = set_remote_host, item = ItemType::RemoteHost); | 391 cstr_item!(set = set_remote_host, item = ItemType::RemoteHost); |
392 cstr_item!(set = set_authtok_item, item = ItemType::AuthTok); | 392 cstr_item!(set = set_authtok_item, item = ItemType::AuthTok); |
393 cstr_item!(set = set_old_authtok_item, item = ItemType::OldAuthTok); | 393 cstr_item!(set = set_old_authtok_item, item = ItemType::OldAuthTok); |
394 } | 394 } |
395 | 395 |
396 impl Conversation for RawPamHandle { | 396 impl Conversation for LibPamHandle { |
397 fn communicate(&self, messages: &[Exchange]) { | 397 fn communicate(&self, messages: &[Exchange]) { |
398 match self.conversation_item() { | 398 match self.conversation_item() { |
399 Ok(conv) => conv.communicate(messages), | 399 Ok(conv) => conv.communicate(messages), |
400 Err(e) => { | 400 Err(e) => { |
401 for msg in messages { | 401 for msg in messages { |
404 } | 404 } |
405 } | 405 } |
406 } | 406 } |
407 } | 407 } |
408 | 408 |
409 impl PamHandleModule for RawPamHandle { | 409 impl PamHandleModule for LibPamHandle { |
410 fn authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString> { | 410 fn authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString> { |
411 self.get_authtok(prompt, ItemType::AuthTok) | 411 self.get_authtok(prompt, ItemType::AuthTok) |
412 } | 412 } |
413 | 413 |
414 fn old_authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString> { | 414 fn old_authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString> { |
428 let _data: Box<T> = Box::from_raw(c_data.cast()); | 428 let _data: Box<T> = Box::from_raw(c_data.cast()); |
429 } | 429 } |
430 } | 430 } |
431 | 431 |
432 // Implementations of internal functions. | 432 // Implementations of internal functions. |
433 impl RawPamHandle { | 433 impl LibPamHandle { |
434 #[cfg(any(pam_impl = "LinuxPam", pam_impl = "OpenPam"))] | 434 #[cfg(any(pam_impl = "LinuxPam", pam_impl = "OpenPam"))] |
435 fn get_authtok(&mut self, prompt: Option<&OsStr>, item_type: ItemType) -> Result<OsString> { | 435 fn get_authtok(&mut self, prompt: Option<&OsStr>, item_type: ItemType) -> Result<OsString> { |
436 let prompt = memory::option_cstr_os(prompt); | 436 let prompt = memory::option_cstr_os(prompt); |
437 let mut output: *const c_char = ptr::null_mut(); | 437 let mut output: *const c_char = ptr::null_mut(); |
438 // SAFETY: We're calling this with known-good values. | 438 // SAFETY: We're calling this with known-good values. |