comparison src/libpam/conversation.rs @ 87:05291b601f0a

Well and truly separate the Linux extensions. This separates the Linux extensions on the libpam side, and disables the two enums on the interface side. Users can still call the Linux extensions from non-Linux PAM impls, but they'll get a conversation error back.
author Paul Fisher <paul@pfish.zone>
date Tue, 10 Jun 2025 04:40:01 -0400
parents 5aa1a010f1e8
children
comparison
equal deleted inserted replaced
86:23162cd399aa 87:05291b601f0a
1 use crate::conv::{ 1 use crate::conv::{BinaryQAndA, RadioQAndA};
2 BinaryQAndA, Conversation, ErrorMsg, InfoMsg, MaskedQAndA, Message, QAndA, RadioQAndA, 2 use crate::conv::{Conversation, ErrorMsg, InfoMsg, MaskedQAndA, Message, QAndA};
3 }; 3 use crate::libpam::answer::BinaryAnswer;
4 use crate::libpam::answer::{Answer, Answers, BinaryAnswer, TextAnswer}; 4 use crate::libpam::answer::{Answer, Answers, TextAnswer};
5 use crate::libpam::memory::Immovable; 5 use crate::libpam::memory::Immovable;
6 use crate::libpam::pam_ffi::AppData; 6 use crate::libpam::pam_ffi::AppData;
7 pub use crate::libpam::pam_ffi::LibPamConversation; 7 pub use crate::libpam::pam_ffi::LibPamConversation;
8 use crate::libpam::question::{Indirect, IndirectTrait, Question, Questions}; 8 use crate::libpam::question::{Indirect, IndirectTrait, Question, Questions};
9 use crate::ErrorCode; 9 use crate::ErrorCode;
10 use crate::Result; 10 use crate::Result;
11 use std::ffi::c_int; 11 use std::ffi::c_int;
12 use std::iter; 12 use std::iter;
13 use std::marker::PhantomData; 13 use std::marker::PhantomData;
14 use std::result::Result as StdResult;
14 15
15 impl LibPamConversation<'_> { 16 impl LibPamConversation<'_> {
16 fn wrap<C: Conversation>(conv: &mut C) -> Self { 17 fn wrap<C: Conversation>(conv: &mut C) -> Self {
17 Self { 18 Self {
18 callback: Self::wrapper_callback::<C>, 19 callback: Self::wrapper_callback::<C>,
20 life: PhantomData, 21 life: PhantomData,
21 _marker: Immovable(PhantomData), 22 _marker: Immovable(PhantomData),
22 } 23 }
23 } 24 }
24 25
26 /// Passed as the conversation function into PAM for an owned handle.
27 ///
28 /// PAM calls this, we compute answers, then send them back.
25 unsafe extern "C" fn wrapper_callback<C: Conversation>( 29 unsafe extern "C" fn wrapper_callback<C: Conversation>(
26 count: c_int, 30 count: c_int,
27 questions: *const *const Question, 31 questions: *const *const Question,
28 answers: *mut *mut Answer, 32 answers: *mut *mut Answer,
29 me: *mut AppData, 33 me: *mut AppData,
41 let messages: Vec<OwnedMessage> = indirect 45 let messages: Vec<OwnedMessage> = indirect
42 .iter(count as usize) 46 .iter(count as usize)
43 .map(TryInto::try_into) 47 .map(TryInto::try_into)
44 .collect::<Result<_>>() 48 .collect::<Result<_>>()
45 .map_err(|_| ErrorCode::ConversationError)?; 49 .map_err(|_| ErrorCode::ConversationError)?;
46 // Borrow all those Q&As and ask them 50 // Borrow all those Q&As and ask them.
47 let borrowed: Vec<Message> = messages.iter().map(Into::into).collect(); 51 // If we got an invalid message type, bail before sending.
48 conv.communicate(&borrowed); 52 let borrowed: Result<Vec<_>> = messages.iter().map(Message::try_from).collect();
53 // TODO: Do we want to log something here?
54 conv.communicate(&borrowed?);
49 55
50 // Send our answers back 56 // Send our answers back.
51 let owned = Answers::build(messages).map_err(|_| ErrorCode::ConversationError)?; 57 let owned = Answers::build(messages).map_err(|_| ErrorCode::ConversationError)?;
52 *answers_ptr = owned.into_ptr(); 58 *answers_ptr = owned.into_ptr();
53 Ok(()) 59 Ok(())
54 }; 60 };
55 ErrorCode::result_to_c(internal()) 61 ErrorCode::result_to_c(internal())
91 /// Like [`Message`], but this time we own the contents. 97 /// Like [`Message`], but this time we own the contents.
92 #[derive(Debug)] 98 #[derive(Debug)]
93 pub enum OwnedMessage<'a> { 99 pub enum OwnedMessage<'a> {
94 MaskedPrompt(MaskedQAndA<'a>), 100 MaskedPrompt(MaskedQAndA<'a>),
95 Prompt(QAndA<'a>), 101 Prompt(QAndA<'a>),
102 Info(InfoMsg<'a>),
103 Error(ErrorMsg<'a>),
96 RadioPrompt(RadioQAndA<'a>), 104 RadioPrompt(RadioQAndA<'a>),
97 BinaryPrompt(BinaryQAndA<'a>), 105 BinaryPrompt(BinaryQAndA<'a>),
98 Info(InfoMsg<'a>),
99 Error(ErrorMsg<'a>),
100 } 106 }
101 107
102 impl<'a> From<&'a OwnedMessage<'a>> for Message<'a> { 108 impl<'a> TryFrom<&'a OwnedMessage<'a>> for Message<'a> {
103 fn from(src: &'a OwnedMessage) -> Self { 109 type Error = ErrorCode;
110 fn try_from(src: &'a OwnedMessage) -> StdResult<Self, ErrorCode> {
104 match src { 111 match src {
105 OwnedMessage::MaskedPrompt(m) => Message::MaskedPrompt(m), 112 OwnedMessage::MaskedPrompt(m) => Ok(Message::MaskedPrompt(m)),
106 OwnedMessage::Prompt(m) => Message::Prompt(m), 113 OwnedMessage::Prompt(m) => Ok(Message::Prompt(m)),
107 OwnedMessage::RadioPrompt(m) => Message::RadioPrompt(m), 114 OwnedMessage::Info(m) => Ok(Message::Info(m)),
108 OwnedMessage::BinaryPrompt(m) => Message::BinaryPrompt(m), 115 OwnedMessage::Error(m) => Ok(Message::Error(m)),
109 OwnedMessage::Info(m) => Message::Info(m), 116 OwnedMessage::RadioPrompt(m) => Ok(Message::RadioPrompt(m)),
110 OwnedMessage::Error(m) => Message::Error(m), 117 OwnedMessage::BinaryPrompt(m) => Ok(Message::BinaryPrompt(m)),
111 } 118 }
112 } 119 }
113 } 120 }
114 121
115 /// Fills in the answer of the Message with the given response. 122 /// Fills in the answer of the Message with the given response.
125 }}; 132 }};
126 } 133 }
127 match *msg { 134 match *msg {
128 Message::MaskedPrompt(qa) => fill_text!(qa, resp), 135 Message::MaskedPrompt(qa) => fill_text!(qa, resp),
129 Message::Prompt(qa) => fill_text!(qa, resp), 136 Message::Prompt(qa) => fill_text!(qa, resp),
130 Message::RadioPrompt(qa) => fill_text!(qa, resp),
131 Message::Error(m) => m.set_answer(Ok(())), 137 Message::Error(m) => m.set_answer(Ok(())),
132 Message::Info(m) => m.set_answer(Ok(())), 138 Message::Info(m) => m.set_answer(Ok(())),
139 Message::RadioPrompt(qa) => fill_text!(qa, resp),
133 Message::BinaryPrompt(qa) => { 140 Message::BinaryPrompt(qa) => {
134 let bin_resp = unsafe { BinaryAnswer::upcast(resp) }; 141 let bin_resp = unsafe { BinaryAnswer::upcast(resp) };
135 qa.set_answer(Ok(bin_resp.data().into())); 142 qa.set_answer(Ok(bin_resp.data().into()));
136 bin_resp.zero_contents() 143 bin_resp.zero_contents()
137 } 144 }