comparison src/libpam/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 4d7333337569
comparison
equal deleted inserted replaced
145:8f964b701652 146:1bc52025156b
1 use super::conversation::{OwnedConversation, PamConv}; 1 use super::conversation::{OwnedConversation, PamConv};
2 use crate::_doc::{guide, linklist, stdlinks};
2 use crate::constants::{ErrorCode, Result}; 3 use crate::constants::{ErrorCode, Result};
3 use crate::conv::Exchange; 4 use crate::conv::Exchange;
4 use crate::environ::EnvironMapMut; 5 use crate::environ::EnvironMapMut;
5 use crate::handle::PamShared; 6 use crate::handle::PamShared;
7 use crate::items::{Items, ItemsMut};
6 use crate::libpam::environ::{LibPamEnviron, LibPamEnvironMut}; 8 use crate::libpam::environ::{LibPamEnviron, LibPamEnvironMut};
7 use crate::libpam::memory; 9 use crate::libpam::items::{LibPamItems, LibPamItemsMut};
10 use crate::libpam::{items, memory};
8 use crate::logging::{Level, Location}; 11 use crate::logging::{Level, Location};
9 use crate::{ 12 use crate::{Conversation, EnvironMap, Flags, ModuleClient, Transaction};
10 guide, linklist, stdlinks, Conversation, EnvironMap, Flags, PamHandleModule, Transaction,
11 };
12 use libpam_sys_helpers::constants; 13 use libpam_sys_helpers::constants;
13 use num_enum::{IntoPrimitive, TryFromPrimitive}; 14 use num_enum::{IntoPrimitive, TryFromPrimitive};
14 use std::cell::Cell; 15 use std::cell::Cell;
15 use std::ffi::{c_char, c_int, CString, OsStr, OsString}; 16 use std::ffi::{c_char, c_int, CString, OsStr, OsString};
16 use std::mem::ManuallyDrop; 17 use std::mem::ManuallyDrop;
207 impl<C: Conversation> PamShared for LibPamTransaction<C> { 208 impl<C: Conversation> PamShared for LibPamTransaction<C> {
208 delegate!(fn log(&self, level: Level, location: Location<'_>, entry: &str) -> ()); 209 delegate!(fn log(&self, level: Level, location: Location<'_>, entry: &str) -> ());
209 delegate!(fn environ(&self) -> impl EnvironMap); 210 delegate!(fn environ(&self) -> impl EnvironMap);
210 delegate!(fn environ_mut(&mut self) -> impl EnvironMapMut); 211 delegate!(fn environ_mut(&mut self) -> impl EnvironMapMut);
211 delegate!(fn username(&mut self, prompt: Option<&OsStr>) -> Result<OsString>); 212 delegate!(fn username(&mut self, prompt: Option<&OsStr>) -> Result<OsString>);
212 delegate!(get = user_item, set = set_user_item); 213 delegate!(fn items(&self) -> impl Items);
213 delegate!(get = service, set = set_service); 214 delegate!(fn items_mut(&mut self) -> impl ItemsMut);
214 delegate!(get = user_prompt, set = set_user_prompt);
215 delegate!(get = tty_name, set = set_tty_name);
216 delegate!(get = remote_user, set = set_remote_user);
217 delegate!(get = remote_host, set = set_remote_host);
218 delegate!(set = set_authtok_item);
219 delegate!(set = set_old_authtok_item);
220 }
221
222 /// Macro to implement getting/setting a CStr-based item.
223 macro_rules! cstr_item {
224 (get = $getter:ident, item = $item_type:path) => {
225 fn $getter(&self) -> Result<Option<OsString>> {
226 unsafe { self.get_cstr_item($item_type) }
227 }
228 };
229 (set = $setter:ident, item = $item_type:path) => {
230 fn $setter(&mut self, value: Option<&OsStr>) -> Result<()> {
231 unsafe { self.set_cstr_item($item_type, value) }
232 }
233 };
234 } 215 }
235 216
236 /// An owned variation of a basic PAM handle. 217 /// An owned variation of a basic PAM handle.
237 /// 218 ///
238 /// This is the most basic version of a wrapped PAM handle. It's mostly used 219 /// This is the most basic version of a wrapped PAM handle. It's mostly used
375 356
376 fn environ_mut(&mut self) -> impl EnvironMapMut { 357 fn environ_mut(&mut self) -> impl EnvironMapMut {
377 LibPamEnvironMut::new(self) 358 LibPamEnvironMut::new(self)
378 } 359 }
379 360
380 cstr_item!(get = user_item, item = ItemType::User); 361 fn items(&self) -> impl Items {
381 cstr_item!(set = set_user_item, item = ItemType::User); 362 LibPamItems(self)
382 cstr_item!(get = service, item = ItemType::Service); 363 }
383 cstr_item!(set = set_service, item = ItemType::Service); 364
384 cstr_item!(get = user_prompt, item = ItemType::UserPrompt); 365 fn items_mut(&mut self) -> impl ItemsMut {
385 cstr_item!(set = set_user_prompt, item = ItemType::UserPrompt); 366 LibPamItemsMut(self)
386 cstr_item!(get = tty_name, item = ItemType::Tty); 367 }
387 cstr_item!(set = set_tty_name, item = ItemType::Tty);
388 cstr_item!(get = remote_user, item = ItemType::RemoteUser);
389 cstr_item!(set = set_remote_user, item = ItemType::RemoteUser);
390 cstr_item!(get = 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);
393 cstr_item!(set = set_old_authtok_item, item = ItemType::OldAuthTok);
394 } 368 }
395 369
396 impl Conversation for LibPamHandle { 370 impl Conversation for LibPamHandle {
397 fn communicate(&self, messages: &[Exchange]) { 371 fn communicate(&self, messages: &[Exchange]) {
398 match self.conversation_item() { 372 match self.conversation_item() {
404 } 378 }
405 } 379 }
406 } 380 }
407 } 381 }
408 382
409 impl PamHandleModule for LibPamHandle { 383 impl ModuleClient for LibPamHandle {
410 fn authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString> { 384 fn authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString> {
411 self.get_authtok(prompt, ItemType::AuthTok) 385 self.get_authtok(prompt, ItemType::AuthTok)
412 } 386 }
413 387
414 fn old_authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString> { 388 fn old_authtok(&mut self, prompt: Option<&OsStr>) -> Result<OsString> {
415 self.get_authtok(prompt, ItemType::OldAuthTok) 389 self.get_authtok(prompt, ItemType::OldAuthTok)
416 } 390 }
417 391
418 cstr_item!(get = authtok_item, item = ItemType::AuthTok); 392 fn authtok_item(&self) -> Result<Option<OsString>> {
419 cstr_item!(get = old_authtok_item, item = ItemType::OldAuthTok); 393 unsafe { items::get_cstr_item(self, ItemType::AuthTok) }
394 }
395 fn old_authtok_item(&self) -> Result<Option<OsString>> {
396 unsafe { items::get_cstr_item(self, ItemType::OldAuthTok) }
397 }
420 } 398 }
421 399
422 /// Function called at the end of a PAM session that is called to clean up 400 /// Function called at the end of a PAM session that is called to clean up
423 /// a value previously provided to PAM in a `pam_set_data` call. 401 /// a value previously provided to PAM in a `pam_set_data` call.
424 /// 402 ///
450 } 428 }
451 429
452 #[cfg(not(any(pam_impl = "LinuxPam", pam_impl = "OpenPam")))] 430 #[cfg(not(any(pam_impl = "LinuxPam", pam_impl = "OpenPam")))]
453 fn get_authtok(&mut self, prompt: Option<&str>, item_type: ItemType) -> Result<String> { 431 fn get_authtok(&mut self, prompt: Option<&str>, item_type: ItemType) -> Result<String> {
454 Err(ErrorCode::ConversationError) 432 Err(ErrorCode::ConversationError)
455 }
456
457 /// Gets a C string item.
458 ///
459 /// # Safety
460 ///
461 /// You better be requesting an item which is a C string.
462 unsafe fn get_cstr_item(&self, item_type: ItemType) -> Result<Option<OsString>> {
463 let mut output = ptr::null();
464 let ret =
465 unsafe { libpam_sys::pam_get_item(self.raw_ref(), item_type as c_int, &mut output) };
466 ErrorCode::result_from(ret)?;
467 Ok(memory::copy_pam_string(output.cast()))
468 }
469
470 /// Sets a C string item.
471 ///
472 /// # Safety
473 ///
474 /// You better be setting an item which is a C string.
475 unsafe fn set_cstr_item(&mut self, item_type: ItemType, data: Option<&OsStr>) -> Result<()> {
476 let data_str = memory::option_cstr_os(data);
477 let ret = unsafe {
478 libpam_sys::pam_set_item(
479 self.raw_mut(),
480 item_type as c_int,
481 memory::prompt_ptr(data_str.as_deref()).cast(),
482 )
483 };
484 ErrorCode::result_from(ret)
485 } 433 }
486 434
487 /// Gets the `PAM_CONV` item from the handle. 435 /// Gets the `PAM_CONV` item from the handle.
488 fn conversation_item(&self) -> Result<&PamConv> { 436 fn conversation_item(&self) -> Result<&PamConv> {
489 let output: *const PamConv = ptr::null_mut(); 437 let output: *const PamConv = ptr::null_mut();