Mercurial > crates > nonstick
diff src/libpam/answer.rs @ 130:80c07e5ab22f
Transfer over (almost) completely to using libpam-sys.
This reimplements everything in nonstick on top of the new -sys crate.
We don't yet use libpam-sys's helpers for binary message payloads. Soon.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Tue, 01 Jul 2025 06:11:43 -0400 |
parents | e97534be35e3 |
children |
line wrap: on
line diff
--- a/src/libpam/answer.rs Mon Jun 30 23:49:54 2025 -0400 +++ b/src/libpam/answer.rs Tue Jul 01 06:11:43 2025 -0400 @@ -1,11 +1,10 @@ //! Types used to communicate data from the application to the module. -use crate::libpam::conversation::OwnedMessage; +use crate::libpam::conversation::OwnedExchange; use crate::libpam::memory; -use crate::libpam::memory::{CBinaryData, CHeapBox, CHeapString}; -pub use crate::libpam::pam_ffi::Answer; +use crate::libpam::memory::{CBinaryData, CHeapBox, CHeapString, Immovable}; use crate::{ErrorCode, Result}; -use std::ffi::CStr; +use std::ffi::{c_int, c_void, CStr}; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; @@ -22,7 +21,7 @@ impl Answers { /// Builds an Answers out of the given answered Message Q&As. - pub fn build(value: Vec<OwnedMessage>) -> Result<Self> { + pub fn build(value: Vec<OwnedExchange>) -> Result<Self> { let mut outputs = Self { base: memory::calloc(value.len())?, count: value.len(), @@ -31,14 +30,16 @@ // all allocated answer memory. for (input, output) in iter::zip(value, outputs.iter_mut()) { match input { - OwnedMessage::MaskedPrompt(p) => TextAnswer::fill(output, p.answer()?.as_ref())?, - OwnedMessage::Prompt(p) => TextAnswer::fill(output, &(p.answer()?))?, - OwnedMessage::Error(p) => TextAnswer::fill(output, p.answer().map(|_| "")?)?, - OwnedMessage::Info(p) => TextAnswer::fill(output, p.answer().map(|_| "")?)?, + OwnedExchange::MaskedPrompt(p) => TextAnswer::fill(output, p.answer()?.as_ref())?, + OwnedExchange::Prompt(p) => TextAnswer::fill(output, &(p.answer()?))?, + OwnedExchange::Error(p) => TextAnswer::fill(output, p.answer().map(|_| "")?)?, + OwnedExchange::Info(p) => TextAnswer::fill(output, p.answer().map(|_| "")?)?, // If we're here, that means that we *got* a Linux-PAM // question from PAM, so we're OK to answer it. - OwnedMessage::RadioPrompt(p) => TextAnswer::fill(output, &(p.answer()?))?, - OwnedMessage::BinaryPrompt(p) => BinaryAnswer::fill(output, (&p.answer()?).into())?, + OwnedExchange::RadioPrompt(p) => TextAnswer::fill(output, &(p.answer()?))?, + OwnedExchange::BinaryPrompt(p) => { + BinaryAnswer::fill(output, (&p.answer()?).into())? + } } } Ok(outputs) @@ -48,8 +49,8 @@ /// /// This object is consumed and the `Answer` pointer now owns its data. /// It can be recreated with [`Self::from_c_heap`]. - pub fn into_ptr(self) -> NonNull<Answer> { - ManuallyDrop::new(self).base + pub fn into_ptr(self) -> *mut libpam_sys::pam_response { + ManuallyDrop::new(self).base.as_ptr().cast() } /// Takes ownership of a list of answers allocated on the C heap. @@ -58,8 +59,11 @@ /// /// It's up to you to make sure you pass a valid pointer, /// like one that you got from PAM, or maybe [`Self::into_ptr`]. - pub unsafe fn from_c_heap(base: NonNull<Answer>, count: usize) -> Self { - Answers { base, count } + pub unsafe fn from_c_heap(base: NonNull<libpam_sys::pam_response>, count: usize) -> Self { + Answers { + base: NonNull::new_unchecked(base.as_ptr().cast()), + count, + } } } @@ -91,6 +95,25 @@ } } +/// Generic version of answer data. +/// +/// This has the same structure as [`BinaryAnswer`](crate::libpam::answer::BinaryAnswer) +/// and [`TextAnswer`](crate::libpam::answer::TextAnswer). +#[repr(C)] +#[derive(Debug, Default)] +pub struct Answer { + /// Owned pointer to the data returned in an answer. + /// For most answers, this will be a + /// [`CHeapString`](crate::libpam::memory::CHeapString), + /// but for [`BinaryQAndA`](crate::conv::BinaryQAndA)s + /// (a Linux-PAM extension), this will be a [`CHeapBox`] of + /// [`CBinaryData`](crate::libpam::memory::CBinaryData). + pub data: Option<CHeapBox<c_void>>, + /// Unused. Just here for the padding. + return_code: c_int, + _marker: Immovable, +} + #[repr(transparent)] #[derive(Debug)] pub struct TextAnswer(Answer); @@ -223,19 +246,19 @@ assert_eq!("", up.contents().unwrap()); } - fn round_trip(msgs: Vec<OwnedMessage>) -> Answers { + fn round_trip(msgs: Vec<OwnedExchange>) -> Answers { let n = msgs.len(); let sent = Answers::build(msgs).unwrap(); - unsafe { Answers::from_c_heap(sent.into_ptr(), n) } + unsafe { Answers::from_c_heap(NonNull::new_unchecked(sent.into_ptr()), n) } } #[test] fn test_round_trip() { let mut answers = round_trip(vec![ - answered!(QAndA, OwnedMessage::Prompt, "whats going on".to_owned()), - answered!(MaskedQAndA, OwnedMessage::MaskedPrompt, "well then".into()), - answered!(ErrorMsg, OwnedMessage::Error, ()), - answered!(InfoMsg, OwnedMessage::Info, ()), + answered!(QAndA, OwnedExchange::Prompt, "whats going on".to_owned()), + answered!(MaskedQAndA, OwnedExchange::MaskedPrompt, "well then".into()), + answered!(ErrorMsg, OwnedExchange::Error, ()), + answered!(InfoMsg, OwnedExchange::Info, ()), ]); if let [going, well, err, info] = &mut answers[..] { @@ -254,13 +277,13 @@ let binary_msg = { let qa = BinaryQAndA::new((&[][..], 0)); qa.set_answer(Ok(BinaryData::new(vec![1, 2, 3], 99))); - OwnedMessage::BinaryPrompt(qa) + OwnedExchange::BinaryPrompt(qa) }; let mut answers = round_trip(vec![ binary_msg, answered!( RadioQAndA, - OwnedMessage::RadioPrompt, + OwnedExchange::RadioPrompt, "beep boop".to_owned() ), ]);