diff src/libpam/answer.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
line wrap: on
line diff
--- a/src/libpam/answer.rs	Tue Jun 10 02:43:31 2025 -0400
+++ b/src/libpam/answer.rs	Tue Jun 10 04:40:01 2025 -0400
@@ -29,10 +29,12 @@
             match input {
                 OwnedMessage::MaskedPrompt(p) => TextAnswer::fill(output, p.answer()?.unsecure())?,
                 OwnedMessage::Prompt(p) => TextAnswer::fill(output, &(p.answer()?))?,
-                OwnedMessage::BinaryPrompt(p) => BinaryAnswer::fill(output, (&p.answer()?).into())?,
                 OwnedMessage::Error(p) => TextAnswer::fill(output, p.answer().map(|_| "")?)?,
                 OwnedMessage::Info(p) => TextAnswer::fill(output, p.answer().map(|_| "")?)?,
+                // If we're here, that means that we *got* a Linux-PAM
+                // question from PAM, so we're OK to answer it.
                 OwnedMessage::RadioPrompt(p) => TextAnswer::fill(output, &(p.answer()?))?,
+                OwnedMessage::BinaryPrompt(p) => BinaryAnswer::fill(output, (&p.answer()?).into())?,
             }
         }
         Ok(outputs)
@@ -213,66 +215,75 @@
 
 #[cfg(test)]
 mod tests {
-    use super::{Answer, Answers, BinaryAnswer, TextAnswer};
-    use crate::conv::{BinaryQAndA, ErrorMsg, InfoMsg, MaskedQAndA, QAndA, RadioQAndA};
-    use crate::libpam::conversation::OwnedMessage;
-    use crate::libpam::memory;
-    use crate::BinaryData;
+    use super::*;
+    use crate::conv::{ErrorMsg, InfoMsg, MaskedQAndA, QAndA};
+
+    macro_rules! answered {
+        ($typ:ty, $msg:path, $data:expr) => {{
+            let qa = <$typ>::new("");
+            qa.set_answer(Ok($data));
+            $msg(qa)
+        }};
+    }
+
+    fn assert_text_answer(want: &str, answer: &mut Answer) {
+        let up = unsafe { TextAnswer::upcast(answer) };
+        assert_eq!(want, up.contents().unwrap());
+        up.free_contents();
+        assert_eq!("", up.contents().unwrap());
+    }
+
+    fn round_trip(msgs: Vec<OwnedMessage>) -> Answers {
+        let n = msgs.len();
+        let sent = Answers::build(msgs).unwrap();
+        unsafe { Answers::from_c_heap(sent.into_ptr(), n) }
+    }
 
     #[test]
     fn test_round_trip() {
+        let mut answers = round_trip(vec![
+            answered!(QAndA, OwnedMessage::Prompt, "whats going on".to_owned()),
+            answered!(MaskedQAndA, OwnedMessage::MaskedPrompt, "well then".into()),
+            answered!(ErrorMsg, OwnedMessage::Error, ()),
+            answered!(InfoMsg, OwnedMessage::Info, ()),
+        ]);
+
+        if let [going, well, err, info] = &mut answers[..] {
+            assert_text_answer("whats going on", going);
+            assert_text_answer("well then", well);
+            assert_text_answer("", err);
+            assert_text_answer("", info);
+        } else {
+            panic!("received wrong size {len}!", len = answers.len())
+        }
+    }
+
+    #[cfg(feature = "linux-pam-extensions")]
+    fn test_round_trip_linux() {
+        use crate::conv::{BinaryData, BinaryQAndA, RadioQAndA};
         let binary_msg = {
             let qa = BinaryQAndA::new((&[][..], 0));
             qa.set_answer(Ok(BinaryData::new(vec![1, 2, 3], 99)));
             OwnedMessage::BinaryPrompt(qa)
         };
-
-        macro_rules! answered {
-            ($typ:ty, $msg:path, $data:expr) => {{
-                let qa = <$typ>::new("");
-                qa.set_answer(Ok($data));
-                $msg(qa)
-            }};
-        }
-
-        let answers = vec![
+        let mut answers = round_trip(vec![
             binary_msg,
-            answered!(QAndA, OwnedMessage::Prompt, "whats going on".to_owned()),
-            answered!(MaskedQAndA, OwnedMessage::MaskedPrompt, "well then".into()),
-            answered!(ErrorMsg, OwnedMessage::Error, ()),
-            answered!(InfoMsg, OwnedMessage::Info, ()),
             answered!(
                 RadioQAndA,
                 OwnedMessage::RadioPrompt,
                 "beep boop".to_owned()
             ),
-        ];
-        let n = answers.len();
-        let sent = Answers::build(answers).unwrap();
-        let heap_answers = sent.into_ptr();
-        let mut received = unsafe { Answers::from_c_heap(heap_answers, n) };
+        ]);
 
-        let assert_text = |want, raw| {
-            let up = unsafe { TextAnswer::upcast(raw) };
-            assert_eq!(want, up.contents().unwrap());
-            up.free_contents();
-            assert_eq!("", up.contents().unwrap());
-        };
-        let assert_bin = |want, raw| {
-            let up = unsafe { BinaryAnswer::upcast(raw) };
-            assert_eq!(BinaryData::from(want), up.data().into());
+        if let [bin, radio] = &mut answers[..] {
+            let up = unsafe { BinaryAnswer::upcast(bin) };
+            assert_eq!(BinaryData::from((&[1, 2, 3][..], 99)), up.data().into());
             up.zero_contents();
             assert_eq!(BinaryData::default(), up.data().into());
-        };
-        if let [zero, one, two, three, four, five] = &mut received[..] {
-            assert_bin((&[1, 2, 3][..], 99), zero);
-            assert_text("whats going on", one);
-            assert_text("well then", two);
-            assert_text("", three);
-            assert_text("", four);
-            assert_text("beep boop", five);
+
+            assert_text_answer("beep boop", radio);
         } else {
-            panic!("received wrong size {len}!", len = received.len())
+            panic!("received wrong size {len}!", len = answers.len())
         }
     }
 
@@ -292,6 +303,7 @@
 
     #[test]
     fn test_binary_answer() {
+        use crate::conv::BinaryData;
         let answer_ptr: *mut Answer = memory::calloc(1);
         let answer = unsafe { &mut *answer_ptr };
         let real_data = BinaryData::new([1, 2, 3, 4, 5, 6, 7, 8], 9);
@@ -306,7 +318,7 @@
     #[test]
     #[ignore]
     fn test_binary_answer_too_big() {
-        let big_data: Vec<u8> = vec![0xFFu8; 10_000_000_000];
+        let big_data: Vec<u8> = vec![0xFFu8; 0x1_0000_0001];
         let answer_ptr: *mut Answer = memory::calloc(1);
         let answer = unsafe { &mut *answer_ptr };
         BinaryAnswer::fill(answer, (&big_data, 100)).expect_err("this is too big!");