Mercurial > crates > nonstick
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 } |