Mercurial > crates > nonstick
comparison src/libpam/question.rs @ 108:e97534be35e3
Make some proc macros for doing cfg-like stuff for PAM impls.
| author | Paul Fisher <paul@pfish.zone> |
|---|---|
| date | Sat, 28 Jun 2025 00:34:45 -0400 |
| parents | 49d9e2b5c189 |
| children | 178310336596 |
comparison
equal
deleted
inserted
replaced
| 107:49c6633f6fd2 | 108:e97534be35e3 |
|---|---|
| 1 //! Data and types dealing with PAM messages. | 1 //! Data and types dealing with PAM messages. |
| 2 | 2 |
| 3 #[cfg(feature = "linux-pam-extensions")] | 3 #[cfg(feature = "linux-pam-ext")] |
| 4 use crate::conv::{BinaryQAndA, RadioQAndA}; | 4 use crate::conv::{BinaryQAndA, RadioQAndA}; |
| 5 use crate::conv::{ErrorMsg, InfoMsg, MaskedQAndA, Message, QAndA}; | 5 use crate::conv::{ErrorMsg, InfoMsg, MaskedQAndA, Message, QAndA}; |
| 6 use crate::libpam::conversation::OwnedMessage; | 6 use crate::libpam::conversation::OwnedMessage; |
| 7 use crate::libpam::memory::{CBinaryData, CHeapBox, CHeapString, Immovable}; | 7 use crate::libpam::memory::{CBinaryData, CHeapBox, CHeapString, Immovable}; |
| 8 use crate::libpam::pam_ffi; | 8 use crate::libpam::pam_ffi; |
| 186 /// An error message. | 186 /// An error message. |
| 187 ErrorMsg = pam_ffi::PAM_ERROR_MSG, | 187 ErrorMsg = pam_ffi::PAM_ERROR_MSG, |
| 188 /// An informational message. | 188 /// An informational message. |
| 189 TextInfo = pam_ffi::PAM_TEXT_INFO, | 189 TextInfo = pam_ffi::PAM_TEXT_INFO, |
| 190 /// Yes/No/Maybe conditionals. A Linux-PAM extension. | 190 /// Yes/No/Maybe conditionals. A Linux-PAM extension. |
| 191 #[cfg(feature = "linux-pam-extensions")] | 191 #[cfg(feature = "linux-pam-ext")] |
| 192 RadioType = pam_ffi::PAM_RADIO_TYPE, | 192 RadioType = pam_ffi::PAM_RADIO_TYPE, |
| 193 /// For server–client non-human interaction. | 193 /// For server–client non-human interaction. |
| 194 /// | 194 /// |
| 195 /// NOT part of the X/Open PAM specification. | 195 /// NOT part of the X/Open PAM specification. |
| 196 /// A Linux-PAM extension. | 196 /// A Linux-PAM extension. |
| 197 #[cfg(feature = "linux-pam-extensions")] | 197 #[cfg(feature = "linux-pam-ext")] |
| 198 BinaryPrompt = pam_ffi::PAM_BINARY_PROMPT, | 198 BinaryPrompt = pam_ffi::PAM_BINARY_PROMPT, |
| 199 } | 199 } |
| 200 | 200 |
| 201 impl Question { | 201 impl Question { |
| 202 /// Gets this message's data pointer as a string. | 202 /// Gets this message's data pointer as a string. |
| 234 let (style, data): (_, CHeapBox<c_void>) = match *msg { | 234 let (style, data): (_, CHeapBox<c_void>) = match *msg { |
| 235 Message::MaskedPrompt(p) => alloc(Style::PromptEchoOff, p.question()), | 235 Message::MaskedPrompt(p) => alloc(Style::PromptEchoOff, p.question()), |
| 236 Message::Prompt(p) => alloc(Style::PromptEchoOn, p.question()), | 236 Message::Prompt(p) => alloc(Style::PromptEchoOn, p.question()), |
| 237 Message::Error(p) => alloc(Style::ErrorMsg, p.question()), | 237 Message::Error(p) => alloc(Style::ErrorMsg, p.question()), |
| 238 Message::Info(p) => alloc(Style::TextInfo, p.question()), | 238 Message::Info(p) => alloc(Style::TextInfo, p.question()), |
| 239 #[cfg(feature = "linux-pam-extensions")] | 239 #[cfg(feature = "linux-pam-ext")] |
| 240 Message::RadioPrompt(p) => alloc(Style::RadioType, p.question()), | 240 Message::RadioPrompt(p) => alloc(Style::RadioType, p.question()), |
| 241 #[cfg(feature = "linux-pam-extensions")] | 241 #[cfg(feature = "linux-pam-ext")] |
| 242 Message::BinaryPrompt(p) => Ok((Style::BinaryPrompt, unsafe { | 242 Message::BinaryPrompt(p) => Ok((Style::BinaryPrompt, unsafe { |
| 243 CHeapBox::cast(CBinaryData::alloc(p.question())?) | 243 CHeapBox::cast(CBinaryData::alloc(p.question())?) |
| 244 })), | 244 })), |
| 245 #[cfg(not(feature = "linux-pam-extensions"))] | 245 #[cfg(not(feature = "linux-pam-ext"))] |
| 246 Message::RadioPrompt(_) | Message::BinaryPrompt(_) => Err(ErrorCode::ConversationError), | 246 Message::RadioPrompt(_) | Message::BinaryPrompt(_) => Err(ErrorCode::ConversationError), |
| 247 }?; | 247 }?; |
| 248 Ok(Self { | 248 Ok(Self { |
| 249 style: style.into(), | 249 style: style.into(), |
| 250 data: Some(data), | 250 data: Some(data), |
| 259 unsafe { | 259 unsafe { |
| 260 // This is nice-to-have. We'll try to zero out the data | 260 // This is nice-to-have. We'll try to zero out the data |
| 261 // in the Question. If it's not a supported format, we skip it. | 261 // in the Question. If it's not a supported format, we skip it. |
| 262 if let Ok(style) = Style::try_from(self.style) { | 262 if let Ok(style) = Style::try_from(self.style) { |
| 263 let _ = match style { | 263 let _ = match style { |
| 264 #[cfg(feature = "linux-pam-extensions")] | 264 #[cfg(feature = "linux-pam-ext")] |
| 265 Style::BinaryPrompt => self | 265 Style::BinaryPrompt => self |
| 266 .data | 266 .data |
| 267 .as_ref() | 267 .as_ref() |
| 268 .map(|p| CBinaryData::zero_contents(CHeapBox::as_ptr(p).cast())), | 268 .map(|p| CBinaryData::zero_contents(CHeapBox::as_ptr(p).cast())), |
| 269 #[cfg(feature = "linux-pam-extensions")] | 269 #[cfg(feature = "linux-pam-ext")] |
| 270 Style::RadioType => self | 270 Style::RadioType => self |
| 271 .data | 271 .data |
| 272 .as_ref() | 272 .as_ref() |
| 273 .map(|p| CHeapString::zero(CHeapBox::as_ptr(p).cast())), | 273 .map(|p| CHeapString::zero(CHeapBox::as_ptr(p).cast())), |
| 274 Style::TextInfo | 274 Style::TextInfo |
| 299 Self::MaskedPrompt(MaskedQAndA::new(question.string_data()?)) | 299 Self::MaskedPrompt(MaskedQAndA::new(question.string_data()?)) |
| 300 } | 300 } |
| 301 Style::PromptEchoOn => Self::Prompt(QAndA::new(question.string_data()?)), | 301 Style::PromptEchoOn => Self::Prompt(QAndA::new(question.string_data()?)), |
| 302 Style::ErrorMsg => Self::Error(ErrorMsg::new(question.string_data()?)), | 302 Style::ErrorMsg => Self::Error(ErrorMsg::new(question.string_data()?)), |
| 303 Style::TextInfo => Self::Info(InfoMsg::new(question.string_data()?)), | 303 Style::TextInfo => Self::Info(InfoMsg::new(question.string_data()?)), |
| 304 #[cfg(feature = "linux-pam-extensions")] | 304 #[cfg(feature = "linux-pam-ext")] |
| 305 Style::RadioType => Self::RadioPrompt(RadioQAndA::new(question.string_data()?)), | 305 Style::RadioType => Self::RadioPrompt(RadioQAndA::new(question.string_data()?)), |
| 306 #[cfg(feature = "linux-pam-extensions")] | 306 #[cfg(feature = "linux-pam-ext")] |
| 307 Style::BinaryPrompt => Self::BinaryPrompt(BinaryQAndA::new(question.binary_data())), | 307 Style::BinaryPrompt => Self::BinaryPrompt(BinaryQAndA::new(question.binary_data())), |
| 308 } | 308 } |
| 309 }; | 309 }; |
| 310 Ok(prompt) | 310 Ok(prompt) |
| 311 } | 311 } |
| 351 assert_matches!(hey => OwnedMessage::Info, "hey"); | 351 assert_matches!(hey => OwnedMessage::Info, "hey"); |
| 352 assert_matches!(gasp => OwnedMessage::Error, "gasp"); | 352 assert_matches!(gasp => OwnedMessage::Error, "gasp"); |
| 353 } | 353 } |
| 354 | 354 |
| 355 #[test] | 355 #[test] |
| 356 #[cfg(not(feature = "linux-pam-extensions"))] | 356 #[cfg(not(feature = "linux-pam-ext"))] |
| 357 fn no_linux_extensions() { | 357 fn no_linux_extensions() { |
| 358 use crate::conv::{BinaryQAndA, RadioQAndA}; | 358 use crate::conv::{BinaryQAndA, RadioQAndA}; |
| 359 <$typ>::new(&[ | 359 <$typ>::new(&[ |
| 360 BinaryQAndA::new((&[5, 4, 3, 2, 1], 66)).message(), | 360 BinaryQAndA::new((&[5, 4, 3, 2, 1], 66)).message(), |
| 361 RadioQAndA::new("you must choose").message(), | 361 RadioQAndA::new("you must choose").message(), |
| 362 ]).unwrap_err(); | 362 ]).unwrap_err(); |
| 363 } | 363 } |
| 364 | 364 |
| 365 #[test] | 365 #[test] |
| 366 #[cfg(feature = "linux-pam-extensions")] | 366 #[cfg(feature = "linux-pam-ext")] |
| 367 fn linux_extensions() { | 367 fn linux_extensions() { |
| 368 let interrogation = Box::pin(<$typ>::new(&[ | 368 let interrogation = Box::pin(<$typ>::new(&[ |
| 369 BinaryQAndA::new((&[5, 4, 3, 2, 1], 66)).message(), | 369 BinaryQAndA::new((&[5, 4, 3, 2, 1], 66)).message(), |
| 370 RadioQAndA::new("you must choose").message(), | 370 RadioQAndA::new("you must choose").message(), |
| 371 ]).unwrap()); | 371 ]).unwrap()); |
