diff src/conv.rs @ 71:58f9d2a4df38

Reorganize everything again??? - Splits ffi/memory stuff into a bunch of stuff in the pam_ffi module. - Builds infrastructure for passing Messages and Responses. - Adds tests for some things at least.
author Paul Fisher <paul@pfish.zone>
date Tue, 03 Jun 2025 21:54:58 -0400
parents 9f8381a1c09c
children 47eb242a4f88
line wrap: on
line diff
--- a/src/conv.rs	Tue Jun 03 01:21:59 2025 -0400
+++ b/src/conv.rs	Tue Jun 03 21:54:58 2025 -0400
@@ -3,13 +3,9 @@
 // Temporarily allowed until we get the actual conversation functions hooked up.
 #![allow(dead_code)]
 
-use crate::constants::{NulError, Result, TooBigError};
-use crate::pam_ffi::{BinaryResponseInner, GenericResponse, TextResponseInner};
+use crate::constants::Result;
+use crate::pam_ffi::Message;
 use secure_string::SecureString;
-use std::mem;
-use std::result::Result as StdResult;
-use std::str::Utf8Error;
-
 // TODO: In most cases, we should be passing around references to strings
 // or binary data. Right now we don't because that turns type inference and
 // trait definitions/implementations into a HUGE MESS.
@@ -18,47 +14,6 @@
 // associated types in the various Conversation traits to avoid copying
 // when unnecessary.
 
-/// The types of message and request that can be sent to a user.
-///
-/// The data within each enum value is the prompt (or other information)
-/// that will be presented to the user.
-#[derive(Debug)]
-pub enum Message<'a> {
-    /// Requests information from the user; will be masked when typing.
-    ///
-    /// Response: [`Response::MaskedText`]
-    MaskedPrompt(&'a str),
-    /// Requests information from the user; will not be masked.
-    ///
-    /// Response: [`Response::Text`]
-    Prompt(&'a str),
-    /// "Yes/No/Maybe conditionals" (a Linux-PAM extension).
-    ///
-    /// Response: [`Response::Text`]
-    /// (Linux-PAM documentation doesn't define its contents.)
-    RadioPrompt(&'a str),
-    /// Raises an error message to the user.
-    ///
-    /// Response: [`Response::NoResponse`]
-    Error(&'a str),
-    /// Sends an informational message to the user.
-    ///
-    /// Response: [`Response::NoResponse`]
-    Info(&'a str),
-    /// Requests binary data from the client (a Linux-PAM extension).
-    ///
-    /// This is used for non-human or non-keyboard prompts (security key?).
-    /// NOT part of the X/Open PAM specification.
-    ///
-    /// Response: [`Response::Binary`]
-    BinaryPrompt {
-        /// Some binary data.
-        data: &'a [u8],
-        /// A "type" that you can use for signalling. Has no strict definition in PAM.
-        data_type: u8,
-    },
-}
-
 /// The responses that PAM will return from a request.
 #[derive(Debug, PartialEq, derive_more::From)]
 pub enum Response {
@@ -103,9 +58,6 @@
     ///
     /// The returned Vec of messages always contains exactly as many entries
     /// as there were messages in the request; one corresponding to each.
-    ///
-    /// Messages with no response (e.g. [info](Message::Info) and
-    /// [error](Message::Error)) will have a `None` entry instead of a `Response`.
     fn send(&mut self, messages: &[Message]) -> Result<Vec<Response>>;
 }
 
@@ -152,84 +104,6 @@
     }
 }
 
-/// An owned text response to a PAM conversation.
-///
-/// It points to a value on the C heap.
-#[repr(C)]
-struct TextResponse(*mut TextResponseInner);
-
-impl TextResponse {
-    /// Allocates a new response with the given text.
-    ///
-    /// A copy of the provided text will be allocated on the C heap.
-    pub fn new(text: impl AsRef<str>) -> StdResult<Self, NulError> {
-        TextResponseInner::alloc(text).map(Self)
-    }
-
-    /// Converts this into a GenericResponse.
-    fn generic(self) -> *mut GenericResponse {
-        let ret = self.0 as *mut GenericResponse;
-        mem::forget(self);
-        ret
-    }
-
-    /// Gets the string data, if possible.
-    pub fn as_str(&self) -> StdResult<&str, Utf8Error> {
-        // SAFETY: We allocated this ourselves or got it back from PAM.
-        unsafe { &*self.0 }.contents().to_str()
-    }
-}
-
-impl Drop for TextResponse {
-    /// Frees an owned response.
-    fn drop(&mut self) {
-        // SAFETY: We allocated this ourselves, or it was provided by PAM.
-        unsafe { TextResponseInner::free(self.0) }
-    }
-}
-
-/// An owned binary response to a PAM conversation.
-///
-/// It points to a value on the C heap.
-#[repr(C)]
-pub struct BinaryResponse(pub(super) *mut BinaryResponseInner);
-
-impl BinaryResponse {
-    /// Creates a binary response with the given data.
-    ///
-    /// A copy of the data will be made and allocated on the C heap.
-    pub fn new(data: &[u8], data_type: u8) -> StdResult<Self, TooBigError> {
-        BinaryResponseInner::alloc(data, data_type).map(Self)
-    }
-
-    /// Converts this into a GenericResponse.
-    fn generic(self) -> *mut GenericResponse {
-        let ret = self.0 as *mut GenericResponse;
-        mem::forget(self);
-        ret
-    }
-
-    /// The data type we point to.
-    pub fn data_type(&self) -> u8 {
-        // SAFETY: We allocated this ourselves or got it back from PAM.
-        unsafe { &*self.0 }.data_type()
-    }
-
-    /// The data we point to.
-    pub fn data(&self) -> &[u8] {
-        // SAFETY: We allocated this ourselves or got it back from PAM.
-        unsafe { &*self.0 }.contents()
-    }
-}
-
-impl Drop for BinaryResponse {
-    /// Frees an owned response.
-    fn drop(&mut self) {
-        // SAFETY: We allocated this ourselves, or it was provided by PAM.
-        unsafe { BinaryResponseInner::free(self.0) }
-    }
-}
-
 /// Owned binary data.
 #[derive(Debug, PartialEq)]
 pub struct BinaryData {
@@ -249,16 +123,6 @@
     }
 }
 
-impl From<BinaryResponse> for BinaryData {
-    /// Copies the data onto the Rust heap.
-    fn from(value: BinaryResponse) -> Self {
-        Self {
-            data: value.data().to_vec(),
-            data_type: value.data_type(),
-        }
-    }
-}
-
 impl From<BinaryData> for Vec<u8> {
     /// Extracts the inner vector from the BinaryData.
     fn from(value: BinaryData) -> Self {
@@ -267,13 +131,9 @@
 }
 
 #[cfg(test)]
-mod test {
-    use super::{
-        BinaryResponse, Conversation, DemuxedConversation, Message, Response, SecureString,
-        TextResponse,
-    };
+mod tests {
+    use super::{Conversation, DemuxedConversation, Message, Response, SecureString};
     use crate::constants::ErrorCode;
-    use crate::pam_ffi::GenericResponse;
 
     #[test]
     fn test_demux() {
@@ -362,33 +222,4 @@
                 .unwrap()
         );
     }
-
-    // The below tests are used in conjunction with ASAN to verify
-    // that we correctly clean up all our memory.
-
-    #[test]
-    fn test_text_response() {
-        let resp = TextResponse::new("it's a-me!").unwrap();
-        assert_eq!("it's a-me!", resp.as_str().unwrap());
-    }
-
-    #[test]
-    fn test_binary_response() {
-        let data = [123, 210, 55];
-        let resp = BinaryResponse::new(&data, 99).unwrap();
-        assert_eq!(data, resp.data());
-        assert_eq!(99, resp.data_type());
-    }
-
-    #[test]
-    fn test_to_generic() {
-        let text = TextResponse::new("oh no").unwrap();
-        let text = text.generic();
-        let binary = BinaryResponse::new(&[], 33).unwrap();
-        let binary = binary.generic();
-        unsafe {
-            GenericResponse::free(text);
-            GenericResponse::free(binary);
-        }
-    }
 }