comparison src/libpam/conversation.rs @ 78:002adfb98c5c

Rename files, reorder structs, remove annoying BorrowedBinaryData type. This is basically a cleanup change. Also it adds tests. - Renames the files with Questions and Answers to question and answer. - Reorders the structs in those files to put the important ones first. - Removes the BorrowedBinaryData type. It was a bad idea all along. Instead, we just use (&[u8], u8). - Adds some tests because I just can't help myself.
author Paul Fisher <paul@pfish.zone>
date Sun, 08 Jun 2025 03:48:40 -0400
parents 351bdc13005e
children 5aa1a010f1e8
comparison
equal deleted inserted replaced
77:351bdc13005e 78:002adfb98c5c
1 use crate::conv::{ 1 use crate::conv::{
2 BinaryQAndA, Conversation, ErrorMsg, InfoMsg, MaskedQAndA, Message, QAndA, 2 BinaryQAndA, Conversation, ErrorMsg, InfoMsg, MaskedQAndA, Message, QAndA, RadioQAndA,
3 RadioQAndA,
4 }; 3 };
4 use crate::libpam::answer::{Answer, Answers, BinaryAnswer, TextAnswer};
5 use crate::libpam::memory::Immovable; 5 use crate::libpam::memory::Immovable;
6 use crate::libpam::message::{Indirect, Questions}; 6 use crate::libpam::question::{Indirect, Questions};
7 use crate::libpam::response::{Answer, Answers, BinaryAnswer, TextAnswer};
8 use crate::ErrorCode; 7 use crate::ErrorCode;
9 use crate::Result; 8 use crate::Result;
10 use std::ffi::c_int; 9 use std::ffi::c_int;
11 use std::iter; 10 use std::iter;
12 use std::marker::PhantomData; 11 use std::marker::PhantomData;
74 let answers_ptr = answers.as_mut().ok_or(ErrorCode::ConversationError)?; 73 let answers_ptr = answers.as_mut().ok_or(ErrorCode::ConversationError)?;
75 74
76 // Build our owned list of Q&As from the questions we've been asked 75 // Build our owned list of Q&As from the questions we've been asked
77 let messages: Vec<OwnedMessage> = indirect 76 let messages: Vec<OwnedMessage> = indirect
78 .iter(count as usize) 77 .iter(count as usize)
79 .map(OwnedMessage::try_from) 78 .map(TryInto::try_into)
80 .collect::<Result<_>>() 79 .collect::<Result<_>>()
81 .map_err(|_| ErrorCode::ConversationError)?; 80 .map_err(|_| ErrorCode::ConversationError)?;
82 // Borrow all those Q&As and ask them 81 // Borrow all those Q&As and ask them
83 let borrowed: Vec<Message> = messages.iter().map(Into::into).collect(); 82 let borrowed: Vec<Message> = messages.iter().map(Into::into).collect();
84 conv.communicate(&borrowed); 83 conv.communicate(&borrowed);
93 } 92 }
94 93
95 impl Conversation for LibPamConversation<'_> { 94 impl Conversation for LibPamConversation<'_> {
96 fn communicate(&mut self, messages: &[Message]) { 95 fn communicate(&mut self, messages: &[Message]) {
97 let internal = || { 96 let internal = || {
98 let mut msgs_to_send = Questions::alloc(messages.len()); 97 let questions = Questions::new(messages)?;
99 for (dst, src) in iter::zip(msgs_to_send.iter_mut(), messages.iter()) {
100 dst.fill(src).map_err(|_| ErrorCode::ConversationError)?
101 }
102 let mut response_pointer = std::ptr::null_mut(); 98 let mut response_pointer = std::ptr::null_mut();
103 // SAFETY: We're calling into PAM with valid everything. 99 // SAFETY: We're calling into PAM with valid everything.
104 let result = unsafe { 100 let result = unsafe {
105 (self.callback)( 101 (self.callback)(
106 messages.len() as c_int, 102 messages.len() as c_int,
107 msgs_to_send.indirect(), 103 questions.indirect(),
108 &mut response_pointer, 104 &mut response_pointer,
109 self.appdata, 105 self.appdata,
110 ) 106 )
111 }; 107 };
112 ErrorCode::result_from(result)?; 108 ErrorCode::result_from(result)?;
126 } 122 }
127 } 123 }
128 } 124 }
129 125
130 /// Like [`Message`], but this time we own the contents. 126 /// Like [`Message`], but this time we own the contents.
127 #[derive(Debug)]
131 pub enum OwnedMessage<'a> { 128 pub enum OwnedMessage<'a> {
132 MaskedPrompt(MaskedQAndA<'a>), 129 MaskedPrompt(MaskedQAndA<'a>),
133 Prompt(QAndA<'a>), 130 Prompt(QAndA<'a>),
134 RadioPrompt(RadioQAndA<'a>), 131 RadioPrompt(RadioQAndA<'a>),
135 BinaryPrompt(BinaryQAndA<'a>), 132 BinaryPrompt(BinaryQAndA<'a>),
155 /// # Safety 152 /// # Safety
156 /// 153 ///
157 /// You are responsible for ensuring that the src-dst pair matches. 154 /// You are responsible for ensuring that the src-dst pair matches.
158 unsafe fn convert(msg: &Message, resp: &mut Answer) { 155 unsafe fn convert(msg: &Message, resp: &mut Answer) {
159 macro_rules! fill_text { 156 macro_rules! fill_text {
160 ($dst:ident, $src:ident) => {{let text_resp = unsafe {TextAnswer::upcast($src)}; 157 ($dst:ident, $src:ident) => {{
161 $dst.set_answer(text_resp.contents().map(Into::into));}} 158 let text_resp = unsafe { TextAnswer::upcast($src) };
162 } 159 $dst.set_answer(text_resp.contents().map(Into::into));
160 }};
161 }
163 match *msg { 162 match *msg {
164 Message::MaskedPrompt(qa) => fill_text!(qa, resp), 163 Message::MaskedPrompt(qa) => fill_text!(qa, resp),
165 Message::Prompt(qa) => fill_text!(qa, resp), 164 Message::Prompt(qa) => fill_text!(qa, resp),
166 Message::RadioPrompt(qa) => fill_text!(qa, resp), 165 Message::RadioPrompt(qa) => fill_text!(qa, resp),
167 Message::Error(m) => m.set_answer(Ok(())), 166 Message::Error(m) => m.set_answer(Ok(())),