comparison src/libpam/conversation.rs @ 80:5aa1a010f1e8

Start using PAM headers; improve owned/borrowed distinction. - Uses bindgen to generate bindings (only if needed). - Gets the story together on owned vs. borrowed handles. - Reduces number of mutable borrows in handle operation (since `PamHandle` is neither `Send` nor `Sync`, we never have to worry about thread safety. - Improves a bunch of macros so we don't have our own special syntax for docs. - Implement question indirection for standard XSSO PAM implementations.
author Paul Fisher <paul@pfish.zone>
date Tue, 10 Jun 2025 01:09:30 -0400
parents 002adfb98c5c
children 05291b601f0a
comparison
equal deleted inserted replaced
79:2128123b9406 80:5aa1a010f1e8
1 use crate::conv::{ 1 use crate::conv::{
2 BinaryQAndA, Conversation, ErrorMsg, InfoMsg, MaskedQAndA, Message, QAndA, RadioQAndA, 2 BinaryQAndA, Conversation, ErrorMsg, InfoMsg, MaskedQAndA, Message, QAndA, RadioQAndA,
3 }; 3 };
4 use crate::libpam::answer::{Answer, Answers, BinaryAnswer, TextAnswer}; 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::question::{Indirect, Questions}; 6 use crate::libpam::pam_ffi::AppData;
7 pub use crate::libpam::pam_ffi::LibPamConversation;
8 use crate::libpam::question::{Indirect, IndirectTrait, Question, Questions};
7 use crate::ErrorCode; 9 use crate::ErrorCode;
8 use crate::Result; 10 use crate::Result;
9 use std::ffi::c_int; 11 use std::ffi::c_int;
10 use std::iter; 12 use std::iter;
11 use std::marker::PhantomData; 13 use std::marker::PhantomData;
12
13 /// An opaque structure that is passed through PAM in a conversation.
14 #[repr(C)]
15 pub struct AppData {
16 _data: (),
17 _marker: Immovable,
18 }
19
20 /// The callback that PAM uses to get information in a conversation.
21 ///
22 /// - `num_msg` is the number of messages in the `pam_message` array.
23 /// - `messages` is a pointer to the messages being sent to the user.
24 /// For details about its structure, see the documentation of
25 /// [`OwnedMessages`](super::OwnedMessages).
26 /// - `responses` is a pointer to an array of [`Answer`]s,
27 /// which PAM sets in response to a module's request.
28 /// This is an array of structs, not an array of pointers to a struct.
29 /// There should always be exactly as many `responses` as `num_msg`.
30 /// - `appdata` is the `appdata` field of the [`LibPamConversation`] we were passed.
31 pub type ConversationCallback = unsafe extern "C" fn(
32 num_msg: c_int,
33 messages: *const Indirect,
34 responses: *mut *mut Answer,
35 appdata: *mut AppData,
36 ) -> c_int;
37
38 /// The type used by PAM to call back into a conversation.
39 #[repr(C)]
40 pub struct LibPamConversation<'a> {
41 /// The function that is called to get information from the user.
42 callback: ConversationCallback,
43 /// The pointer that will be passed as the last parameter
44 /// to the conversation callback.
45 appdata: *mut AppData,
46 life: PhantomData<&'a mut ()>,
47 _marker: Immovable,
48 }
49 14
50 impl LibPamConversation<'_> { 15 impl LibPamConversation<'_> {
51 fn wrap<C: Conversation>(conv: &mut C) -> Self { 16 fn wrap<C: Conversation>(conv: &mut C) -> Self {
52 Self { 17 Self {
53 callback: Self::wrapper_callback::<C>, 18 callback: Self::wrapper_callback::<C>,
57 } 22 }
58 } 23 }
59 24
60 unsafe extern "C" fn wrapper_callback<C: Conversation>( 25 unsafe extern "C" fn wrapper_callback<C: Conversation>(
61 count: c_int, 26 count: c_int,
62 questions: *const Indirect, 27 questions: *const *const Question,
63 answers: *mut *mut Answer, 28 answers: *mut *mut Answer,
64 me: *mut AppData, 29 me: *mut AppData,
65 ) -> c_int { 30 ) -> c_int {
66 let internal = || { 31 let internal = || {
67 // Collect all our pointers 32 // Collect all our pointers
68 let conv = me 33 let conv = me
69 .cast::<C>() 34 .cast::<C>()
70 .as_mut() 35 .as_mut()
71 .ok_or(ErrorCode::ConversationError)?; 36 .ok_or(ErrorCode::ConversationError)?;
72 let indirect = questions.as_ref().ok_or(ErrorCode::ConversationError)?; 37 let indirect = Indirect::borrow_ptr(questions).ok_or(ErrorCode::ConversationError)?;
73 let answers_ptr = answers.as_mut().ok_or(ErrorCode::ConversationError)?; 38 let answers_ptr = answers.as_mut().ok_or(ErrorCode::ConversationError)?;
74 39
75 // Build our owned list of Q&As from the questions we've been asked 40 // Build our owned list of Q&As from the questions we've been asked
76 let messages: Vec<OwnedMessage> = indirect 41 let messages: Vec<OwnedMessage> = indirect
77 .iter(count as usize) 42 .iter(count as usize)