pam_client/
conversation.rs

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