Mercurial > crates > nonstick
diff src/libpam/conversation.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 | 94b51fa4f797 |
children | efbc235f01d3 |
line wrap: on
line diff
--- a/src/libpam/conversation.rs Mon Jun 30 23:49:54 2025 -0400 +++ b/src/libpam/conversation.rs Tue Jul 01 06:11:43 2025 -0400 @@ -1,25 +1,35 @@ use crate::conv::{BinaryQAndA, RadioQAndA}; -use crate::conv::{Conversation, ErrorMsg, InfoMsg, MaskedQAndA, Message, QAndA}; +use crate::conv::{Conversation, ErrorMsg, Exchange, InfoMsg, MaskedQAndA, QAndA}; use crate::libpam::answer::BinaryAnswer; use crate::libpam::answer::{Answer, Answers, TextAnswer}; use crate::libpam::memory::CBinaryData; -use crate::libpam::pam_ffi::AppData; -pub use crate::libpam::pam_ffi::LibPamConversation; -use crate::libpam::question::QuestionsTrait; -use crate::libpam::question::{Question, Questions}; +use crate::libpam::question::Question; use crate::ErrorCode; use crate::Result; +use libpam_sys::helpers::PtrPtrVec; +use libpam_sys::AppData; use std::ffi::c_int; use std::iter; use std::marker::PhantomData; use std::ptr::NonNull; use std::result::Result as StdResult; +/// The type used by PAM to call back into a conversation. +#[repr(C)] +pub struct LibPamConversation<'a> { + pam_conv: libpam_sys::pam_conv, + /// Marker to associate the lifetime of this with the conversation + /// that was passed in. + pub life: PhantomData<&'a mut ()>, +} + impl LibPamConversation<'_> { pub fn wrap<C: Conversation>(conv: &C) -> Self { Self { - callback: Self::wrapper_callback::<C>, - appdata: (conv as *const C).cast(), + pam_conv: libpam_sys::pam_conv { + conv: Self::wrapper_callback::<C>, + appdata_ptr: (conv as *const C).cast_mut().cast(), + }, life: PhantomData, } } @@ -29,9 +39,9 @@ /// PAM calls this, we compute answers, then send them back. unsafe extern "C" fn wrapper_callback<C: Conversation>( count: c_int, - questions: *const *const Question, - answers: *mut *mut Answer, - me: *const AppData, + questions: *const *const libpam_sys::pam_message, + answers: *mut *mut libpam_sys::pam_response, + me: *mut AppData, ) -> c_int { let internal = || { // Collect all our pointers @@ -39,23 +49,23 @@ .cast::<C>() .as_ref() .ok_or(ErrorCode::ConversationError)?; - let indirect = Questions::borrow_ptr(questions, count as usize); + let q_iter = PtrPtrVec::<Question>::iter_over(questions, count as usize); let answers_ptr = answers.as_mut().ok_or(ErrorCode::ConversationError)?; // Build our owned list of Q&As from the questions we've been asked - let messages: Vec<OwnedMessage> = indirect + let messages: Vec<OwnedExchange> = q_iter .map(TryInto::try_into) .collect::<Result<_>>() .map_err(|_| ErrorCode::ConversationError)?; // Borrow all those Q&As and ask them. // If we got an invalid message type, bail before sending. - let borrowed: Result<Vec<_>> = messages.iter().map(Message::try_from).collect(); + let borrowed: Result<Vec<_>> = messages.iter().map(Exchange::try_from).collect(); // TODO: Do we want to log something here? conv.communicate(&borrowed?); // Send our answers back. let owned = Answers::build(messages)?; - *answers_ptr = owned.into_ptr().as_ptr(); + *answers_ptr = owned.into_ptr(); Ok(()) }; ErrorCode::result_to_c(internal()) @@ -63,17 +73,18 @@ } impl Conversation for LibPamConversation<'_> { - fn communicate(&self, messages: &[Message]) { + fn communicate(&self, messages: &[Exchange]) { let internal = || { - let questions = Box::pin(Questions::new(messages)?); + let questions: Result<_> = messages.iter().map(Question::try_from).collect(); + let questions = PtrPtrVec::new(questions?); let mut response_pointer = std::ptr::null_mut(); // SAFETY: We're calling into PAM with valid everything. let result = unsafe { - (self.callback)( + (self.pam_conv.conv)( messages.len() as c_int, - questions.as_ref().ptr(), + questions.as_ptr(), &mut response_pointer, - self.appdata, + self.pam_conv.appdata_ptr, ) }; ErrorCode::result_from(result)?; @@ -96,9 +107,9 @@ } } -/// Like [`Message`], but this time we own the contents. +/// Like [`Exchange`], but this time we own the contents. #[derive(Debug)] -pub enum OwnedMessage<'a> { +pub enum OwnedExchange<'a> { MaskedPrompt(MaskedQAndA<'a>), Prompt(QAndA<'a>), Info(InfoMsg<'a>), @@ -107,16 +118,16 @@ BinaryPrompt(BinaryQAndA<'a>), } -impl<'a> TryFrom<&'a OwnedMessage<'a>> for Message<'a> { +impl<'a> TryFrom<&'a OwnedExchange<'a>> for Exchange<'a> { type Error = ErrorCode; - fn try_from(src: &'a OwnedMessage) -> StdResult<Self, ErrorCode> { + fn try_from(src: &'a OwnedExchange) -> StdResult<Self, ErrorCode> { match src { - OwnedMessage::MaskedPrompt(m) => Ok(Message::MaskedPrompt(m)), - OwnedMessage::Prompt(m) => Ok(Message::Prompt(m)), - OwnedMessage::Info(m) => Ok(Message::Info(m)), - OwnedMessage::Error(m) => Ok(Message::Error(m)), - OwnedMessage::RadioPrompt(m) => Ok(Message::RadioPrompt(m)), - OwnedMessage::BinaryPrompt(m) => Ok(Message::BinaryPrompt(m)), + OwnedExchange::MaskedPrompt(m) => Ok(Exchange::MaskedPrompt(m)), + OwnedExchange::Prompt(m) => Ok(Exchange::Prompt(m)), + OwnedExchange::Info(m) => Ok(Exchange::Info(m)), + OwnedExchange::Error(m) => Ok(Exchange::Error(m)), + OwnedExchange::RadioPrompt(m) => Ok(Exchange::RadioPrompt(m)), + OwnedExchange::BinaryPrompt(m) => Ok(Exchange::BinaryPrompt(m)), } } } @@ -126,7 +137,7 @@ /// # Safety /// /// You are responsible for ensuring that the src-dst pair matches. -unsafe fn convert(msg: &Message, resp: &mut Answer) { +unsafe fn convert(msg: &Exchange, resp: &mut Answer) { macro_rules! fill_text { ($dst:ident, $src:ident) => {{ let text_resp = unsafe { TextAnswer::upcast($src) }; @@ -134,12 +145,12 @@ }}; } match *msg { - Message::MaskedPrompt(qa) => fill_text!(qa, resp), - Message::Prompt(qa) => fill_text!(qa, resp), - Message::Error(m) => m.set_answer(Ok(())), - Message::Info(m) => m.set_answer(Ok(())), - Message::RadioPrompt(qa) => fill_text!(qa, resp), - Message::BinaryPrompt(qa) => { + Exchange::MaskedPrompt(qa) => fill_text!(qa, resp), + Exchange::Prompt(qa) => fill_text!(qa, resp), + Exchange::Error(m) => m.set_answer(Ok(())), + Exchange::Info(m) => m.set_answer(Ok(())), + Exchange::RadioPrompt(qa) => fill_text!(qa, resp), + Exchange::BinaryPrompt(qa) => { let bin_resp = unsafe { BinaryAnswer::upcast(resp) }; qa.set_answer(Ok(bin_resp .data()