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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use std::io::{self, Write, BufRead};
use std::ffi::{CStr, CString};
use crate::error::ReturnCode;
use super::ConversationHandler;
fn trim_newline(s: &mut String) {
if s.ends_with('\n') {
s.pop();
if s.ends_with('\r') {
s.pop();
}
}
}
#[derive(Debug, Clone)]
pub struct Conversation {
info_prefix: String,
error_prefix: String,
}
impl Conversation {
#[must_use]
pub fn new() -> Self {
Self {
info_prefix: "[PAM INFO] ".to_string(),
error_prefix: "[PAM ERROR] ".to_string(),
}
}
#[inline]
#[must_use]
pub fn info_prefix(&self) -> &str {
&self.info_prefix
}
pub fn set_info_prefix(&mut self, prefix: impl Into<String>) {
self.info_prefix = prefix.into();
}
#[inline]
#[must_use]
pub fn error_prefix(&self) -> &str {
&self.error_prefix
}
pub fn set_error_prefix(&mut self, prefix: impl Into<String>) {
self.error_prefix = prefix.into();
}
}
impl Default for Conversation {
fn default() -> Self {
Self::new()
}
}
impl ConversationHandler for Conversation {
fn prompt_echo_on(&mut self, msg: &CStr) -> Result<CString, ReturnCode> {
let mut line = String::new();
if io::stderr().lock().write_all(msg.to_bytes()).is_err() {
return Err(ReturnCode::CONV_ERR);
}
match io::stdin().lock().read_line(&mut line) {
Err(_) | Ok(0) => Err(ReturnCode::CONV_ERR),
Ok(_) => {
trim_newline(&mut line);
CString::new(line).map_err(|_| ReturnCode::CONV_ERR)
}
}
}
fn prompt_echo_off(&mut self, msg: &CStr) -> Result<CString, ReturnCode> {
let prompt = msg.to_string_lossy();
match rpassword::read_password_from_tty(Some(&prompt)) {
Err(_) => Err(ReturnCode::CONV_ERR),
Ok(password) => CString::new(password).map_err(|_| ReturnCode::CONV_ERR)
}
}
fn text_info(&mut self, msg: &CStr) {
eprintln!("{}{}", &self.info_prefix, msg.to_string_lossy());
}
fn error_msg(&mut self, msg: &CStr) {
eprintln!("{}{}", &self.error_prefix, msg.to_string_lossy());
}
}