comparison src/conv.rs @ 56:daa2cde64601

Big big refactor. Probably should have been multiple changes. - Makes FFI safer by explicitly specifying c_int in calls. - Uses ToPrimitive/FromPrimitive to make this easier. - Pulls PamFlag variables into a bitflags! struct. - Pulls PamMessageStyle variables into an enum. - Renames ResultCode to ErrorCode. - Switches from PAM_SUCCESS to using a Result<(), ErrorCode>. - Uses thiserror to make ErrorCode into an Error. - Gets rid of pam_try! because now we have Results. - Expands some names (e.g. Conv to Conversation). - Adds more doc comments. - Returns passwords as a SecureString, to avoid unnecessarily keeping it around in memory.
author Paul Fisher <paul@pfish.zone>
date Sun, 04 May 2025 02:56:55 -0400
parents 9d1160b02d2c
children 3f4a77aa88be
comparison
equal deleted inserted replaced
55:676675c3d434 56:daa2cde64601
1 use libc::{c_char, c_int}; 1 use libc::{c_char, c_int};
2 use std::ffi::{CStr, CString}; 2 use std::ffi::{CStr, CString};
3 use std::ptr; 3 use std::ptr;
4 4
5 use crate::constants::PamMessageStyle; 5 use crate::constants::MessageStyle;
6 use crate::constants::PamResultCode; 6 use crate::constants::PamResult;
7 use crate::constants::ErrorCode;
7 use crate::items::Item; 8 use crate::items::Item;
8 use crate::module::PamResult;
9 9
10 #[repr(C)] 10 #[repr(C)]
11 struct PamMessage { 11 struct Message {
12 msg_style: PamMessageStyle, 12 msg_style: MessageStyle,
13 msg: *const c_char, 13 msg: *const c_char,
14 } 14 }
15 15
16 #[repr(C)] 16 #[repr(C)]
17 struct PamResponse { 17 struct Response {
18 resp: *const c_char, 18 resp: *const c_char,
19 resp_retcode: libc::c_int, // Unused - always zero 19 resp_retcode: libc::c_int, // Unused - always zero
20 } 20 }
21 21
22 #[repr(C)] 22 #[repr(C)]
23 pub struct Inner { 23 pub struct Inner {
24 conv: extern "C" fn( 24 conv: extern "C" fn(
25 num_msg: c_int, 25 num_msg: c_int,
26 pam_message: &&PamMessage, 26 pam_message: &&Message,
27 pam_response: &mut *const PamResponse, 27 pam_response: &mut *const Response,
28 appdata_ptr: *const libc::c_void, 28 appdata_ptr: *const libc::c_void,
29 ) -> PamResultCode, 29 ) -> c_int,
30 appdata_ptr: *const libc::c_void, 30 appdata_ptr: *const libc::c_void,
31 } 31 }
32 32
33 /// A `Conv`ersation channel with the user. 33 /// A `Conv`ersation channel with the user.
34 /// 34 ///
51 /// - PAM_BINARY_PROMPT 51 /// - PAM_BINARY_PROMPT
52 /// 52 ///
53 /// Note that the user experience will depend on how the client implements 53 /// Note that the user experience will depend on how the client implements
54 /// these message styles - and not all applications implement all message 54 /// these message styles - and not all applications implement all message
55 /// styles. 55 /// styles.
56 pub fn send(&self, style: PamMessageStyle, msg: &str) -> PamResult<Option<&CStr>> { 56 pub fn send(&self, style: MessageStyle, msg: &str) -> PamResult<Option<&CStr>> {
57 let mut resp_ptr: *const PamResponse = ptr::null(); 57 let mut resp_ptr: *const Response = ptr::null();
58 let msg_cstr = CString::new(msg).unwrap(); 58 let msg_cstr = CString::new(msg).unwrap();
59 let msg = PamMessage { 59 let msg = Message {
60 msg_style: style, 60 msg_style: style,
61 msg: msg_cstr.as_ptr(), 61 msg: msg_cstr.as_ptr(),
62 }; 62 };
63 let ret = (self.0.conv)(1, &&msg, &mut resp_ptr, self.0.appdata_ptr);
64 ErrorCode::result_from(ret)?;
63 65
64 let ret = (self.0.conv)(1, &&msg, &mut resp_ptr, self.0.appdata_ptr); 66 let result = unsafe {
65 67 match (*resp_ptr).resp {
66 if PamResultCode::PAM_SUCCESS == ret { 68 p if p.is_null() => None,
67 // PamResponse.resp is null for styles that don't return user input like PAM_TEXT_INFO 69 p => Some(CStr::from_ptr(p)),
68 let response = unsafe { (*resp_ptr).resp };
69 if response.is_null() {
70 Ok(None)
71 } else {
72 Ok(Some(unsafe { CStr::from_ptr(response) }))
73 } 70 }
74 } else { 71 };
75 Err(ret) 72 Ok(result)
76 }
77 } 73 }
78 } 74 }
79 75
80 impl Item for Conv<'_> { 76 impl Item for Conv<'_> {
81 type Raw = Inner; 77 type Raw = Inner;
82 78
83 fn type_id() -> crate::items::ItemType { 79 fn type_id() -> crate::items::ItemType {
84 crate::items::ItemType::Conv 80 crate::items::ItemType::Conversation
85 } 81 }
86 82
87 unsafe fn from_raw(raw: *const Self::Raw) -> Self { 83 unsafe fn from_raw(raw: *const Self::Raw) -> Self {
88 Self(&*raw) 84 Self(&*raw)
89 } 85 }