1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
//! Conversation trait definition module
/***********************************************************************
* (c) 2021 Christoph Grenz <christophg+gitorious @ grenz-bonn.de> *
* *
* This Source Code Form is subject to the terms of the Mozilla Public *
* License, v. 2.0. If a copy of the MPL was not distributed with this *
* file, You can obtain one at http://mozilla.org/MPL/2.0/. *
***********************************************************************/
#![forbid(unsafe_code)]
use crate::error::ErrorCode;
use std::ffi::{CStr, CString};
use std::result::Result;
/// Trait for PAM conversation functions
///
/// Implement this for custom behaviour when a PAM module asks for usernames,
/// passwords, etc. or wants to show a message to the user
#[rustversion::attr(since(1.48), doc(alias = "pam_conv"))]
pub trait ConversationHandler {
/// Called by [`Context`][`crate::Context`] directly after taking ownership
/// of the handler.
///
/// May be called multiple times if
/// [`Context::replace_conversation()`][`crate::Context::replace_conversation`]
/// is used. In this case it is called each time a context takes ownership
/// and passed the current target username of that context (if any) as the
/// argument.
///
/// The default implementation does nothing.
fn init(&mut self, _default_user: Option<impl AsRef<str>>) {}
/// Obtains a string whilst echoing text (e.g. username)
///
/// # Errors
/// You should return one of the following error codes on failure.
/// - [`ErrorCode::CONV_ERR`]: Conversation failure.
/// - [`ErrorCode::BUF_ERR`]: Memory allocation error.
/// - [`ErrorCode::CONV_AGAIN`]: no result yet, the PAM library should
/// pass [`ErrorCode::INCOMPLETE`] to the application and let it
/// try again later.
fn prompt_echo_on(&mut self, prompt: &CStr) -> Result<CString, ErrorCode>;
/// Obtains a string without echoing any text (e.g. password)
///
/// # Errors
/// You should return one of the following error codes on failure.
/// - [`ErrorCode::CONV_ERR`]: Conversation failure.
/// - [`ErrorCode::BUF_ERR`]: Memory allocation error.
/// - [`ErrorCode::CONV_AGAIN`]: no result yet, the PAM library should
/// pass [`ErrorCode::INCOMPLETE`] to the application and let it
/// try again later.
fn prompt_echo_off(&mut self, prompt: &CStr) -> Result<CString, ErrorCode>;
/// Displays some text.
fn text_info(&mut self, msg: &CStr);
/// Displays an error message.
fn error_msg(&mut self, msg: &CStr);
/// Obtains a yes/no answer (Linux specific).
///
/// The default implementation calls `prompt_echo_on` and maps any answer
/// starting with 'y' or 'j' to "yes" and everything else to "no".
///
/// # Errors
/// You should return one of the following error codes on failure.
/// - [`ErrorCode::CONV_ERR`]: Conversation failure.
/// - [`ErrorCode::BUF_ERR`]: Memory allocation error.
/// - [`ErrorCode::CONV_AGAIN`]: no result yet, the PAM library should
/// pass [`ErrorCode::INCOMPLETE`] to the application and let it
/// try again later.
fn radio_prompt(&mut self, prompt: &CStr) -> Result<bool, ErrorCode> {
let prompt = [prompt.to_bytes(), b" [y/N]\0"].concat();
self.prompt_echo_on(CStr::from_bytes_with_nul(&prompt).unwrap())
.map(|s| matches!(s.as_bytes_with_nul()[0], b'Y' | b'y' | b'j' | b'J'))
}
/// Exchanges binary data (Linux specific, experimental).
///
/// The default implementation returns a conversation error.
///
/// # Errors
/// You should return one of the following error codes on failure.
/// - [`ErrorCode::CONV_ERR`]: Conversation failure.
/// - [`ErrorCode::BUF_ERR`]: Memory allocation error.
/// - [`ErrorCode::CONV_AGAIN`]: no result yet, the PAM library should
/// pass [`ErrorCode::INCOMPLETE`] to the application and let it
/// try again later.
fn binary_prompt(&mut self, _type: u8, _data: &[u8]) -> Result<(u8, Vec<u8>), ErrorCode> {
Err(ErrorCode::CONV_ERR)
}
}